Skip to content

[Bug]: OCG DeepSeek Chat re-hoists chronological reminders after inbound fix #4161 #4439

Description

@Yongzhaooo

Client or integration

Claude Code (Claude Desktop Code surface)

Area

Provider adapter

Summary

On OpenCode Go's deepseek-v4.1-flash Chat route, appending a chronological Claude system reminder still rewrites the leading outbound system message. The generic Chat serializer collects text-only developer messages into that leading message, undoing the chronological representation introduced by #4161. This changes the reusable prompt prefix even when the existing conversation is unchanged.

This is the Chat-outbound follow-up explicitly left out of scope in #4161, which closed #4148. Proposed narrow fix: #4438.

Reproduction

  1. Use the canonical OpenCode Go destination (https://opencode.ai/zen/go/v1), Chat adapter, and model deepseek-v4.1-flash.

  2. Translate a synthetic Claude request through anthropicToResponsesBodyparseRequestcreateOpenAIChatAdapter(...).buildRequest(...):

    {
      "model": "deepseek-v4.1-flash",
      "system": "Stable project instructions.",
      "max_tokens": 100,
      "messages": [
        {"role": "user", "content": "Inspect the synthetic project."},
        {"role": "assistant", "content": "First result."},
        {"role": "system", "content": "Synthetic reminder A."}
      ]
    }
  3. Append an assistant turn, a user continuation, and another system reminder B; build the second outbound request.

  4. Compare the old-length prefix of the second outbound messages array with the first array. Before the fix, reminder B joins the leading system content and the comparison fails. Expected on this compatible route: the prior serialized messages remain unchanged and the new reminder stays in its chronological position, while pending tool calls/results remain adjacent.

The offline regression in #4438 exercises the actual translation/parser/adapter chain with stabilizePromptCache both false and true. It requires no credentials or model requests. The new suite produced 5 failures on the unmodified base and 15 passes with the patch, including destination/model boundaries and pending-tool behavior.

Version

Observed locally on OpenCodex 2.52.0, Bun 1.4.2. PR base: dcd13b4358befaae0fdca845a8219103943faca0; proposed head: e7bfb08b2823647b09d501692f759193a19d2299.

Operating system

Windows 11, build 26200.

Provider and model

OpenCode Go / deepseek-v4.1-flash, High effort. Live observation includes input growing to 409,130 tokens; it does not validate the full advertised 1M window.

Observed cache behavior

Snapshot through 2026-09-12 22:07:56 UTC, about 2h23m after the local chronological patch became active:

  • Same long-session cohort: 9.17% before (16 measured later requests), 99.05% after (194).
  • Both patched cohorts combined: 99.06% over 202 measured later requests; latest 50: 99.88%; latest 20: 99.92%.
  • Four measured requests were below 90%, retained in those totals. One reset coincided with input shrinking from 214,155 to 36,948 tokens; another followed about 33 minutes without a successful request in that cohort and recovered on the next success. Compaction/cache expiry are possible explanations, not established causes.

Ratios are sum(cached input)/sum(input) from reported upstream usage; input already includes cached tokens. The first successful request per phase/session/effort is excluded as a cold-start approximation, and eligible requests require at least 1,024 input tokens. Failed requests and missing/estimated usage are not counted as cache measurements. The whole patch window contains 218 requests: 204 HTTP 200, 2 client cancellations (499), 12 connection failures (502), and no 400/422. Connection failures are disclosed separately; this issue does not propose a 502 fix.

This is an uncontrolled within-session observation, not a general cache guarantee. The live local endpoint predicate differs from the PR's registry-based predicate, whose boundary is tested offline. The opt-in trailing-notice stabilization setting stayed enabled during the live patch window; the new offline tests cover both setting values.

Related work / duplicate check

Searched open/closed issues and PRs for cache, DeepSeek, system, hoist and chronological terminology. No other PR implementing this specific residual fix was found; #4438 already exists and is reused. It remains draft because broader local test:changed validation is unresolved, as detailed in its body.

Checks

  • I searched existing issues and documentation.
  • I removed secrets, tokens, account details, request credentials, and personal data.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingproviderProvider adapters, OpenAI-compat presets, upstream API quirkstoolstool_calls, MCP, web-search / sidecar tools

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions