mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-26 20:45:37 +02:00
feat(core): add unified data tool with finance domain support
Introduces a `data` tool that provides structured access to the Financial Datasets API (financialdatasets.ai). Supports 18 finance actions covering stock prices, financial statements, key metrics, SEC filings, analyst estimates, insider trades, news, and crypto data. Designed as a stable interface — the backend can be swapped from direct API calls to a Multica Data Service without changing the tool schema. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,7 @@ const CORE_TOOL_SUMMARIES: Record<string, string> = {
|
||||
web_fetch: "Fetch and extract readable content from a URL",
|
||||
memory_search: "Search memory files by keyword",
|
||||
sessions_spawn: "Spawn a sub-agent session",
|
||||
data: "Query structured financial and market data",
|
||||
};
|
||||
|
||||
/** Preferred display order for tools */
|
||||
@@ -42,6 +43,7 @@ const TOOL_ORDER = [
|
||||
"web_fetch",
|
||||
"memory_search",
|
||||
"sessions_spawn",
|
||||
"data",
|
||||
];
|
||||
|
||||
// ─── Section builders ───────────────────────────────────────────────────────
|
||||
@@ -266,6 +268,17 @@ export function buildConditionalToolSections(
|
||||
);
|
||||
}
|
||||
|
||||
// Data tools
|
||||
if (toolSet.has("data")) {
|
||||
lines.push(
|
||||
"## Data Access",
|
||||
"You have access to structured financial and market data via the `data` tool.",
|
||||
'Use domain="finance" with specific actions to retrieve stock prices, financial statements, SEC filings, metrics, and more.',
|
||||
"Always specify dates in YYYY-MM-DD format. Use period='annual' or 'quarterly' or 'ttm' for financial statements.",
|
||||
"",
|
||||
);
|
||||
}
|
||||
|
||||
// Web tools
|
||||
if (toolSet.has("web_search") || toolSet.has("web_fetch")) {
|
||||
lines.push(
|
||||
|
||||
@@ -10,6 +10,7 @@ import { createSessionsSpawnTool } from "./tools/sessions-spawn.js";
|
||||
import { createSessionsListTool } from "./tools/sessions-list.js";
|
||||
import { createMemorySearchTool } from "./tools/memory-search.js";
|
||||
import { createCronTool } from "./tools/cron/index.js";
|
||||
import { createDataTool } from "./tools/data/index.js";
|
||||
import { filterTools } from "./tools/policy.js";
|
||||
import { isMulticaError, isRetryableError } from "@multica/utils";
|
||||
import type { ExecApprovalCallback } from "./tools/exec-approval-types.js";
|
||||
@@ -110,6 +111,7 @@ export function createAllTools(options: CreateToolsOptions | string): AgentTool<
|
||||
const webSearchTool = createWebSearchTool();
|
||||
|
||||
const cronTool = createCronTool();
|
||||
const dataTool = createDataTool();
|
||||
|
||||
const tools: AgentTool<any>[] = [
|
||||
...baseTools,
|
||||
@@ -119,6 +121,7 @@ export function createAllTools(options: CreateToolsOptions | string): AgentTool<
|
||||
webFetchTool as AgentTool<any>,
|
||||
webSearchTool as AgentTool<any>,
|
||||
cronTool as AgentTool<any>,
|
||||
dataTool as AgentTool<any>,
|
||||
];
|
||||
|
||||
// Add memory_search tool if profileDir is provided
|
||||
|
||||
118
packages/core/src/agent/tools/data/data-tool.ts
Normal file
118
packages/core/src/agent/tools/data/data-tool.ts
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* Unified data tool — structured access to domain-specific data sources.
|
||||
*
|
||||
* Currently supports the "finance" domain (Financial Datasets API).
|
||||
* Designed as a stable interface: the backend can be swapped from
|
||||
* direct API calls to a Multica Data Service without changing the tool schema.
|
||||
*/
|
||||
|
||||
import { Type } from "@sinclair/typebox";
|
||||
import type { AgentTool } from "@mariozechner/pi-agent-core";
|
||||
import { executeFinanceAction } from "./finance/actions.js";
|
||||
|
||||
// ─── Schema ─────────────────────────────────────────────────────────────────
|
||||
|
||||
const DataToolSchema = Type.Object({
|
||||
domain: Type.String({
|
||||
description: 'Data domain. Currently supported: "finance".',
|
||||
}),
|
||||
action: Type.String({
|
||||
description:
|
||||
"Action to perform within the domain.\n\n" +
|
||||
"FINANCE DOMAIN ACTIONS:\n" +
|
||||
"Prices:\n" +
|
||||
" get_price_snapshot — params: { ticker }\n" +
|
||||
" get_prices — params: { ticker, start_date, end_date, interval?, interval_multiplier? }\n" +
|
||||
" get_crypto_price_snapshot — params: { ticker } (e.g. BTC-USD)\n" +
|
||||
" get_crypto_prices — params: { ticker, start_date, end_date, interval?, interval_multiplier? }\n" +
|
||||
" get_available_crypto_tickers — params: {}\n" +
|
||||
"Financial Statements (period: annual|quarterly|ttm):\n" +
|
||||
" get_income_statements — params: { ticker, period, limit?, report_period_gt/gte/lt/lte? }\n" +
|
||||
" get_balance_sheets — same params\n" +
|
||||
" get_cash_flow_statements — same params\n" +
|
||||
" get_all_financial_statements — same params (returns all three)\n" +
|
||||
"Metrics:\n" +
|
||||
" get_financial_metrics_snapshot — params: { ticker }\n" +
|
||||
" get_financial_metrics — params: { ticker, period?, limit?, report_period*? }\n" +
|
||||
" get_analyst_estimates — params: { ticker, period? }\n" +
|
||||
"Company:\n" +
|
||||
" get_news — params: { ticker, start_date?, end_date?, limit? }\n" +
|
||||
" get_insider_trades — params: { ticker, limit?, filing_date*? }\n" +
|
||||
" get_segmented_revenues — params: { ticker, period, limit? }\n" +
|
||||
" get_company_facts — params: { ticker }\n" +
|
||||
"SEC Filings:\n" +
|
||||
" get_filings — params: { ticker, filing_type?, limit? }\n" +
|
||||
" get_filing_items — params: { ticker, filing_type, accession_number?, item? }",
|
||||
}),
|
||||
params: Type.Record(Type.String(), Type.Unknown(), {
|
||||
description:
|
||||
"Action-specific parameters as key-value pairs. " +
|
||||
"Common: ticker (string, e.g. 'AAPL'), period ('annual'|'quarterly'|'ttm'), " +
|
||||
"limit (number), start_date/end_date ('YYYY-MM-DD'), " +
|
||||
"interval ('day'|'week'|'month'|'year'), filing_type ('10-K'|'10-Q'|'8-K').",
|
||||
}),
|
||||
});
|
||||
|
||||
// ─── Types ──────────────────────────────────────────────────────────────────
|
||||
|
||||
type DataToolArgs = {
|
||||
domain: string;
|
||||
action: string;
|
||||
params: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type DataToolResult = {
|
||||
domain: string;
|
||||
action: string;
|
||||
data: unknown;
|
||||
sourceUrl?: string;
|
||||
};
|
||||
|
||||
// ─── Factory ────────────────────────────────────────────────────────────────
|
||||
|
||||
export function createDataTool(): AgentTool<typeof DataToolSchema, DataToolResult> {
|
||||
return {
|
||||
name: "data",
|
||||
label: "Data",
|
||||
description:
|
||||
"Query structured data from external sources. " +
|
||||
'Supports domain="finance" for stock prices, financial statements, key metrics, ' +
|
||||
"SEC filings, analyst estimates, insider trades, news, and crypto data.",
|
||||
parameters: DataToolSchema,
|
||||
execute: async (_toolCallId, args, signal) => {
|
||||
const { domain, action, params } = args as DataToolArgs;
|
||||
|
||||
if (domain !== "finance") {
|
||||
const errorPayload = {
|
||||
error: true,
|
||||
message: `Unknown domain: "${domain}". Currently supported: "finance".`,
|
||||
};
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(errorPayload, null, 2) }],
|
||||
details: { domain, action, data: null } as unknown as DataToolResult,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await executeFinanceAction(action, params ?? {}, signal);
|
||||
const payload: DataToolResult = {
|
||||
domain,
|
||||
action,
|
||||
data: result.data,
|
||||
sourceUrl: result.sourceUrl,
|
||||
};
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
||||
details: payload,
|
||||
};
|
||||
} catch (error) {
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
const errorPayload = { error: true, domain, action, message };
|
||||
return {
|
||||
content: [{ type: "text", text: JSON.stringify(errorPayload, null, 2) }],
|
||||
details: { domain, action, data: null } as unknown as DataToolResult,
|
||||
};
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
295
packages/core/src/agent/tools/data/finance/actions.ts
Normal file
295
packages/core/src/agent/tools/data/finance/actions.ts
Normal file
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* Finance action handlers.
|
||||
*
|
||||
* Maps each action name to the corresponding Financial Datasets API call.
|
||||
*/
|
||||
|
||||
import type { FinanceAction } from "./types.js";
|
||||
import { FINANCE_ACTION_SET } from "./types.js";
|
||||
import { financeFetch } from "./api.js";
|
||||
|
||||
// ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
type Params = Record<string, unknown>;
|
||||
|
||||
function requireParam(params: Params, name: string): string {
|
||||
const value = params[name];
|
||||
if (value === undefined || value === null || value === "") {
|
||||
throw new Error(`Missing required parameter: ${name}`);
|
||||
}
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function optionalString(params: Params, name: string): string | undefined {
|
||||
const value = params[name];
|
||||
if (value === undefined || value === null || value === "") return undefined;
|
||||
return String(value);
|
||||
}
|
||||
|
||||
function optionalNumber(params: Params, name: string): number | undefined {
|
||||
const value = params[name];
|
||||
if (value === undefined || value === null) return undefined;
|
||||
return Number(value);
|
||||
}
|
||||
|
||||
function optionalStringArray(params: Params, name: string): string[] | undefined {
|
||||
const value = params[name];
|
||||
if (value === undefined || value === null) return undefined;
|
||||
if (Array.isArray(value)) return value.map(String);
|
||||
return [String(value)];
|
||||
}
|
||||
|
||||
/** Extract common financial statement filter params */
|
||||
function statementFilters(params: Params) {
|
||||
return {
|
||||
ticker: requireParam(params, "ticker"),
|
||||
period: requireParam(params, "period"),
|
||||
limit: optionalNumber(params, "limit"),
|
||||
report_period_gt: optionalString(params, "report_period_gt"),
|
||||
report_period_gte: optionalString(params, "report_period_gte"),
|
||||
report_period_lt: optionalString(params, "report_period_lt"),
|
||||
report_period_lte: optionalString(params, "report_period_lte"),
|
||||
};
|
||||
}
|
||||
|
||||
// ─── Action result type ─────────────────────────────────────────────────────
|
||||
|
||||
export interface FinanceActionResult {
|
||||
data: unknown;
|
||||
sourceUrl: string;
|
||||
}
|
||||
|
||||
// ─── Action handlers ────────────────────────────────────────────────────────
|
||||
|
||||
type ActionHandler = (params: Params, signal?: AbortSignal) => Promise<FinanceActionResult>;
|
||||
|
||||
const handlers: Record<FinanceAction, ActionHandler> = {
|
||||
// ── Prices ──────────────────────────────────────────────────────────────
|
||||
|
||||
get_price_snapshot: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch("/prices/snapshot", { ticker }, signal);
|
||||
return { data: (data as Record<string, unknown>).snapshot ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_prices: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const start_date = requireParam(params, "start_date");
|
||||
const end_date = requireParam(params, "end_date");
|
||||
const { data, url } = await financeFetch(
|
||||
"/prices",
|
||||
{
|
||||
ticker,
|
||||
start_date,
|
||||
end_date,
|
||||
interval: optionalString(params, "interval") ?? "day",
|
||||
interval_multiplier: optionalNumber(params, "interval_multiplier"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).prices ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_crypto_price_snapshot: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch("/crypto/prices/snapshot", { ticker }, signal);
|
||||
return { data: (data as Record<string, unknown>).snapshot ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_crypto_prices: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const start_date = requireParam(params, "start_date");
|
||||
const end_date = requireParam(params, "end_date");
|
||||
const { data, url } = await financeFetch(
|
||||
"/crypto/prices",
|
||||
{
|
||||
ticker,
|
||||
start_date,
|
||||
end_date,
|
||||
interval: optionalString(params, "interval") ?? "day",
|
||||
interval_multiplier: optionalNumber(params, "interval_multiplier"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).prices ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_available_crypto_tickers: async (_params, signal) => {
|
||||
const { data, url } = await financeFetch("/crypto/prices/tickers", {}, signal);
|
||||
return { data: (data as Record<string, unknown>).tickers ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
// ── Financial statements ────────────────────────────────────────────────
|
||||
|
||||
get_income_statements: async (params, signal) => {
|
||||
const filters = statementFilters(params);
|
||||
const { data, url } = await financeFetch("/financials/income-statements", filters, signal);
|
||||
return { data: (data as Record<string, unknown>).income_statements ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_balance_sheets: async (params, signal) => {
|
||||
const filters = statementFilters(params);
|
||||
const { data, url } = await financeFetch("/financials/balance-sheets", filters, signal);
|
||||
return { data: (data as Record<string, unknown>).balance_sheets ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_cash_flow_statements: async (params, signal) => {
|
||||
const filters = statementFilters(params);
|
||||
const { data, url } = await financeFetch("/financials/cash-flow-statements", filters, signal);
|
||||
return { data: (data as Record<string, unknown>).cash_flow_statements ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_all_financial_statements: async (params, signal) => {
|
||||
const filters = statementFilters(params);
|
||||
const { data, url } = await financeFetch("/financials", filters, signal);
|
||||
return { data: (data as Record<string, unknown>).financials ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
// ── Metrics & estimates ─────────────────────────────────────────────────
|
||||
|
||||
get_financial_metrics_snapshot: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch("/financial-metrics/snapshot", { ticker }, signal);
|
||||
return { data: (data as Record<string, unknown>).snapshot ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_financial_metrics: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch(
|
||||
"/financial-metrics",
|
||||
{
|
||||
ticker,
|
||||
period: optionalString(params, "period"),
|
||||
limit: optionalNumber(params, "limit"),
|
||||
report_period: optionalString(params, "report_period"),
|
||||
report_period_gt: optionalString(params, "report_period_gt"),
|
||||
report_period_gte: optionalString(params, "report_period_gte"),
|
||||
report_period_lt: optionalString(params, "report_period_lt"),
|
||||
report_period_lte: optionalString(params, "report_period_lte"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).financial_metrics ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_analyst_estimates: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch(
|
||||
"/analyst-estimates",
|
||||
{
|
||||
ticker,
|
||||
period: optionalString(params, "period"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).analyst_estimates ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
// ── Company info ────────────────────────────────────────────────────────
|
||||
|
||||
get_news: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch(
|
||||
"/news",
|
||||
{
|
||||
ticker,
|
||||
start_date: optionalString(params, "start_date"),
|
||||
end_date: optionalString(params, "end_date"),
|
||||
limit: optionalNumber(params, "limit"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).news ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_insider_trades: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch(
|
||||
"/insider-trades",
|
||||
{
|
||||
ticker: ticker.toUpperCase(),
|
||||
limit: optionalNumber(params, "limit"),
|
||||
filing_date: optionalString(params, "filing_date"),
|
||||
filing_date_gt: optionalString(params, "filing_date_gt"),
|
||||
filing_date_gte: optionalString(params, "filing_date_gte"),
|
||||
filing_date_lt: optionalString(params, "filing_date_lt"),
|
||||
filing_date_lte: optionalString(params, "filing_date_lte"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).insider_trades ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_segmented_revenues: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const period = requireParam(params, "period");
|
||||
const { data, url } = await financeFetch(
|
||||
"/financials/segmented-revenues",
|
||||
{
|
||||
ticker,
|
||||
period,
|
||||
limit: optionalNumber(params, "limit"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).segmented_revenues ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_company_facts: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch("/company/facts", { ticker }, signal);
|
||||
return { data: (data as Record<string, unknown>).company_facts ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
// ── SEC filings ─────────────────────────────────────────────────────────
|
||||
|
||||
get_filings: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker");
|
||||
const { data, url } = await financeFetch(
|
||||
"/filings",
|
||||
{
|
||||
ticker,
|
||||
filing_type: optionalString(params, "filing_type"),
|
||||
limit: optionalNumber(params, "limit"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data: (data as Record<string, unknown>).filings ?? data, sourceUrl: url };
|
||||
},
|
||||
|
||||
get_filing_items: async (params, signal) => {
|
||||
const ticker = requireParam(params, "ticker").toUpperCase();
|
||||
const filing_type = requireParam(params, "filing_type");
|
||||
const { data, url } = await financeFetch(
|
||||
"/filings/items",
|
||||
{
|
||||
ticker,
|
||||
filing_type,
|
||||
accession_number: optionalString(params, "accession_number"),
|
||||
item: optionalStringArray(params, "item"),
|
||||
},
|
||||
signal,
|
||||
);
|
||||
return { data, sourceUrl: url };
|
||||
},
|
||||
};
|
||||
|
||||
// ─── Public API ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Execute a finance domain action.
|
||||
*
|
||||
* @throws Error if the action is unknown or required params are missing.
|
||||
*/
|
||||
export function executeFinanceAction(
|
||||
action: string,
|
||||
params: Record<string, unknown>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<FinanceActionResult> {
|
||||
if (!FINANCE_ACTION_SET.has(action)) {
|
||||
throw new Error(
|
||||
`Unknown finance action: "${action}". Available: ${[...FINANCE_ACTION_SET].join(", ")}`,
|
||||
);
|
||||
}
|
||||
return handlers[action as FinanceAction](params, signal);
|
||||
}
|
||||
74
packages/core/src/agent/tools/data/finance/api.ts
Normal file
74
packages/core/src/agent/tools/data/finance/api.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Financial Datasets API client.
|
||||
*
|
||||
* Base URL: https://api.financialdatasets.ai
|
||||
* Auth: X-API-KEY header
|
||||
* All endpoints use GET with query parameters.
|
||||
*/
|
||||
|
||||
import { credentialManager } from "../../../credentials.js";
|
||||
|
||||
const BASE_URL = "https://api.financialdatasets.ai";
|
||||
const TIMEOUT_MS = 30_000;
|
||||
|
||||
function getApiKey(): string {
|
||||
const key = credentialManager.getEnv("FINANCIAL_DATASETS_API_KEY");
|
||||
if (!key) {
|
||||
throw new Error(
|
||||
"FINANCIAL_DATASETS_API_KEY not configured. " +
|
||||
"Set it in ~/.super-multica/skills.env.json5 under env, or as an environment variable.",
|
||||
);
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch data from the Financial Datasets API.
|
||||
*
|
||||
* @param path - API path (e.g., "/prices/snapshot")
|
||||
* @param params - Query parameters. Arrays are sent as repeated params (e.g., item=1A&item=1B).
|
||||
* @param signal - Optional AbortSignal for cancellation.
|
||||
*/
|
||||
export async function financeFetch<T = Record<string, unknown>>(
|
||||
path: string,
|
||||
params: Record<string, string | string[] | number | boolean | undefined>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<{ data: T; url: string }> {
|
||||
const apiKey = getApiKey();
|
||||
|
||||
const url = new URL(path, BASE_URL);
|
||||
for (const [key, value] of Object.entries(params)) {
|
||||
if (value === undefined || value === null) continue;
|
||||
if (Array.isArray(value)) {
|
||||
for (const v of value) {
|
||||
url.searchParams.append(key, String(v));
|
||||
}
|
||||
} else {
|
||||
url.searchParams.set(key, String(value));
|
||||
}
|
||||
}
|
||||
|
||||
const timeoutSignal = AbortSignal.timeout(TIMEOUT_MS);
|
||||
const combinedSignal = signal
|
||||
? AbortSignal.any([signal, timeoutSignal])
|
||||
: timeoutSignal;
|
||||
|
||||
const res = await fetch(url.toString(), {
|
||||
method: "GET",
|
||||
headers: {
|
||||
"X-API-KEY": apiKey,
|
||||
Accept: "application/json",
|
||||
},
|
||||
signal: combinedSignal,
|
||||
});
|
||||
|
||||
if (!res.ok) {
|
||||
const body = await res.text().catch(() => "");
|
||||
throw new Error(
|
||||
`Financial Datasets API error (${res.status}): ${body || res.statusText}`,
|
||||
);
|
||||
}
|
||||
|
||||
const data = (await res.json()) as T;
|
||||
return { data, url: url.toString() };
|
||||
}
|
||||
35
packages/core/src/agent/tools/data/finance/types.ts
Normal file
35
packages/core/src/agent/tools/data/finance/types.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Finance domain types for the data tool.
|
||||
*/
|
||||
|
||||
/** All supported finance actions */
|
||||
export const FINANCE_ACTIONS = [
|
||||
// Price data
|
||||
"get_price_snapshot",
|
||||
"get_prices",
|
||||
"get_crypto_price_snapshot",
|
||||
"get_crypto_prices",
|
||||
"get_available_crypto_tickers",
|
||||
// Financial statements
|
||||
"get_income_statements",
|
||||
"get_balance_sheets",
|
||||
"get_cash_flow_statements",
|
||||
"get_all_financial_statements",
|
||||
// Metrics & estimates
|
||||
"get_financial_metrics_snapshot",
|
||||
"get_financial_metrics",
|
||||
"get_analyst_estimates",
|
||||
// Company info
|
||||
"get_news",
|
||||
"get_insider_trades",
|
||||
"get_segmented_revenues",
|
||||
"get_company_facts",
|
||||
// SEC filings
|
||||
"get_filings",
|
||||
"get_filing_items",
|
||||
] as const;
|
||||
|
||||
export type FinanceAction = (typeof FINANCE_ACTIONS)[number];
|
||||
|
||||
/** Set for O(1) lookup */
|
||||
export const FINANCE_ACTION_SET = new Set<string>(FINANCE_ACTIONS);
|
||||
1
packages/core/src/agent/tools/data/index.ts
Normal file
1
packages/core/src/agent/tools/data/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { createDataTool, type DataToolResult } from "./data-tool.js";
|
||||
@@ -39,6 +39,9 @@ export const TOOL_GROUPS: Record<string, string[]> = {
|
||||
// Cron/scheduling tools
|
||||
"group:cron": ["cron"],
|
||||
|
||||
// Data tools (finance, etc.)
|
||||
"group:data": ["data"],
|
||||
|
||||
// All core tools
|
||||
"group:core": [
|
||||
"read",
|
||||
@@ -49,6 +52,7 @@ export const TOOL_GROUPS: Record<string, string[]> = {
|
||||
"process",
|
||||
"web_search",
|
||||
"web_fetch",
|
||||
"data",
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ export { createProcessTool } from "./process.js";
|
||||
export { createGlobTool } from "./glob.js";
|
||||
export { createWebFetchTool, createWebSearchTool } from "./web/index.js";
|
||||
export { createCronTool } from "./cron/index.js";
|
||||
export { createDataTool } from "./data/index.js";
|
||||
export { createSessionsListTool } from "./sessions-list.js";
|
||||
|
||||
// Tool groups
|
||||
|
||||
Reference in New Issue
Block a user