Problem
The system prompt for a request is generated once, from the settings at that moment, when the request is built (getSystemPrompt is awaited once in src/core/task/Task.ts). Tool-call validation during the streaming response does not reuse that moment: for every tool call it re-reads current settings. In src/core/assistant-message/presentAssistantMessage.ts, each tool call fetches fresh state inside the tool_use case of presentAssistantMessage (const state = await cline.providerRef.deref()?.getState() at presentAssistantMessage.ts:347), destructures disabledTools from it (presentAssistantMessage.ts:348), and converts it into the validation requirements passed to validateToolUse.
Observed in version v3.82.1
Consequence
Generating once and validating live makes the two moments diverge whenever settings change mid-request. If disabledTools gains an entry after the prompt was built, validation rejects a tool the prompt advertised, and the model gets a rejection for following its instructions. If an entry is removed mid-request, validation accepts a tool the prompt never advertised. Either way the effective tool policy differs between the prompt and the validator within a single request.
Desired behavior
Runtime validation during an in-flight request should consume the same policy snapshot the prompt for that request was generated from. This is a new property: on version v3.82.1 both layers read live state, and no request-scoped snapshot exists to share.
For this issue, the request's policy snapshot is exactly the set of inputs the request's tool validation consumes: disabledTools, experiments, customModes, and the request's modelInfo (the source of the model's excluded and included tools). Validation must consume that snapshot rather than re-read live settings.
Acceptance criteria
- The request's policy snapshot is threaded through the streaming presentation chain as a required parameter, with no fallback re-read of live settings (terminal contract: callers that do not supply it fail fast rather than silently reverting to live reads).
- A
disabledTools change landing mid-request cannot change validation behavior for the in-flight request; it takes effect for the next request. Each API-request attempt captures its own snapshot of the configuration-derived inputs disabledTools, experiments, and customModes, retries included, so a settings change landing mid-request can affect a later retry attempt, but never the one in flight. The request's modelInfo is the deliberate exception: it is resolved once per request, and each attempt of that request publishes a snapshot carrying that same resolution and builds its prompt from it, so validation and prompt can never contradict each other about the model, and re-resolving the model mid-request is out of scope for this issue.
- Tests cover both directions with a mid-stream settings mutation: rejecting a tool the prompt advertised, and accepting a tool the prompt omitted. These tests belong at the
src unit/integration layer (the presentation-chain tests under src/core/assistant-message); no VS Code extension-host end-to-end test is required.
Problem
The system prompt for a request is generated once, from the settings at that moment, when the request is built (
getSystemPromptis awaited once insrc/core/task/Task.ts). Tool-call validation during the streaming response does not reuse that moment: for every tool call it re-reads current settings. Insrc/core/assistant-message/presentAssistantMessage.ts, each tool call fetches fresh state inside thetool_usecase ofpresentAssistantMessage(const state = await cline.providerRef.deref()?.getState()atpresentAssistantMessage.ts:347), destructuresdisabledToolsfrom it (presentAssistantMessage.ts:348), and converts it into the validation requirements passed tovalidateToolUse.Observed in version v3.82.1
Consequence
Generating once and validating live makes the two moments diverge whenever settings change mid-request. If
disabledToolsgains an entry after the prompt was built, validation rejects a tool the prompt advertised, and the model gets a rejection for following its instructions. If an entry is removed mid-request, validation accepts a tool the prompt never advertised. Either way the effective tool policy differs between the prompt and the validator within a single request.Desired behavior
Runtime validation during an in-flight request should consume the same policy snapshot the prompt for that request was generated from. This is a new property: on version v3.82.1 both layers read live state, and no request-scoped snapshot exists to share.
For this issue, the request's policy snapshot is exactly the set of inputs the request's tool validation consumes:
disabledTools,experiments,customModes, and the request'smodelInfo(the source of the model's excluded and included tools). Validation must consume that snapshot rather than re-read live settings.Acceptance criteria
disabledToolschange landing mid-request cannot change validation behavior for the in-flight request; it takes effect for the next request. Each API-request attempt captures its own snapshot of the configuration-derived inputsdisabledTools,experiments, andcustomModes, retries included, so a settings change landing mid-request can affect a later retry attempt, but never the one in flight. The request'smodelInfois the deliberate exception: it is resolved once per request, and each attempt of that request publishes a snapshot carrying that same resolution and builds its prompt from it, so validation and prompt can never contradict each other about the model, and re-resolving the model mid-request is out of scope for this issue.srcunit/integration layer (the presentation-chain tests undersrc/core/assistant-message); no VS Code extension-host end-to-end test is required.