| 351 | } |
| 352 | } |
| 353 | return count; |
| 354 | } |
| 355 | |
| 356 | get(name: string): Tool<any> | undefined { |
| 357 | return this.tools.get(this.resolveName(name)); |
| 358 | } |
| 359 | |
| 360 | has(name: string): boolean { |
| 361 | return this.tools.has(this.resolveName(name)); |
| 362 | } |
| 363 | |
| 364 | getSchemas(mode: ToolExecutionMode): ToolSchema[] { |
| 365 | const filtered = this.filterByMode(mode); |
| 366 | // Two-bucket deterministic sort: |
| 367 | // 1. "Common" tools first, in a fixed hand-picked order. LLMs pay more attention |
| 368 | // to tools at the top of the list — putting bash, read_file, write_file, etc. |
| 369 | // first significantly improves tool-call accuracy on smaller models like |
| 370 | // Qwen 2.5 Coder, where a flood of code_graph_* tools at the top was burying |
| 371 | // the basics. |
| 372 | // 2. Everything else alphabetical. |
| 373 | // |
| 374 | // Order within each bucket is still deterministic, which preserves the byte-identical |
| 375 | // tool-schema prefix needed for prompt caching (Ollama, vLLM, Anthropic cache). |
| 376 | // |
| 377 | // The COMMON list is intentionally short and stable — adding tools here breaks |
| 378 | // cached prefixes for users, so keep changes deliberate. |
| 379 | const COMMON_PRIORITY = [ |
| 380 | 'shell', 'read_file', 'write_file', 'edit_text', 'multi_edit', 'edit_symbol', |
| 381 | 'ls', 'glob', 'grep', 'todo_write', 'todo_read', |
| 382 | ]; |
| 383 | const priorityIndex = new Map(COMMON_PRIORITY.map((name, i) => [name, i])); |
| 384 | |
| 385 | return filtered |
| 386 | .map(t => t.schema()) |
| 387 | .sort((a, b) => { |
| 388 | const aPri = priorityIndex.get(a.function.name); |
| 389 | const bPri = priorityIndex.get(b.function.name); |
| 390 | // Both in priority list: order by priority index |