| 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 |
| 391 | if (aPri !== undefined && bPri !== undefined) return aPri - bPri; |
| 392 | // Only A in priority list: A comes first |
| 393 | if (aPri !== undefined) return -1; |
| 394 | if (bPri !== undefined) return 1; |
| 395 | // Neither in priority list: alphabetical |
| 396 | return a.function.name.localeCompare(b.function.name); |
| 397 | }); |
| 398 | } |
| 399 | |
| 400 | filterByMode(mode: ToolExecutionMode): Tool<any>[] { |
| 401 | let tools = Array.from(this.tools.values()); |
| 402 | |
| 403 | if (mode.mode === 'plan') { |
| 404 | // Only read-only + plan-specific tools |
| 405 | tools = tools.filter(t => t.isReadOnly || t.name === 'present_plan' || t.name === 'todo_write' || t.name === 'todo_read'); |
| 406 | } else if (mode.mode === 'subagent') { |
| 407 | // Exclude every sub-agent-spawning tool (no recursion) + present_plan. |
| 408 | const noRecursion = new Set(['task', 'gather', 'orchestrate', 'fanout', 'present_plan']); |
| 409 | tools = tools.filter(t => !noRecursion.has(t.name)); |
| 410 | } else { |
| 411 | // Normal mode: exclude present_plan (only used in plan mode) |
| 412 | tools = tools.filter(t => t.name !== 'present_plan'); |
| 413 | } |
| 414 | |
| 415 | if (mode.allowedTools) { |