pi-mono/packages/coding-agent/src/core/extensions/wrapper.ts
Armin Ronacher 3d8f74357c
feat(ai): support message-anchored tool loading (#6474)
This adds cache-friendly dynamic tool loading anchored to tool results. Purely additive active-tool changes are recorded with `addedToolNames`, allowing supported Anthropic and OpenAI Responses models to load tool definitions at the point they become available instead of placing them in the cached prompt prefix.

It retains safe fallback behavior for unsupported models and non-additive changes but it will wipe caches.
2026-07-10 23:52:54 +02:00

45 lines
1.8 KiB
TypeScript

/**
* Tool wrappers for extension-registered tools.
*
* These wrappers only adapt tool execution so extension tools receive the runner context.
* Tool call and tool result interception is handled by AgentSession via agent-core hooks.
*/
import type { AgentTool } from "@earendil-works/pi-agent-core";
import { wrapToolDefinition } from "../tools/tool-definition-wrapper.ts";
import type { ExtensionRunner } from "./runner.ts";
import type { RegisteredTool } from "./types.ts";
/**
* Wrap a RegisteredTool into an AgentTool.
* Uses the runner's createContext() for consistent context across tools and event handlers.
*/
export function wrapRegisteredTool(registeredTool: RegisteredTool, runner: ExtensionRunner): AgentTool {
const tool = wrapToolDefinition(registeredTool.definition, () => runner.createContext());
const execute = tool.execute;
return {
...tool,
execute: async (toolCallId, params, signal, onUpdate) => {
const activeBefore = runner.getActiveTools();
const result = await execute(toolCallId, params, signal, onUpdate);
const activeAfter = runner.getActiveTools();
if (!activeBefore.every((name) => activeAfter.includes(name))) return result;
const beforeNames = new Set(activeBefore);
const addedToolNames = activeAfter.filter((name) => !beforeNames.has(name));
if (addedToolNames.length === 0) return result;
return {
...result,
addedToolNames: [...new Set([...(result.addedToolNames ?? []), ...addedToolNames])],
};
},
};
}
/**
* Wrap all registered tools into AgentTools.
* Uses the runner's createContext() for consistent context across tools and event handlers.
*/
export function wrapRegisteredTools(registeredTools: RegisteredTool[], runner: ExtensionRunner): AgentTool[] {
return registeredTools.map((tool) => wrapRegisteredTool(tool, runner));
}