Skip to content

Commit eb9820d

Browse files
authored
feat: Generate Citations (#96)
1 parent 5b36033 commit eb9820d

11 files changed

Lines changed: 162 additions & 14 deletions

File tree

.github/workflows/build-backend-prd.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
XTRAMCP_OPENREVIEW_PASSWORD: ${{ secrets.XTRAMCP_OPENREVIEW_PASSWORD_PRD }}
7070
XTRAMCP_CROSSREF_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_CROSSREF_EMAIL_ADDRESS_PRD }}
7171
XTRAMCP_DOI_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_DOI_EMAIL_ADDRESS_PRD }}
72+
XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_PRD }}
7273
XTRAMCP_ARXIV_METADATA_DB_URL: ${{ secrets.XTRAMCP_ARXIV_METADATA_DB_URL_PRD }}
7374
XTRAMCP_MONGO_URI: ${{ secrets.XTRAMCP_MONGO_URI_PRD }}
7475
MONGO_URI: ${{ secrets.MONGO_URI_PRD }}

.github/workflows/build-backend-stg.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ jobs:
6969
XTRAMCP_OPENREVIEW_PASSWORD: ${{ secrets.XTRAMCP_OPENREVIEW_PASSWORD_STG }}
7070
XTRAMCP_CROSSREF_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_CROSSREF_EMAIL_ADDRESS_STG }}
7171
XTRAMCP_DOI_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_DOI_EMAIL_ADDRESS_STG }}
72+
XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_PRD }}
7273
XTRAMCP_ARXIV_METADATA_DB_URL: ${{ secrets.XTRAMCP_ARXIV_METADATA_DB_URL_STG }}
7374
XTRAMCP_MONGO_URI: ${{ secrets.XTRAMCP_MONGO_URI_STG }}
7475
MONGO_URI: ${{ secrets.MONGO_URI_STG }}

hack/prd.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREV
1818
XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD}
1919
XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address}
2020
XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address}
21+
XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url}
2122
XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url}
2223
XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri}
2324
PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest}
@@ -42,6 +43,7 @@ helm template $ROOT_DIR/helm-chart \
4243
--set-string xtramcp_openreview_password=$XTRAMCP_OPENREVIEW_PASSWORD \
4344
--set-string xtramcp_crossref_email_address=$XTRAMCP_CROSSREF_EMAIL_ADDRESS \
4445
--set-string xtramcp_doi_email_address=$XTRAMCP_DOI_EMAIL_ADDRESS \
46+
--set-string xtramcp_acl_metadata_db_url=$XTRAMCP_ACL_METADATA_DB_URL \
4547
--set-string xtramcp_arxiv_metadata_db_url=$XTRAMCP_ARXIV_METADATA_DB_URL \
4648
--set-string xtramcp_mongo_uri=$XTRAMCP_MONGO_URI \
4749
--set-string paperdebugger.image=$PAPERDEBUGGER_IMAGE \

hack/stg.sh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREV
1818
XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD}
1919
XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address}
2020
XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address}
21+
XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url}
2122
XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url}
2223
XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri}
2324
PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest}
@@ -42,6 +43,7 @@ helm template $ROOT_DIR/helm-chart \
4243
--set-string xtramcp_openreview_password=$XTRAMCP_OPENREVIEW_PASSWORD \
4344
--set-string xtramcp_crossref_email_address=$XTRAMCP_CROSSREF_EMAIL_ADDRESS \
4445
--set-string xtramcp_doi_email_address=$XTRAMCP_DOI_EMAIL_ADDRESS \
46+
--set-string xtramcp_acl_metadata_db_url=$XTRAMCP_ACL_METADATA_DB_URL \
4547
--set-string xtramcp_arxiv_metadata_db_url=$XTRAMCP_ARXIV_METADATA_DB_URL \
4648
--set-string xtramcp_mongo_uri=$XTRAMCP_MONGO_URI \
4749
--set-string paperdebugger.image=$PAPERDEBUGGER_IMAGE \

helm-chart/templates/paperdebugger-xtramcp-server.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,3 +60,4 @@ data:
6060
MONGODB_CONNECTION_STRING: "{{ .Values.xtramcp_mongo_uri }}"
6161
MONGODB_DATABASE: "paperdebugger"
6262
ARXIV_METADATA_DB_URL: "{{ .Values.xtramcp_arxiv_metadata_db_url }}"
63+
ACL_METADATA_DB_URL: "{{ .Values.xtramcp_acl_metadata_db_url }}"

helm-chart/values.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ paperdebuggerMcpServer:
1414
image: ghcr.io/paperdebugger/paperdebugger-mcp-server:main-14409c5
1515

