Skip to content

feat: deliver mid-turn user messages with the next tool result - #23

Open
karimodm wants to merge 1 commit into
openchamber:mainfrom
karimodm:feat/mid-turn-steering
Open

karimodm wants to merge 1 commit into
openchamber:mainfrom
karimodm:feat/mid-turn-steering

Conversation

@karimodm

Copy link
Copy Markdown

In OpenCode you can send a message while the model is working. On claude-code/* models those messages are silently lost whenever a tool is running.

OpenCode puts a queued user message after the tool results in the next request. The proxy resumes the parked bridge using only the tool results, so the user message never reaches Claude. OpenCode still marks it as delivered, so the user thinks the model saw it. (A message sent while Claude is only generating text already works, because OpenCode starts a new turn for it.)

Fix: in the resume branch, collectSteeringText() gathers the text of the user messages that come after the last tool message. withSteering() appends that text inside a <system-reminder> to the last tool result resolved in this request. Claude gets it as part of that tool result and can adjust right away. A later request has newer tool messages after the steer, so the same text is never delivered twice.

We have run this locally with a real Claude Code CLI. A steer sent during sleep 40 ("the secret word is PINEAPPLE") was ignored before the patch and used after it. In a run with three tool calls, it was delivered exactly once.

Limits: text only (images in a queued message are not forwarded), and the message arrives when the current tool finishes, not mid-tool.

Test: test/steering-regression.ts unit-tests collectSteeringText. It also parks a mock turn on bash, resumes with a tool result plus a trailing user message, and checks the tool result Claude receives contains the steer. A resume without a trailing message gets the plain result. On main the steer is missing and the test fails. bun test/smoke.ts and tsc --noEmit pass.

A message the user sends while a bridged tool runs arrives after the
tool results in OpenCode's resume request. The parked bridge only
consumed tool results, so the message was dropped and OpenCode then
treated it as answered. Append its text to the last tool result
resolved in that request, inside a system-reminder, so Claude reads it
exactly once.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant