Skip to content

fix(opencode): keep mid-conversation system messages in place - #200

Open
salty-flower wants to merge 1 commit into
raine:mainfrom
salty-flower:fix/opencode-system-messages-in-place
Open

salty-flower wants to merge 1 commit into
raine:mainfrom
salty-flower:fix/opencode-system-messages-in-place

Conversation

@salty-flower

Copy link
Copy Markdown
Contributor

Claude Code sessions routed to OpenCode Go now reuse the upstream prompt cache instead of re-reading almost the whole conversation on every request.

Why: Claude Code appends a role: "system" message mid-conversation on most turns (output-style notices, hook context, environment updates). The Chat Completions translator moved each of them into the leading system message → the start of the prompt changed on every request → the upstream prefix cache could only reuse what came before the change. In practice, Claude Code sessions on opencode-go/deepseek-v4.1-flash hit about 8% cache, while the same model called from OpenCode itself hits about 97%. The cached part grew only in 128-token steps, matching the old system string's length, and a near-full hit appeared only after turns that added no system message.

What changes in build_messages:

  • The leading system message carries only the request's system field.
  • Each mid-conversation system or developer message stays at its position as a user message wrapped in <system-reminder> (left as-is if it is already wrapped), so the upstream prompt is append-only.
  • It does not stay a system message: chat templates such as DeepSeek's gather every system message to the front, which would void the cache again.
  • A reminder that lands between an assistant tool call and its results waits until those results are in place, so tool responses stay contiguous.

What to check: whether a user-role reminder is the shape you want for these messages, compared with the Kimi translator, which keeps them as system messages outside K3 mode.

Validation:

  • cargo test: all suites pass (1,141 tests), including two new regressions. One asserts that the translated messages of a later turn start with the earlier turn's messages exactly. The other covers the deferred reminder.
  • cargo fmt --check and cargo clippy --all-targets -- -D warnings are clean.
  • Live check against DeepSeek V4.1 Flash with this message shape (through another OpenAI-compatible gateway, since my OpenCode Go quota is spent): consecutive user messages are accepted, and a request that appends one turn reports cached_tokens 7552 of 7689. I have not run it against OpenCode Go itself yet.

🤖 Generated with Claude Code

Claude Code appends a system message mid-conversation on most turns
(output-style notices, hook context, environment updates). The Chat
Completions translator hoisted each one into the leading system message,
so the start of the prompt changed on every request and the upstream
prefix cache could only reuse the part before it: Claude Code sessions on
OpenCode Go hit about 8% cache, against 97% for the same model from
OpenCode itself.

Each such message now stays at its position as a user message wrapped in
<system-reminder>, so the upstream prompt is append-only. It is not kept
as a system message because chat templates such as DeepSeek's gather
every system message to the front, which would void the cache again. A
reminder that lands between an assistant tool call and its results waits
until those results are in place.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-30T17:52:17.678057Z
We couldn’t complete this review. Comment @codex review to try again.
12175b8 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

This branch has not been deployed

No deployments
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