(name: string, args: unknown, ctx: ToolContext)
| 412 | tools = tools.filter(t => t.name !== 'present_plan'); |
| 413 | } |
| 414 | |
| 415 | if (mode.allowedTools) { |
| 416 | tools = tools.filter(t => mode.allowedTools!.includes(t.name)); |
| 417 | } |
| 418 | if (mode.blockedTools) { |
| 419 | tools = tools.filter(t => !mode.blockedTools!.includes(t.name)); |
| 420 | } |
| 421 | |
| 422 | return tools; |
| 423 | } |
| 424 | |
| 425 | async execute(name: string, args: unknown, ctx: ToolContext): Promise<ToolResult> { |
| 426 | const tool = this.tools.get(this.resolveName(name)); |
| 427 | if (!tool) { |
| 428 | // Suggest the closest known tool name to nudge the model onto the right one. |
| 429 | const known = Array.from(this.tools.keys()); |
| 430 | const guess = known.find(k => k.includes(name) || name.includes(k)); |
| 431 | const hint = guess ? ` Did you mean "${guess}"?` : ` Use one of the listed tools (e.g. "shell" for commands).`; |
| 432 | return { content: `[ERROR] Unknown tool: ${name}.${hint}`, isError: true }; |
| 433 | } |
| 434 | |
| 435 | // Validate args. Two normalization passes BEFORE zod (schema stays strict, so the |
| 436 | // JSON schema the model sees is unchanged): |
| 437 | // 1. tool.coerceArgs — tool-specific fixups (e.g. todo_write's stringy ids). |
| 438 | // 2. coerceArgsToSchema — generic, schema-guided repair of unambiguous type |
| 439 | // mistakes ("5"→5, JSON-string→array, "true"→true). Backend-agnostic; turns |
| 440 | // a class of would-be ARGUMENT_VALIDATION_ERRORs into successful calls. |
| 441 | let parsed: any; |
| 442 | try { |
| 443 | const jsonSchema = tool.schema().function.parameters as JsonSchemaNode; |
| 444 | parsed = tool.argsSchema.parse(coerceArgsToSchema(tool.coerceArgs(args), jsonSchema)); |
| 445 | } catch (e: any) { |
| 446 | const errMsg = e.errors |
| 447 | ? e.errors.map((err: any) => `${err.path.join('.')}: ${err.message}`).join('; ') |
| 448 | : e.message; |
| 449 | return { |
| 450 | content: `[ARGUMENT_VALIDATION_ERROR] ${errMsg}\nProvided args: ${JSON.stringify(args)}\nFix your tool arguments and try again.`, |
| 451 | isError: true, |
| 452 | }; |
| 453 | } |
| 454 | |
| 455 | logger.debug('Executing tool', { name, args: parsed }); |
| 456 | |
| 457 | try { |
| 458 | const result = await tool.execute(parsed, ctx); |
nothing calls this directly
no test coverage detected