Migrate to Pi Coding Agent SDK for multi-provider LLM support

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>
This commit is contained in:
2026-05-15 00:17:26 -04:00
parent 506d092b2b
commit 0624026af3
30 changed files with 4326 additions and 354 deletions

View File

@@ -0,0 +1,208 @@
/**
* 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];
}