import type { AgentToolResult } from "@earendil-works/pi-coding-agent"; import { RESERVED_AGENT_TOOL, RESERVED_APPROVAL_TOOL, RESERVED_LOAD_TOOL, RESERVED_MCP_TOOL, RESERVED_MEMORY_TOOL, RESERVED_OUTPUT_TOOL, RESERVED_SCHEMA_TOOL, RESERVED_STORE_TOOL, } from "../bridge/reserved.ts"; import type { SessionStore } from "../tool/session-store.ts"; import type { EvalLanguage, EvalStatusEvent, ExecuteTool, } from "../tool/types.ts"; import { type AgentExecuteTool, runEvalAgent } from "./agent-bridge.ts"; import { type MarshalledToolResult, type OutputExecuteTool, runEvalOutput, } from "./output-bridge.ts"; import { type McpClient, runEvalMcp } from "./mcp-bridge.ts"; import { runEvalApproval } from "./approval-bridge.ts"; import { runEvalMemory } from "./memory-bridge.ts"; import { type EvalSchemaToolInfo, runEvalSchema } from "./schema-bridge.ts"; export interface ReservedDispatchContext { readonly args: unknown; readonly callId: string; readonly emitStatus: (event: EvalStatusEvent) => void; readonly executeTool: AgentExecuteTool & OutputExecuteTool & ExecuteTool; readonly listTools: (() => readonly EvalSchemaToolInfo[]) | undefined; readonly marshalToolResult: ( result: AgentToolResult ) => MarshalledToolResult; /** Session value store backing the store()/load() helpers. */ readonly sessionStore: SessionStore; /** MCP client backing the mcp() helper; absent until the host wires one. */ readonly mcpClient?: McpClient; /** Agent directory backing the recall() helper; defaults to getAgentDir(). */ readonly agentDir?: string; readonly signal: AbortSignal | undefined; readonly taskOutputToolName: string; readonly taskToolName: string; } const STORE_LANGUAGES: readonly string[] = ["py", "js", "rb"]; function storeLoadArgs(args: unknown): { readonly language: EvalLanguage; readonly key: string; readonly value: unknown; } { const record = ( typeof args === "object" && args !== null ? args : {} ) as Readonly>; const language = record.language; if (typeof language !== "string" || !STORE_LANGUAGES.includes(language)) { throw new TypeError( `store()/load(): unsupported language ${String(language)}` ); } const key = record.key; if (typeof key !== "string") { throw new TypeError( `store()/load(): key must be a string (got ${key === null ? "null" : typeof key})` ); } return { language: language as EvalLanguage, key, value: record.value }; } class SchemaUnavailableError extends Error { readonly name = "SchemaUnavailableError"; constructor() { super( "tool_schema() unavailable: this session does not expose a tool catalog" ); } } export function isReservedToolName(toolName: string): boolean { return ( toolName === RESERVED_AGENT_TOOL || toolName === RESERVED_OUTPUT_TOOL || toolName === RESERVED_SCHEMA_TOOL || toolName === RESERVED_STORE_TOOL || toolName === RESERVED_LOAD_TOOL || toolName === RESERVED_MCP_TOOL || toolName === RESERVED_MEMORY_TOOL || toolName === RESERVED_APPROVAL_TOOL ); } export async function runReservedTool( toolName: string, context: ReservedDispatchContext ): Promise { if (toolName === RESERVED_AGENT_TOOL) { return await runEvalAgent(context.args, { callId: context.callId, taskToolName: context.taskToolName, executeTool: context.executeTool, ...(context.signal === undefined ? {} : { signal: context.signal }), emitStatus: context.emitStatus, }); } if (toolName === RESERVED_OUTPUT_TOOL) { return await runEvalOutput(context.args, { taskOutputToolName: context.taskOutputToolName, executeTool: context.executeTool, ...(context.signal === undefined ? {} : { signal: context.signal }), marshalToolResult: context.marshalToolResult, }); } if (toolName === RESERVED_SCHEMA_TOOL) { const listTools = context.listTools; if (listTools === undefined) { throw new SchemaUnavailableError(); } return runEvalSchema(context.args, { listTools }); } if (toolName === RESERVED_STORE_TOOL) { const args = storeLoadArgs(context.args); return context.sessionStore.stage(args.language, args.key, args.value); } if (toolName === RESERVED_LOAD_TOOL) { const args = storeLoadArgs(context.args); return context.sessionStore.read(args.language, args.key); } if (toolName === RESERVED_MCP_TOOL) { return await runEvalMcp(context.args, { client: context.mcpClient, ...(context.signal === undefined ? {} : { signal: context.signal }), }); } if (toolName === RESERVED_MEMORY_TOOL) { return await runEvalMemory(context.args, { ...(context.agentDir === undefined ? {} : { agentDir: context.agentDir }), ...(context.signal === undefined ? {} : { signal: context.signal }), }); } if (toolName === RESERVED_APPROVAL_TOOL) { return await runEvalApproval(context.args, { ...(context.signal === undefined ? {} : { signal: context.signal }), }); } throw new Error( `runReservedTool received a non-reserved tool name: ${toolName}` ); }