/** * Tools slot subflow builder * * Pattern: Builder (returns a FlowChart mountable via addSubFlowChartNext). * Role: Layer-3 context engineering. Resolves the tools list the LLM * sees on this iteration — one InjectionRecord per exposed tool. * Emits: None directly; ContextRecorder sees the writes. * * Minimal scope for Phase 3e: static tool registry, all exposed every * iteration. Full permission gating / skill activation / context-aware * tool filtering arrives in Phase 5. */ import type { FlowChart } from 'footprintjs'; import type { LLMToolSchema } from '../../adapters/types.js'; import type { Tool } from '../tools.js'; import type { ToolProvider } from '../../tool-providers/types.js'; /** * Mutable cache shared between `buildToolsSlot` (writer) and * `buildToolCallsHandler` (reader) within ONE run. The Tools slot * resolves the provider's tools each iteration and stashes the * Tool[] here; the toolCalls handler reads on dispatch — so async * providers pay the discovery cost once, not twice. Scoped to the * chart build so concurrent `agent.run()` calls each get their own * cache. */ export interface ProviderToolCache { current: readonly Tool[]; } export interface ToolsSlotConfig { /** Tool registry exposed to the LLM. Empty → empty slot (LLMCall case). */ readonly tools: readonly LLMToolSchema[]; /** * Optional `ToolProvider` consulted PER-ITERATION (Block A5 follow-up). * When set, the slot calls `provider.list(ctx)` each iteration with * the current `{ iteration, activeSkillId, identity, signal }`. * Provider-supplied tool schemas are MERGED with the static `tools` * registry — both flow to the LLM. This is what makes Dynamic ReAct's * tool list reshape per iteration. */ readonly toolProvider?: ToolProvider; /** * Mutable cache the slot writes to after resolving `toolProvider.list(ctx)`. * The same cache reference is passed to `buildToolCallsHandler` so * dispatch reads from this iteration's resolved Tool[] instead of * calling `list()` a second time. Required when `toolProvider` is set. */ readonly providerToolCache?: ProviderToolCache; /** Budget cap (chars). Default: 2000. */ readonly budgetCap?: number; } /** * Build the Tools slot subflow. * * Mount with: * builder.addSubFlowChartNext(SUBFLOW_IDS.TOOLS, buildToolsSlot(cfg), 'Tools', { * inputMapper: (parent) => ({ iteration: parent.iteration }), * outputMapper: (sf) => ({ toolsInjections: sf.toolsInjections, toolSchemas: sf.toolSchemas }), * }) */ export declare function buildToolsSlot(config: ToolsSlotConfig): FlowChart;