import toolMap from "./tool-defs/index.ts"; import { Config } from "../config.ts"; import { Transport } from "../transports/transport-common.ts"; import { Result, ok, err } from "../libocto/result.ts"; import { LoadedTools as GenericLoadedTools, ToolCall as GenericToolCall, ToolFactoryRequirements, ToolReturn, } from "../libocto/tool-def.ts"; export type LoadedTools = GenericLoadedTools; export type ToolCall = GenericToolCall; type ToolExtra = T extends ToolFactoryRequirements ? Extra : never; export type ToolRunResult = ToolReturn>; export async function loadTools( transport: Transport, signal: AbortSignal, config: Config, ): Promise> { const loaded: Partial = {}; await Promise.all( (Object.keys(toolMap) as Array).map(async key => { const toolDef = await toolMap[key]({ signal, transport, data: config }); if (toolDef) { toolDef.name = key; // @ts-ignore loaded[key] = toolDef; } }), ); return loaded as LoadedTools; } export const SKIP_CONFIRMATION_TOOLS: Array = [ "read", "partial-read", "list", "skill", "web-search", "fetch", "glob", "grep", "lsp-definition", "lsp-references", "lsp-hover", "lsp-diagnostics", "lsp-document-symbol", "lsp-implementation", "lsp-incoming-calls", "lsp-outgoing-calls", ]; export const ALWAYS_REQUEST_PERMISSION_TOOLS: Array = ["shell"]; export async function runTool( abortSignal: AbortSignal, transport: Transport, loaded: Partial, call: ToolCall, config: Config, ): Promise> { const def = lookup(loaded, call); if (!def.success) return def; const output = await (def.data as any).run({ signal: abortSignal, transport, toolCall: { toolCallId: call.toolCallId, original: { name: call.name, arguments: call.original }, parsed: { name: call.name, arguments: call.parsed }, }, data: config, }); return output; } export async function validateTool( abortSignal: AbortSignal, transport: Transport, loaded: Partial, tool: ToolCall, config: Config, ): Promise> { const toolDef = lookup(loaded, tool); if (!toolDef.success) return toolDef; return await toolDef.data.validate( abortSignal, transport, { original: { name: tool.name, arguments: tool.original }, parsed: { name: tool.name, arguments: tool.parsed }, }, config, ); } function lookup(loaded: Partial, t: T): Result { const def = (loaded as any)[(t as any).name]; if (def == null) return err(`No tool named ${t.name}`); return ok(def); }