Register alphaXiv research tools as native Pi tools
Replace the alpha-research CLI skill with direct programmatic Pi tool registrations via @companion-ai/alpha-hub/lib. Tools connect to alphaXiv's MCP server through the library and reuse the connection across calls instead of spawning a new CLI process each time. Registers: alpha_search, alpha_get_paper, alpha_ask_paper, alpha_annotate_paper, alpha_list_annotations, alpha_read_code. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
|
|
||||||
|
import { registerAlphaTools } from "./research-tools/alpha.js";
|
||||||
import { installFeynmanHeader } from "./research-tools/header.js";
|
import { installFeynmanHeader } from "./research-tools/header.js";
|
||||||
import { registerHelpCommand } from "./research-tools/help.js";
|
import { registerHelpCommand } from "./research-tools/help.js";
|
||||||
import { registerInitCommand, registerOutputsCommand } from "./research-tools/project.js";
|
import { registerInitCommand, registerOutputsCommand } from "./research-tools/project.js";
|
||||||
@@ -15,6 +16,7 @@ export default function researchTools(pi: ExtensionAPI): void {
|
|||||||
await installFeynmanHeader(pi, ctx, cache);
|
await installFeynmanHeader(pi, ctx, cache);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerAlphaTools(pi);
|
||||||
registerHelpCommand(pi);
|
registerHelpCommand(pi);
|
||||||
registerInitCommand(pi);
|
registerInitCommand(pi);
|
||||||
registerOutputsCommand(pi);
|
registerOutputsCommand(pi);
|
||||||
|
|||||||
107
extensions/research-tools/alpha.ts
Normal file
107
extensions/research-tools/alpha.ts
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
import {
|
||||||
|
askPaper,
|
||||||
|
annotatePaper,
|
||||||
|
clearPaperAnnotation,
|
||||||
|
getPaper,
|
||||||
|
listPaperAnnotations,
|
||||||
|
readPaperCode,
|
||||||
|
searchPapers,
|
||||||
|
} from "@companion-ai/alpha-hub/lib";
|
||||||
|
import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
|
||||||
|
import { Type } from "@sinclair/typebox";
|
||||||
|
|
||||||
|
function formatText(value: unknown): string {
|
||||||
|
if (typeof value === "string") return value;
|
||||||
|
return JSON.stringify(value, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function registerAlphaTools(pi: ExtensionAPI): void {
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_search",
|
||||||
|
label: "Alpha Search",
|
||||||
|
description:
|
||||||
|
"Search research papers through alphaXiv. Modes: semantic (default, use 2-3 sentence queries), keyword (exact terms), agentic (broad multi-turn retrieval), both, or all.",
|
||||||
|
parameters: Type.Object({
|
||||||
|
query: Type.String({ description: "Search query." }),
|
||||||
|
mode: Type.Optional(
|
||||||
|
Type.String({ description: "Search mode: semantic, keyword, both, agentic, or all." }),
|
||||||
|
),
|
||||||
|
}),
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
const result = await searchPapers(params.query, params.mode?.trim() || "semantic");
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_get_paper",
|
||||||
|
label: "Alpha Get Paper",
|
||||||
|
description: "Fetch a paper's AI-generated report (or raw full text) plus any local annotation.",
|
||||||
|
parameters: Type.Object({
|
||||||
|
paper: Type.String({ description: "arXiv ID, arXiv URL, or alphaXiv URL." }),
|
||||||
|
fullText: Type.Optional(Type.Boolean({ description: "Return raw full text instead of AI report." })),
|
||||||
|
}),
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
const result = await getPaper(params.paper, { fullText: params.fullText });
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_ask_paper",
|
||||||
|
label: "Alpha Ask Paper",
|
||||||
|
description: "Ask a targeted question about a paper. Uses AI to analyze the PDF and answer.",
|
||||||
|
parameters: Type.Object({
|
||||||
|
paper: Type.String({ description: "arXiv ID, arXiv URL, or alphaXiv URL." }),
|
||||||
|
question: Type.String({ description: "Question about the paper." }),
|
||||||
|
}),
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
const result = await askPaper(params.paper, params.question);
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_annotate_paper",
|
||||||
|
label: "Alpha Annotate Paper",
|
||||||
|
description: "Write or clear a persistent local annotation for a paper.",
|
||||||
|
parameters: Type.Object({
|
||||||
|
paper: Type.String({ description: "Paper ID (arXiv ID or URL)." }),
|
||||||
|
note: Type.Optional(Type.String({ description: "Annotation text. Omit when clear=true." })),
|
||||||
|
clear: Type.Optional(Type.Boolean({ description: "Clear the existing annotation." })),
|
||||||
|
}),
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
const result = params.clear
|
||||||
|
? await clearPaperAnnotation(params.paper)
|
||||||
|
: params.note
|
||||||
|
? await annotatePaper(params.paper, params.note)
|
||||||
|
: (() => { throw new Error("Provide either note or clear=true."); })();
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_list_annotations",
|
||||||
|
label: "Alpha List Annotations",
|
||||||
|
description: "List all persistent local paper annotations.",
|
||||||
|
parameters: Type.Object({}),
|
||||||
|
async execute() {
|
||||||
|
const result = await listPaperAnnotations();
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
pi.registerTool({
|
||||||
|
name: "alpha_read_code",
|
||||||
|
label: "Alpha Read Code",
|
||||||
|
description: "Read files from a paper's GitHub repository. Use '/' for repo overview.",
|
||||||
|
parameters: Type.Object({
|
||||||
|
githubUrl: Type.String({ description: "GitHub repository URL." }),
|
||||||
|
path: Type.Optional(Type.String({ description: "File or directory path. Default: '/'" })),
|
||||||
|
}),
|
||||||
|
async execute(_toolCallId, params) {
|
||||||
|
const result = await readPaperCode(params.githubUrl, params.path?.trim() || "/");
|
||||||
|
return { content: [{ type: "text", text: formatText(result) }], details: result };
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user