/** * A terminating structured-output tool. When a subagent is given a schema, this * tool is the only way for it to "return" — Pi validates the arguments against the * schema before execute() runs, and `terminate: true` lets the subagent finish on * this call without paying for an extra assistant turn. */ import { defineTool, type ToolDefinition } from "@earendil-works/pi-coding-agent"; import type { Static, TSchema } from "typebox"; import { assertStructuredOutputLimit } from "./value-limits.ts"; export interface StructuredOutputCapture { value: T | undefined; called: boolean; } export interface StructuredOutputToolOptions { schema: TSchemaDef; capture: StructuredOutputCapture>; name?: string; } export function createStructuredOutputTool({ schema, capture, name = "structured_output", }: StructuredOutputToolOptions): ToolDefinition> { return defineTool({ name, label: "Structured Output", description: "Return the final machine-readable result for this subagent task.", promptSnippet: "Return final machine-readable output", promptGuidelines: [ `${name} is the final answer channel for this task; call ${name} exactly once when done.`, `Do not write a prose final answer after calling ${name}.`, `If you need to inspect files or run commands first, do so, then call ${name} exactly once.`, ], parameters: schema, async execute(_toolCallId, params) { assertStructuredOutputLimit(params); capture.value = params; capture.called = true; return { content: [{ type: "text", text: "Structured output received." }], details: params, terminate: true, }; }, }); }