1616
paperdebuggerXtraMcpServer:
17-
image: ghcr.io/paperdebugger/xtragpt-mcp-server:sha-2f1404c
17+
image: ghcr.io/paperdebugger/xtragpt-mcp-server:sha-16c3861
1818

1919
mongo:
2020
in_cluster: true

internal/api/user/list_prompts.go

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,44 +13,60 @@ import (
1313
)
1414

1515
var defaultPrompts = []*userv1.Prompt{
16+
{
17+
Id: "1",
18+
CreatedAt: timestamppb.New(time.Time{}),
19+
UpdatedAt: timestamppb.New(time.Time{}),
20+
Title: "Tool List",
21+
Content: "List available MCP tools with a brief description for each tool.",
22+
IsUserPrompt: false,
23+
},
1624
{
1725
Id: "2",
1826
CreatedAt: timestamppb.New(time.Time{}),
1927
UpdatedAt: timestamppb.New(time.Time{}),
20-
Title: "Search Relevant Papers (Powered by XtraMCP)",
21-
Content: "First, understand my paper and extract the key ideas into an optimized query to find papers that are relevant to my work. Then search for relevant papers to read.\n\nOptional Args:\ntop_k: 10\nStart Date: None (e.g. 2018-12-31)\nEnd Date: None (e.g. 2025-12-31)",
28+
Title: "Search Relevant Papers (XtraMCP's Researcher)",
29+
Content: "You are a research assistant helping to retrieve related academic papers.\n\nStep 1 — Query synthesis:\nCarefully read the provided paper content.\nExtract the core technical ideas, methods, problem setting, and application domain.\nProduce ONE concise, high-signal search query optimized for academic paper retrieval.\n- Prefer technical keywords and established terminology\n- Include model names, task names, or methodological frameworks when applicable\n- Avoid unnecessary elaboration, prose, or citations\n\nStep 2 — Tool invocation:\nCall `search_relevant_papers` using the synthesized query.\n\nTool parameters:\n- query: <your synthesized query>\n- top_k: 10\n- start_date: 2018-12-31\n- end_date: 2025-12-31",
2230
IsUserPrompt: false,
2331
},
2432
{
2533
Id: "3",
2634
CreatedAt: timestamppb.New(time.Time{}),
2735
UpdatedAt: timestamppb.New(time.Time{}),
28-
Title: "Paper Review (Powered by XtraMCP)",
29-
Content: "Call review_paper and evaluate my paper.\n\nOptional Args:\nTarget Venue: None (e.g. ICML, NeurIPS, CVPR)\nSeverity Level (blocker | major | minor | nit): Major\nSpecific Sections (default: entire paper): None (e.g. Abstract, Results, <section name in paper>)",
36+
Title: "Paper Review (XtraMCP's Reviewer)",
37+
Content: "Call `review_paper` and evaluate my paper.\n\nTool parameters:\nTarget Venue: None (e.g. ICML, NeurIPS, CVPR)\nSeverity Level (blocker | major | minor | nit): Major\nSpecific Sections (default: entire paper): None (e.g. Abstract, Results, <section name in paper>)",
3038
IsUserPrompt: false,
3139
},
3240
{
3341
Id: "4",
3442
CreatedAt: timestamppb.New(time.Time{}),
3543
UpdatedAt: timestamppb.New(time.Time{}),
36-
Title: "Verify Citations (Powered by XtraMCP)",
37-
Content: "Call verify_citations to check the validity of all citations in my paper and identify any potential issues such as incorrect formatting, missing information, or inaccurate references.",
44+
Title: "Verify Citations (XtraMCP's Reviewer)",
45+
Content: "Call `verify_citations` to check the validity of all citations in my paper and identify any potential issues such as incorrect formatting, missing information, or inaccurate references.",
3846
IsUserPrompt: false,
3947
},
4048
{
4149
Id: "5",
4250
CreatedAt: timestamppb.New(time.Time{}),
4351
UpdatedAt: timestamppb.New(time.Time{}),
44-
Title: "Deep Research (Powered by XtraMCP)",
45-
Content: "First, understand my paper and extract the key ideas into an optimized query. Do deep research and compare my paper against others.",
52+
Title: "Generate Citations (XtraMCP's Reviewer)",
53+
Content: "Call `generate_citations` to create properly formatted citations for:\n\nTool parameters:\n- links: [\n\t# paste URLs, arXiv IDs, DOIs, or titles\n\t# eg.: XtraGPT: Context-Aware and Controllable Academic Paper Revision\n\t...\n]",
4654
IsUserPrompt: false,
4755
},
4856
{
4957
Id: "6",
5058
CreatedAt: timestamppb.New(time.Time{}),
5159
UpdatedAt: timestamppb.New(time.Time{}),
52-
Title: "Online Research (Powered by XtraMCP)",
53-
Content: "Understand my paper and run online search to find the latest papers related to my work.",
60+
Title: "Deep Research (XtraMCP's Researcher)",
61+
Content: "You are a research assistant helping to retrieve related academic papers to prepare for Deep Research.\n\nStep 1 — Query synthesis:\nCarefully read the provided paper content.\nExtract the core technical ideas, methods, problem setting, and application domain.\nProduce ONE concise, high-signal search query optimized for academic paper retrieval.\n- Prefer technical keywords and established terminology\n- Include model names, task names, or methodological frameworks when applicable\n- Avoid unnecessary elaboration, prose, or citations\n\nStep 2 — Tool invocation:\nCall `deep_research` using the synthesized query.\n\nTool parameters:\n- query: <your synthesized query>",
62+
IsUserPrompt: false,
63+
},
64+
{
65+
Id: "7",
66+
CreatedAt: timestamppb.New(time.Time{}),
67+
UpdatedAt: timestamppb.New(time.Time{}),
68+
Title: "Online Research (XtraMCP's Researcher)",
69+
Content: "You are a research assistant assisting with a recency-focused academic literature search.\n\nStep 1 — Keyword extraction:\nCarefully read the paper and extract a set of high-recall search keywords, including:\n- core task names and problem statements\n- methodological approaches and system types\n- application domains\n- commonly used synonyms and alternative phrasings\n- well-known model or framework names if relevant and widely used\n\nPrefer established terminology used in paper titles and abstracts.\nAvoid internal project names or marketing labels.\n\nStep 2 — Query construction:\nConstruct a keyword-based search query optimized for lexical search:\n- Use keyword phrases rather than full sentences\n- Combine terms using natural keyword adjacency (not prose)\n- Bias toward recall over precision\n\nStep 3 — Online retrieval:\nCall `online_search_papers` using the constructed query to find recent papers outside the internal database.",
5470
IsUserPrompt: false,
5571
},
5672
}

webapp/_webapp/src/components/message-entry-container/tools/tools.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { ReviewPaperCard } from "./xtramcp/review-paper";
88
import { SearchRelevantPapersCard } from "./xtramcp/search-relevant-papers";
99
import { OnlineSearchPapersCard } from "./xtramcp/online-search-papers";
1010
import { VerifyCitationsCard } from "./xtramcp/verify-citations";
11+
import { GenerateCitationsCard } from "./xtramcp/generate-citations";
1112
import { isXtraMcpTool } from "./xtramcp/utils/common";
1213
import { GeneralToolCard } from "./general";
1314

@@ -67,6 +68,10 @@ export default function Tools({ messageId, functionName, message, error, prepari
6768
return (
6869
<VerifyCitationsCard functionName={functionName} message={message} preparing={preparing} animated={animated} />
6970
);
71+
} else if (functionName === "generate_citations") {
72+
return (
73+
<GenerateCitationsCard functionName={functionName} message={message} preparing={preparing} animated={animated} />
74+
);
7075
}
7176

7277
// Generic XtraMCP tool (not specialized)
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
import { cn } from "@heroui/react";
2+
import { LoadingIndicator } from "../../../loading-indicator";
3+
import MarkdownComponent from "../../../markdown";
4+
import { useState } from "react";
5+
import { XtraMcpToolCardProps, parseXtraMcpToolResult, CollapseArrowButton, CollapseWrapper } from "./utils/common";
6+
7+
export const GenerateCitationsCard = ({ functionName, message, preparing, animated }: XtraMcpToolCardProps) => {
8+
const [isMetadataCollapsed, setIsMetadataCollapsed] = useState(false);
9+
10+
// Loading state (tool executing)
11+
if (preparing) {
12+
return (
13+
<div className={cn("tool-card", { animated: animated })}>
14+
<div className="flex items-center justify-between">
15+
<h3 className="tool-card-title">Generating your citations..</h3>
16+
</div>
17+
<LoadingIndicator text="Processing ..." estimatedSeconds={35} />
18+
</div>
19+
);
20+
}
21+
22+
// Parse XtraMCP ToolResult format
23+
const result = parseXtraMcpToolResult(message);
24+
25+
// No result or not ToolResult format - minimal display
26+
if (!result) {
27+
return (
28+
<div className={cn("tool-card noselect narrow", { animated: animated })}>
29+
<div className="flex items-center justify-between">
30+
<h3 className="tool-card-title">{functionName}</h3>
31+
</div>
32+
</div>
33+
);
34+
}
35+
36+
// Error state
37+
if (result.error || result.success === false) {
38+
return (
39+
<div className={cn("tool-card noselect narrow", { animated: animated })}>
40+
{/* Header with Error label and arrow button */}
41+
<div
42+
className="flex items-center justify-between cursor-pointer"
43+
onClick={() => setIsMetadataCollapsed(!isMetadataCollapsed)}
44+
>
45+
<h3 className="tool-card-title">{functionName}</h3>
46+
<div className="flex items-center gap-2">
47+
<span className="text-red-500 text-sm font-medium">Error</span>
48+
<CollapseArrowButton
49+
isCollapsed={isMetadataCollapsed}
50+
ariaLabel={isMetadataCollapsed ? "Expand error" : "Collapse error"}
51+
/>
52+
</div>
53+
</div>
54+
55+
{/* Error message dropdown */}
56+
<CollapseWrapper isCollapsed={isMetadataCollapsed}>
57+
<div className="text-xs text-red-600 mt-2 pt-2 border-t border-red-200">
58+
{result.error || "Tool execution failed"}
59+
</div>
60+
</CollapseWrapper>
61+
</div>
62+
);
63+
}
64+
65+
// Success state - verbatim mode (guaranteed for this tool on success)
66+
// Display compact card + content below
67+
if (typeof result.content === "string") {
68+
return (
69+
<>
70+
{/* COMPACT TOOL CARD - Just title + metadata dropdown */}
71+
<div className={cn("tool-card noselect narrow", { animated: animated })}>
72+
{/* Header with arrow button */}
73+
<div
74+
className="flex items-center justify-between cursor-pointer"
75+
onClick={() => setIsMetadataCollapsed(!isMetadataCollapsed)}
76+
>
77+
<h3 className="tool-card-title">{functionName}</h3>
78+
<CollapseArrowButton
79+
isCollapsed={isMetadataCollapsed}
80+
ariaLabel={isMetadataCollapsed ? "Expand metadata" : "Collapse metadata"}
81+
/>
82+
</div>
83+
84+
{/* Metadata dropdown - INSIDE the tool card */}
85+
{result.metadata && Object.keys(result.metadata).length > 0 && (
86+
<CollapseWrapper isCollapsed={isMetadataCollapsed}>
87+
<div className="text-xs text-gray-600 mt-2 pt-2 border-t border-gray-200">
88+
{/* Custom metadata rendering */}
89+
<div className="mb-2 italic">⚠️ [Experimental Feature] Some BibTeX entries may not be able to be generated.<br />Report if you encounter an unknown issue.</div>
90+
{result.metadata.total_links !== undefined && (
91+
<div>
92+
<span className="font-medium">Total Links/IDs/Info:</span> {result.metadata.total_links}
93+
</div>
94+
)}
95+
</div>
96+
</CollapseWrapper>
97+
)}
98+
</div>
99+
100+
{/* CONTENT - OUTSIDE/BELOW the tool card, always visible */}
101+
<div className="canselect text-sm mt-2">
102+
<MarkdownComponent animated={animated}>{result.content}</MarkdownComponent>
103+
</div>
104+
</>
105+
);
106+
}
107+
108+
// Fallback - unknown format
109+
return (
110+
<div className={cn("tool-card noselect narrow", { animated: animated })}>
111+
<div className="flex items-center justify-between">
112+
<h3 className="tool-card-title">{functionName}</h3>
113+
</div>
114+
</div>
115+
);
116+
};

webapp/_webapp/src/components/message-entry-container/tools/xtramcp/search-relevant-papers.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,10 @@ export const SearchRelevantPapersCard = ({ functionName, message, preparing, ani
9393
{result.metadata && Object.keys(result.metadata).length > 0 && (
9494
<CollapseWrapper isCollapsed={isMetadataCollapsed}>
9595
<div className="text-xs text-gray-600 mt-2 pt-2 border-t border-gray-200">
96-
{/* Custom metadata rendering */}
96+
{/* Custom metadata rendering; NOTE: hard-coded the CAA date */}
97+
<div className="mb-2">
98+
<span className="font-medium">⚠️ Papers searched from a pool updated as of 31st Dec 2025.</span>
99+
</div>
97100
{result.metadata.query && (
98101
<div className="mb-2">
99102
<span className="font-medium">Query Used:</span> "{result.metadata.query}"

0 commit comments

Comments
 (0)