Replace the custom Pi API fetch client with the @earendil-works/pi-coding-agent SDK, enabling support for multiple LLM providers (Anthropic, OpenAI, DeepSeek, Google Gemini, xAI/ZAI) while maintaining backward compatibility. Key changes: - Add piSdk.ts with SDK session management and provider auto-detection - Refactor client.ts to delegate to SDK adapter, keeping public API surface - Update documentation to reflect multi-provider environment variables - Add RPC contracts for LLM model selection and provider configuration - Update agent runner to support provider-specific tools and parameters Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
209 lines
6.3 KiB
TypeScript
209 lines
6.3 KiB
TypeScript
/**
|
|
* Custom tools: Company, filings, and earnings data access
|
|
*/
|
|
|
|
import { Type } from "typebox";
|
|
import { defineTool } from "@earendil-works/pi-coding-agent";
|
|
import type { Db } from "../db/database.js";
|
|
import {
|
|
getCompany,
|
|
getCompanyByTicker,
|
|
resolveCompany,
|
|
listFilings,
|
|
getEarningsSchedule,
|
|
listCatalysts,
|
|
listRisks,
|
|
listAlerts,
|
|
} from "../db/queries.js";
|
|
|
|
export function createCompanyTools(db: Db) {
|
|
const getCompanyInfo = defineTool({
|
|
name: "get_company_info",
|
|
label: "Get Company Info",
|
|
description:
|
|
"Get company details including name, ticker, sector, price, thesis, and metadata. Accepts either a company ID or ticker symbol.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.String({
|
|
description: "Company ID or ticker symbol (e.g. 'AAPL' or 'company-123')",
|
|
}),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = resolveCompany(db, params.companyIdOrTicker);
|
|
if (!company) {
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text" as const,
|
|
text: `Company "${params.companyIdOrTicker}" not found.`,
|
|
},
|
|
],
|
|
isError: true,
|
|
details: {},
|
|
};
|
|
}
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text" as const,
|
|
text: JSON.stringify(company, null, 2),
|
|
},
|
|
],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
const getFilingsTool = defineTool({
|
|
name: "get_filings",
|
|
label: "Get SEC Filings",
|
|
description:
|
|
"List SEC filings for a company (10-K, 10-Q, 8-K, DEF 14A, etc.). Returns form type, title, filed date, and key changes.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.String({
|
|
description: "Company ID or ticker symbol",
|
|
}),
|
|
limit: Type.Optional(
|
|
Type.Number({ description: "Max filings to return (default 20)", default: 20 }),
|
|
),
|
|
since: Type.Optional(
|
|
Type.String({ description: "Only filings after this date (YYYY-MM-DD)" }),
|
|
),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = resolveCompany(db, params.companyIdOrTicker);
|
|
if (!company) {
|
|
return {
|
|
content: [{ type: "text" as const, text: `Company "${params.companyIdOrTicker}" not found.` }],
|
|
isError: true,
|
|
details: {},
|
|
};
|
|
}
|
|
const filings = listFilings(db, company.id, params.since);
|
|
const limited = filings.slice(0, params.limit ?? 20);
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text" as const,
|
|
text: JSON.stringify(
|
|
{ companyId: company.id, ticker: company.ticker, count: limited.length, filings: limited },
|
|
null,
|
|
2,
|
|
),
|
|
},
|
|
],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
const getEarningsTool = defineTool({
|
|
name: "get_earnings",
|
|
label: "Get Earnings Schedule",
|
|
description:
|
|
"Get upcoming and historical earnings dates, actual vs expected revenue and EPS.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.String({
|
|
description: "Company ID or ticker symbol",
|
|
}),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = resolveCompany(db, params.companyIdOrTicker);
|
|
if (!company) {
|
|
return {
|
|
content: [{ type: "text" as const, text: `Company "${params.companyIdOrTicker}" not found.` }],
|
|
isError: true,
|
|
details: {},
|
|
};
|
|
}
|
|
const schedule = getEarningsSchedule(db, company.id);
|
|
return {
|
|
content: [
|
|
{
|
|
type: "text" as const,
|
|
text: JSON.stringify(schedule, null, 2),
|
|
},
|
|
],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
const getCatalystsTool = defineTool({
|
|
name: "get_catalysts",
|
|
label: "Get Catalysts",
|
|
description: "List catalysts (upcoming events) for a company with impact assessment and thesis relevance.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.String({
|
|
description: "Company ID or ticker symbol",
|
|
}),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = resolveCompany(db, params.companyIdOrTicker);
|
|
if (!company) {
|
|
return {
|
|
content: [{ type: "text" as const, text: `Company "${params.companyIdOrTicker}" not found.` }],
|
|
isError: true,
|
|
details: {},
|
|
};
|
|
}
|
|
const catalysts = listCatalysts(db, company.id);
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(catalysts, null, 2) }],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
const getRisksTool = defineTool({
|
|
name: "get_risks",
|
|
label: "Get Risks",
|
|
description: "List identified risks for a company, categorized by type with severity and likelihood.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.String({
|
|
description: "Company ID or ticker symbol",
|
|
}),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = resolveCompany(db, params.companyIdOrTicker);
|
|
if (!company) {
|
|
return {
|
|
content: [{ type: "text" as const, text: `Company "${params.companyIdOrTicker}" not found.` }],
|
|
isError: true,
|
|
details: {},
|
|
};
|
|
}
|
|
const risks = listRisks(db, company.id);
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(risks, null, 2) }],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
const getAlertsTool = defineTool({
|
|
name: "get_alerts",
|
|
label: "Get Alerts",
|
|
description: "List recent alerts (filing, price move, earnings surprise, peer event) for a company.",
|
|
parameters: Type.Object({
|
|
companyIdOrTicker: Type.Optional(
|
|
Type.String({ description: "Company ID or ticker symbol (omit for all companies)" }),
|
|
),
|
|
since: Type.Optional(
|
|
Type.String({ description: "Only alerts after this timestamp" }),
|
|
),
|
|
}),
|
|
execute: async (_, params) => {
|
|
const company = params.companyIdOrTicker
|
|
? resolveCompany(db, params.companyIdOrTicker)
|
|
: undefined;
|
|
const alerts = listAlerts(db, company?.id, params.since);
|
|
return {
|
|
content: [{ type: "text" as const, text: JSON.stringify(alerts, null, 2) }],
|
|
details: {},
|
|
};
|
|
},
|
|
});
|
|
|
|
return [getCompanyInfo, getFilingsTool, getEarningsTool, getCatalystsTool, getRisksTool, getAlertsTool];
|
|
}
|