Context
A single ranking at task start can miss tools the conversation drifts toward in the first few turns. The rolling window re-runs ranking against the latest user message for the first N turns (default 7) and unions the result into `Task.attachedMcpToolNames` — tools are only ever appended, never removed. After turn N the set is frozen; only `mcp_load` can grow it further.
The union-only rule preserves prompt caching: the API `tools` array prefix grows monotonically, so cached prefixes are never invalidated by a removal.
Depends on #578 and #579.
Developer Notes
- New setting `mcp.dynamicLoad.searchTurns` (default 7). `0` disables dynamic loading entirely; `1` is sticky-from-start with no rolling.
- Constant `MAX_ATTACHED_DURING_ROLLING = 60` (export from `packages/types/src/mcp.ts`). If `|attachedMcpToolNames| ≥ this` after a proposed append in the rolling phase, stop appending for that turn and log a warning.
- In `src/core/task/build-tools.ts`, before each API call within the first N turns:
- Compute `queryText` = last user message (or last 2 messages, capped to avoid wasting tokens on the ranking call).
- Call `ToolRouter.search(queryText, scopedTools, initialK)`.
- `attachedMcpToolNames ← attachedMcpToolNames ∪ result` (union, never remove).
- Build the API `tools` array in stable order (attach order, then tool name) so cached prefixes are deterministic across turns.
Acceptance Criteria
Context
A single ranking at task start can miss tools the conversation drifts toward in the first few turns. The rolling window re-runs ranking against the latest user message for the first N turns (default 7) and unions the result into `Task.attachedMcpToolNames` — tools are only ever appended, never removed. After turn N the set is frozen; only `mcp_load` can grow it further.
The union-only rule preserves prompt caching: the API `tools` array prefix grows monotonically, so cached prefixes are never invalidated by a removal.
Depends on #578 and #579.
Developer Notes
Acceptance Criteria