/** * The host's tool sources: `tool()` (descriptor + execute, the host's own auth * model), `api()` (the existing actions registry over `.vendo/tools.json`), * `mcp` servers, and `mergeSources` — one registry the guard binds, where a * name collision is a boot error, never a silent shadow. */ import { type Connector, type McpHeadersResolver } from "../actions/index.js"; import { type ActAs, type Json, type JsonSchema, type RiskLabel, type RunContext, type ToolCall, type ToolDescriptor, type ToolRegistry } from "../core/index.js"; import { type FlexibleSchema, type InferSchema } from "ai"; /** What `execute` is handed. A zod (or any standard-schema) `inputSchema` types * it; a raw JSON Schema cannot, because JSON Schema is data — there is nothing * in it for TypeScript to read — so that branch stays `Json`, as it always was. */ export type ToolInput = [InferSchema] extends [never] ? Json : InferSchema; export interface ToolConfig { name: string; /** What this tool does and when to reach for it. REQUIRED: it is the only * thing the model reads when deciding whether to call it. */ description: string; /** The dev's label is FINAL; unlabeled = ungraded = asks at call time. */ risk?: RiskLabel; /** A zod schema — which also types `execute`'s `input` — or a raw JSON * Schema for a host that has one already. */ inputSchema: TSchema; /** The tool's DECLARED result shape. Surfaces print it, so generated UI can * bind to fields before any call; nothing validates a result against it, so a * stale schema never fails a working tool. */ outputSchema?: JsonSchema; execute(input: ToolInput, ctx: RunContext, call: ToolCall): Promise | Json; } /** One host-authored tool, ready for `agent({ tools: [...] })`. */ export interface HostTool { descriptor: ToolDescriptor; execute(input: Json, ctx: RunContext, call: ToolCall): Promise | Json; } export type ToolSource = HostTool | ToolRegistry; export declare function tool(config: ToolConfig): HostTool; export interface ApiOptions { /** The `.vendo` directory (or host root); defaults to the working directory. */ dir?: string; /** Away-run auth minting; a present user's headers forward on their own. */ actAs?: ActAs; /** The host origin route/tRPC tools dial; defaults to `VENDO_BASE_URL`. */ baseUrl?: string; untrustedOriginPolicy?: "warn" | "fail"; fetch?: typeof fetch; } /** The existing actions registry: `.vendo/tools.json`, layered overrides, * present-header forwarding with the origin gate, `actAs` for away runs. */ export declare function api(options?: ApiOptions): ToolRegistry; /** * `agent({ mcp: [...] })` — external MCP servers as tool sources, through the * existing outbound connector. Static headers = one shared identity for every * user; a resolver function = per-user identity, resolved at call time. */ export interface McpServerConfig { url: string; headers?: Record | McpHeadersResolver; /** Tool-name prefix (`mcp__*`); defaults to "mcp". */ name?: string; } export declare function mcpSources(configs: readonly McpServerConfig[]): Connector[]; /** * Merge the host's tool sources and MCP servers into ONE registry. * * Statically-known names (every `tool()`) collide at boot, synchronously. * Dynamic sources (`api()`, MCP listings) are only knowable by asking them, so * their collisions throw on the first projection instead — still before any * call can dispatch through a shadowed name. */ export declare function mergeSources(sources: readonly ToolSource[], mcp: readonly McpServerConfig[]): ToolRegistry;