Skip to content

(feat) Warm sessions should hold client tool calls open instead of replaying the turn #5384

Description

@mmabrouk

The problem, from the user's side

You are in the playground on a warm agent session (you have already sent a few turns, so the agent's process is live). The agent calls a browser-fulfilled client tool, so a widget appears and you fill it in. When you submit your answer, the agent does not simply pick up where it left off. It re-runs its whole turn from the start before continuing: you see it pause with a "waiting for the user" message, and on resume it visibly restarts its reasoning and replays the conversation to get back to the point where you answered.

That costs you two things. Latency, because the whole turn is replayed instead of resumed. And tokens, because the replay re-sends the conversation and the model re-reasons. On a warm session none of that should be necessary. The agent is still running and could just wait for your answer, the way it already does for an approval prompt.

Current behavior

Client tools take the cold path everywhere, including warm sessions. When the tool parks, the runner writes a synthetic paused result to end the harness's tool call, the turn ends, and the answer is delivered on a fresh turn that replays the stored history (cold replay) to reach the paused point again. This is correct and necessary for a genuinely cold session, which has no live process to hold anything open. It is wasteful on a warm one.

Research (verbatim from the design-record on #5383)

the message-plus-replay pattern is the cold-path contract, inherited from the Pi relay model, and it must exist regardless because a cold session has no process to hold anything open. The native hold is real and already exists in this codebase for approvals on warm sessions (the ACP permission request stays pending inside the live turn). Client tools do not get it yet because the relay has no turn-boundary model (open issue S5.2), the frontend answers by posting a new request rather than into an open turn, and a blocking MCP call faces Claude Code's client timeout (escape hatch identified: MCP progress notifications reset that timeout).

Proposed direction

Give client tools on a warm session the native hold that approvals already have: keep the harness's tool call open inside the live turn and settle it in place when the user answers, instead of ending the turn and replaying. This couples to two existing threads:

  • the relay turn-boundary model (open issue S5.2 in docs/design/agent-workflows/scratch/open-issues.md), which the relay needs before it can hold a call open rather than fire-and-forget, and
  • the pending-interaction-records direction, so the live turn knows which interaction it is waiting on and can resume it in place.

The escape hatch for the blocking-MCP-call timeout is already identified: MCP progress notifications reset Claude Code's client timeout while the call is held.

The implementation shipped in #5383 is shaped for this without building it. The client-tool pause disposition is a closed set (ClientToolPauseDisposition) with a reserved warm-hold member and an exhaustive mapping, so adding the warm hold is a local change at the client-tool boundary rather than a rework. No warm-hold behavior exists yet.

Links

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions