UNPKG

agentfootprint

Version:

The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.

86 lines (85 loc) • 4.21 kB
/** * tools/script — a tool's declaration that it RUNS a program, and the one rule * that judges the declaration. * * Pattern: Map. `Tool.script` is plain data on the tool, judged by ONE assert * at the three doors a declaration crosses (the `askOrAssume` * precedent, `tools/declare.ts`): definition (`tools.ts` · * `defineTool`), dispatch (`scriptOf`, for a Tool built by hand or * served by a ToolProvider, which never passes `defineTool`) and MCP * ingest (`mcp/toolExtras.ts` · `readToolExtras`). * Role: tools/ layer leaf (L7). Imports nothing from the agent. * Emits: N/A. * * ## Declared, never inferred * * A tool is code-running because it SAYS so. The library never reads it off a * tool's name (`run_code`), a property named `code` or the description. A tool * that runs code and does not declare it has no submissions on the record, so * a script the model shows for it is prose, as it always was. `codeRunnerTool` * declares `{ argument: 'code', language }` on the tool it builds. * * What the declaration arms (design: docs/design/2026-10-script-artifact.md): * the dispatch loop files one `script` row per call of the tool while * `.namesAndNumbersFromEvidence({ code: 'match' })` or * `.scriptTravelsWithTheAnswer()` is on — the program SUBMITTED to the tool, * and what the runner reported. Never evidence for a value. * * @example * ```ts * const runSql = defineTool({ * name: 'run_sql', * description: 'Run a read-only SQL query and print the rows.', * inputSchema: { type: 'object', properties: { query: { type: 'string' } }, required: ['query'] }, * script: { argument: 'query', language: 'sql' }, * execute: async ({ query }) => db.read(query), * }); * ``` */ /** Where a code-running tool's program travels, and its language. */ export interface ToolScript { /** The ONE string argument of the input schema that carries the program. */ readonly argument: string; /** * The program's language — the info string of the fence the library renders * the program in (`python`, `sql`). One plain token: no line break, no * backtick (a backtick fence's info string may not hold one), at most 64 * characters. Absent → a fence with no info string. */ readonly language?: string; } /** * The one judge of a `script` declaration: refuses, naming the tool, the field * and the fix — a declaration the dispatch loop could not honour, never one it * would quietly repair. * * - a plain object holding only `argument` and `language`; * - `argument` names a property of the input schema whose `type` is `'string'` * (a program is text), and not a `wants` argument (that one carries an * artifact ref, then its data — never the program); * - `language`, when present, is one plain token the fence can carry. */ export declare function assertToolScript(toolName: string, script: unknown, inputSchema: Readonly<Record<string, unknown>> | undefined, wants?: Readonly<Record<string, unknown>>): void; /** A frozen copy of a well-formed declaration: the two fields, nothing else. */ export declare function copyToolScript(script: ToolScript): ToolScript; /** The tool shape the dispatch door reads — structurally any `Tool`. */ export interface ScriptToolLike { readonly schema: { readonly name: string; readonly inputSchema?: Readonly<Record<string, unknown>>; }; readonly script?: unknown; readonly wants?: Readonly<Record<string, unknown>>; } /** * THE DISPATCH DOOR — the tool's `script` declaration, judged once per tool * object, or `undefined` when it declares none. * * A tool built by hand or served by a ToolProvider never passed `defineTool`, * so its declaration is judged here by the same assert. One that fails it is * NOT a code-running tool for the record (no row is filed, a block the model * shows for it is prose) — never half-honoured — and dev mode names the rule * once, the MCP ingest law (`mcp/toolExtras.ts`): the rail stays unarmed and * the developer is told which and why. */ export declare function scriptOf(tool: ScriptToolLike | undefined): ToolScript | undefined;