Skip to content

fix(providers): replay DeepSeek reasoning for opencode-zen (#994) - #1068

Merged
Wibias merged 2 commits into
lidge-jun:devfrom
justjxke:fix/opencode-zen-reasoning-replay
Aug 6, 2026
Merged

fix(providers): replay DeepSeek reasoning for opencode-zen (#994)#1068
Wibias merged 2 commits into
lidge-jun:devfrom
justjxke:fix/opencode-zen-reasoning-replay

Conversation

@justjxke

@justjxke justjxke commented Aug 5, 2026

Copy link
Copy Markdown

Summary

  • opencode-zen was the only OpenCode provider missing DeepSeek reasoning metadata. The fix(responses): keep DeepSeek reasoning_content on tool-call continuations (#950) #971 replay fix only fires for models in preserveReasoningContentModels, and opencode-zen declared none — so opencode-zen/deepseek-v4-flash-free tool-call continuations went upstream without the original reasoning_content, and the gateway rejected them with HTTP 400.
  • Mirrors the DeepSeek thinking metadata (preserveReasoningContentModels, reasoning-effort map, noVisionModels) that opencode-go and opencode-free already carry onto opencode-zen, covering deepseek-v4-pro, deepseek-v4-flash, and deepseek-v4-flash-free.

Verification

  • bun run typecheck — pass
  • bun test tests/opencode-zen-deepseek-reasoning.test.ts — pass (regression; red before fix, green after; also asserts effort mapping and that non-listed models are untouched)
  • bun test tests/provider-registry-parity.test.ts tests/opencode-go-deepseek.test.ts tests/reasoning-effort.test.ts tests/deepseek-reasoning-replay.test.ts — pass
  • bun run test — 9018 pass, 0 fail
  • bun run privacy:scan — pass

Checklist

  • Scope stays focused and avoids unrelated cleanup.
  • Docs or release notes were updated when needed.
  • Security-sensitive changes were reviewed for secrets, auth, and unsafe defaults.

Related

  • #950 — original report: intermittent drop of reasoning_content on tool-call continuation for DeepSeek thinking mode
  • #971 — the replay fix that covered opencode-go / opencode-free but not opencode-zen
  • #994 — regression this PR closes (same 400 via opencode-zen)

Review readiness checklist

This PR stays in draft until every box below is ticked. Tick all four boxes once the requirements are met:

  • All CI tests are green on my local testing.

  • I pushed my PR to the latest dev commit.

  • I resolved all correct Codex and CodeRabbit findings.

  • My PR is ready for review.

Summary by CodeRabbit

Summary by CodeRabbit

  • New Features

    • Added support for OpenCode Zen DeepSeek models with configurable reasoning levels, including xhigh mapped to the maximum level.
    • Added support for DeepSeek V4 and its free Flash variant.
  • Bug Fixes

    • Preserved reasoning content across tool-call continuations for more consistent multi-step responses.
    • Improved tool-call handling for DeepSeek conversations.
    • Correctly routes DeepSeek models as text-only when image input is used.

@github-actions github-actions Bot added the bug Something isn't working label Aug 5, 2026
@github-actions
github-actions Bot marked this pull request as draft August 5, 2026 16:44
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown

Deterministic PR hygiene checks passed.

@coderabbitai

coderabbitai Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@github-actions[bot], you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 04e9734b-18bf-4db6-bb77-788431c9a21c

📥 Commits

Reviewing files that changed from the base of the PR and between e50f580 and 957990a.

📒 Files selected for processing (2)
  • src/providers/registry.ts
  • tests/opencode-zen-deepseek-reasoning.test.ts
📝 Walkthrough

Walkthrough

The opencode-zen registry adds DeepSeek reasoning mappings, continuation replay configuration, and vision-routing metadata. Integration tests validate request construction, tool-call serialization, reasoning replay, and model routing.

Changes

OpenCode Zen DeepSeek reasoning support

Layer / File(s) Summary
DeepSeek registry metadata and adapter validation
src/providers/registry.ts, tests/opencode-zen-deepseek-reasoning.test.ts
The registry adds DeepSeek reasoning-effort mappings, preserves reasoning_content during tool-call continuations, and marks DeepSeek models as lacking native vision support. Tests validate xhigh to max mapping, reasoning replay, tool-call serialization, and non-DeepSeek routing.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: ingwannu, wibias

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the DeepSeek reasoning replay fix for the opencode-zen provider, which matches the primary change.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/opencode-zen-deepseek-reasoning.test.ts`:
- Around line 75-80: Add focused image-request regression coverage near the
existing tests in tests/opencode-zen-deepseek-reasoning.test.ts for
deepseek-v4-pro, deepseek-v4-flash, and deepseek-v4-flash-free. Exercise the
noVisionModels configuration from the provider registry and assert each model
follows its expected no-vision or vision-sidecar path, while preserving the
existing reasoning replay tests.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 97e90f8b-4585-4bad-8c33-eb36766bf9fa

📥 Commits

Reviewing files that changed from the base of the PR and between 0e92714 and 391bae1.

📒 Files selected for processing (2)
  • src/providers/registry.ts
  • tests/opencode-zen-deepseek-reasoning.test.ts

Comment thread tests/opencode-zen-deepseek-reasoning.test.ts
@justjxke
justjxke marked this pull request as ready for review August 5, 2026 16:55
@lidge-jun

Copy link
Copy Markdown
Owner

The registry slice looks right: the missing opencode-zen metadata is exactly what breaks reasoning replay there, and the focused tests cover it. Two things before this can land: (1) the branch is currently conflicting with dev — please rebase; (2) the tests exercise a synthesized adapter context only — an end-to-end regression for a real Claude Messages continuation (thinking block replayed on the second request) would prove the fix where users hit it. Note #994 stays open either way: the Claude /v1/messages replay path dropping thinking is a separate gap from the Zen registry fix.

@lidge-jun

Copy link
Copy Markdown
Owner

The replay bug you are fixing is real, and the diagnosis is right. opencode-zen reaches the same opencode.ai/zen/v1 gateway as opencode-free but carries no preserveReasoningContentModels, so a DeepSeek thinking turn serializes a bare tool-call continuation and the gateway answers 400. Your regression test builds a real translated continuation and would fail without the metadata — that is a genuine test, not a restatement.

There is one line I have to block on, and it is easy to miss because it looks like an addition rather than a deletion.

noVisionModels is replaced, not extended. On dev:

// #1043: without this the proxy forwards image parts to text-only Zen models and
// the upstream rejects the whole request with a 400.
noVisionModels: OPENCODE_ZEN_TEXT_ONLY_MODELS,

Your diff sets noVisionModels: [...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS]. I diffed the two sets:

dev list:  big-pickle, nemotron-3-ultra-free, ling-3.0-flash-free,
           north-mini-code-free, laguna-s-2.1-free, deepseek-v4-flash-free
your list: deepseek-v4-pro, deepseek-v4-flash, deepseek-v4-flash-free

lost:      big-pickle, nemotron-3-ultra-free, ling-3.0-flash-free,
           north-mini-code-free, laguna-s-2.1-free

Five models stop being marked text-only, so the proxy resumes forwarding image parts to them and the gateway 400s the whole request. That is #1043 reopening. The list is not a guess either — it came out of a modality probe recorded in devlog/_plan/260805_bug_fix_stack/002_zen_modality_probe.md, and deepseek-v4-flash-free overlapping both sets is probably what made the replacement look safe.

Fix is a one-liner: union the two rather than replace.

noVisionModels: [
  ...OPENCODE_ZEN_TEXT_ONLY_MODELS,
  ...DEEPSEEK_THINKING_MODELS,
  ...OPENCODE_FREE_DEEPSEEK_MODELS,
],

Your new test asserting minimax-m2.7 stays out of noVisionModels still passes under that union, and it would be worth adding big-pickle to the positive cases so a future replacement fails loudly.

Second item: the effort constants moved under you. The branch uses generic DeepSeek effort constants, but v2.10.2 split them per model for #1057 — Flash and Pro now advertise different ladders and map differently (src/providers/registry.ts:380-434). Please rebase and use deepseekThinkingEffortsFor / deepseekReasoningMapFor instead of a single shared array, otherwise the entry either conflicts on rebase or advertises a tier the model does not honor.

On the failing check: the enforce-target failure is not a verdict on your diff. It is a repository-side gate artifact — a stale head's workflow YAML calling into base-pinned scripts. An earlier draft of my review was going to tell you the failure was substantive; that was wrong and I would rather say so than let you spend an evening on it. Rebase onto current dev and it clears on its own.

So: keep the replay metadata and the test, union the vision list, rebase for the per-model effort helpers. The replay half of this is work we want, and #994 is waiting on it.

@Wibias
Wibias force-pushed the fix/opencode-zen-reasoning-replay branch from f377088 to ac63b73 Compare August 6, 2026 09:34
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@github-actions

github-actions Bot commented Aug 6, 2026

Copy link
Copy Markdown

✅ READY

  • all PR quality gates passed; the review readiness checklist is complete.

Review readiness checklist

  • ✅ All CI tests are green on my local testing.
  • ✅ I pushed my PR to the latest dev commit.
  • ✅ I resolved all correct Codex and CodeRabbit findings.
  • ✅ My PR is ready for review.

4/4 boxes ticked.

This pull request is already Ready for Review.
CodeRabbit/Codex review was requested via the review-ready label. If no review appears, comment @coderabbitai review to request one.
Maintainers: @lidge-jun @Ingwannu @Wibias

@github-actions
github-actions Bot marked this pull request as draft August 6, 2026 09:34

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/opencode-zen-deepseek-reasoning.test.ts`:
- Around line 82-95: Add a positive test alongside the existing noVisionModels
coverage using routeModel(configFor("big-pickle"), "opencode-zen/big-pickle"),
and assert that the resulting provider.noVisionModels contains "big-pickle".
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b6d1f07b-e32a-422d-a4af-2f6b09c0c376

📥 Commits

Reviewing files that changed from the base of the PR and between a5b3782 and ac63b73.

📒 Files selected for processing (2)
  • src/providers/registry.ts
  • tests/opencode-zen-deepseek-reasoning.test.ts

Comment thread tests/opencode-zen-deepseek-reasoning.test.ts
@Wibias
Wibias force-pushed the fix/opencode-zen-reasoning-replay branch 2 times, most recently from 8efa6cd to cb5641d Compare August 6, 2026 10:33
@Wibias
Wibias force-pushed the fix/opencode-zen-reasoning-replay branch from cb5641d to 957990a Compare August 6, 2026 10:36
@github-actions
github-actions Bot marked this pull request as ready for review August 6, 2026 10:39
@Wibias

Wibias commented Aug 6, 2026

Copy link
Copy Markdown
Collaborator

[GD] Verdict: gated

TLDR

  • PR: fix(providers): replay DeepSeek reasoning for opencode-zen (#994) #1068 — fix(providers): replay DeepSeek reasoning for opencode-zen (The request couldn’t be completed. #994)
  • Head: 957990a on dev (�50f58057; mergeStateStatus: UNSTABLE, mergeable: MERGEABLE)
  • Decision: useful and correct; gated on the draft state — the PR is a GitHub draft (auto-drafted by the opencodex-pr-gate bot on the new head), so no merge-ready claim is made. Owner action: tick the readiness checklist / mark ready for review when the remaining ask is done.
  • Usefulness: fixes a real bug — opencode-zen reaches the same opencode.ai/zen/v1 gateway as opencode-free but carried no preserveReasoningContentModels, so DeepSeek thinking turns serialized a bare tool-call continuation and the gateway answered HTTP 400 (The request couldn’t be completed. #994, same class as [Bug] OpenCode Go DeepSeek V4 Flash intermittently drops reasoning_content on tool-call continuation #950). The regression test builds a real translated continuation and fails without the metadata.
  • Bugs: none blocking on the reviewed head. Two rebase-drift issues were found and fixed in this session (see full verdict).
  • Security: none — registry metadata only; no credential, auth, or input-handling surface changed. privacy:scan passed.
  • Spec / standards: clean against the maintainer's explicit contract; both maintainer asks that involve code were implemented.
  • Reviews: lidge-jun's two comments: (1) rebase — done; (2) vision-list union + per-model effort helpers + �ig-pickle positive test — all implemented on this head. CodeRabbit: 1 open thread (the �ig-pickle ask) — verified addressed on this head and resolved. 1 earlier thread already resolved by the author.
  • Base / CI: rebased onto dev@e50f58057 in 957990a; mergeable, no conflicts. Local typecheck + privacy scan + 97 focused tests green. Required CI running on this head ( est 1-4/4, gates, keyring windows,
    pm-global pending;
    eact-doctor/changes/keyring passing).
  • Gate: draft (GitHub isDraft: true) — gated.
  • Owner actions (foreign PR): (1) add the maintainer-requested end-to-end regression for a real Claude /v1/messages continuation (thinking block replayed on the second request) — the synthesized-adapter tests do not cover that path; (2) when ready, tick the readiness checklist so the gate bot clears the draft. Optional simplify candidates are listed in the full verdict.
  • Bottom line: the fix is sound and the requested code changes are landed. This is a draft-gated verdict — the PR cannot be merge-ready until the draft is cleared and the owner adds the e2e test the maintainer asked for.
Full verdict

Semantic propagation

  • Concepts audited: DeepSeek reasoning metadata on the opencode-zen registry entry — modelReasoningEfforts, modelReasoningEffortMap, preserveReasoningContentModels,
    oVisionModels — and their interaction with the shared DeepSeek V4 ladder helpers and the Zen text-only list.
  • Authoritative sources: src/providers/registry.ts (the provider registry), ests/opencode-zen-deepseek-reasoning.test.ts (PR regression), ests/provider-registry-parity.test.ts (base parity contract), and the live routed-adapter behavior on the rebased head.
  • Producers and consumers checked:
    outeModel → createOpenAIChatAdapter buildRequest path; opencode-go / opencode-free as sibling providers carrying the same metadata; the vision sidecar behavior exercised by ests/vision-sidecar-e2e.test.ts.
  • Public/derived representations checked: the wire
    easoning_effort value and
    oVisionModels routing for all three Zen DeepSeek models plus the measured free-only set.
  • Material variant partitions checked: Flash vs Pro effort ladder (Flash: xhigh -> high; Pro: xhigh -> max, per Align DeepSeek reasoning levels with official low/high/max ladder #1057), and no-vision set membership for deepseek-v4-flash-free (in both base lists), deepseek-v4-pro/deepseek-v4-flash (PR additions), and minimax-m2.7/�ig-pickle (positive/negative coverage).
  • Positive and negative assertions checked: replay of
    easoning_content; �ig-pickle stays in
    oVisionModels; minimax-m2.7 stays out; parity test's measured text-only / vision-capable lists.
  • Unmapped surfaces: none — the changed concepts are contained to the registry entry and its direct consumers.
  • Unproven equivalence assumptions: none — sibling-provider equivalence was verified by running the actual routed adapter for opencode-go/opencode-free/opencode-zen on this head.
  • Representation mismatches: one found and fixed this session (the effort-map test asserted Flash xhigh -> max, which contradicts the current Align DeepSeek reasoning levels with official low/high/max ladder #1057 ladder; aligned to high). One base/PR conflict found and fixed (Zen
    oVisionModels must be the union, not a replacement).
  • Variant coverage gaps: the maintainer-requested e2e Claude /v1/messages continuation test is not present.
  • Axis verdict: pass (with the noted e2e coverage gap carried as an owner action).

Linked: #994 (this PR's issue), #950/#971 (replay history), #1043 (Zen text-only list), #1057 (per-model DeepSeek ladder).

Usefulness

Real, user-visible bug. opencode-zen is the same gateway as opencode-free but lacked the DeepSeek reasoning metadata, so a tool-call continuation in DeepSeek thinking mode dropped
easoning_content and the gateway answered HTTP 400. The fix mirrors the metadata that opencode-go/opencode-free already carry. The regression test is a genuine translated-continuation test that fails without the metadata — confirmed.

Bugs / correctness

  • Method: static review of the registry diff + routed-adapter verification on the rebased head (no Bugbot; Cursor bug axis n/a here — this is a registry-metadata change; complementary lenses: silent_failures, �dge_cases, �pi_compatibility).
  • Findings: none blocking on the current head.
  • Fixed this session (rebase-drift corrections on the PR head, committed and pushed):

oVisionModels replaced the base OPENCODE_ZEN_TEXT_ONLY_MODELS with only the DeepSeek set — this would have reopened #1043 (five measured text-only models lose image stripping). Corrected to the union [...OPENCODE_ZEN_TEXT_ONLY_MODELS, ...DEEPSEEK_THINKING_MODELS].

Security

  • Scope reviewed: registry metadata only — no auth, credential, SSRF, injection, or input-handling surface. privacy:scan passed on the head.
  • Findings: none.
  • Fixed this session: none.

Spec / standards

  • Spec source: PR body + maintainer comments (lidge-jun 01:52Z and 09:13Z) + linked issue The request couldn’t be completed. #994.
  • Gaps: none in the code the maintainer asked for; the only open item is the requested e2e Claude /v1/messages continuation test (owner action).

Reviews

  • Owners/maintainers: lidge-jun 01:52Z (rebase + e2e test) — rebase done, e2e test open (owner action). lidge-jun 09:13Z (vision union + per-model effort helpers + �ig-pickle test) — all implemented on 957990a.
  • Bots (CodeRabbit): thread PRRT_kwDOS-0Gi86W737X (add �ig-pickle positive coverage) — verified addressed on this head, replied in-thread with evidence, and resolved. Earlier thread already resolved by the author.

Base / CI

  • Behind/conflicts: clean — rebased onto dev@e50f58057; mergeable, no conflicts.
  • Required checks: running on 957990a — �nforce-target, hygiene, label,
    eact-doctor, changes, keyring pass; est 1-4/4, gates, keyring windows,
    pm-global pending. CodeRabbit skipped (draft).
  • Local tip compile/tests: �un run typecheck pass; �un run privacy:scan pass; focused suite �un test tests/opencode-zen-deepseek-reasoning.test.ts tests/provider-registry-parity.test.ts tests/opencode-go-deepseek.test.ts tests/reasoning-effort.test.ts tests/deepseek-reasoning-replay.test.ts tests/vision-sidecar-e2e.test.ts → 97 pass / 0 fail.

Simplification (for the PR owner)

Simplify was explicitly requested, but this PR is foreign, so nothing was edited or pushed beyond the rebase/fix commits above. Bounded candidates for the owner to consider (optional; not blockers):

  1. ests/opencode-zen-deepseek-reasoning.test.ts — �uildToolCallBody and the two est.each blocks repeat the same three-model array ["deepseek-v4-flash-free", "deepseek-v4-flash", "deepseek-v4-pro"]. A single shared const ZEN_DEEPSEEK_MODELS = [...] at the top of the file removes the triplication (risk: low; validation: existing tests still pass).
  2. src/providers/registry.ts — the opencode-zen block builds modelReasoningEfforts/modelReasoningEffortMap/preserveReasoningContentModels/
    oVisionModels from the same [...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS] base four times. A local const ZEN_DEEPSEEK_MODELS = [...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS] (with
    oVisionModels still adding OPENCODE_ZEN_TEXT_ONLY_MODELS) reduces repetition without changing behavior (risk: low; validation: registry-parity + reasoning tests).
  3. ests/opencode-zen-deepseek-reasoning.test.ts — the two
    oVisionModels est.each blocks and the �ig-pickle case could collapse into one table covering both positive and negative memberships, but the current split (DeepSeek additions vs measured free-only) documents intent; only merge if the owner prefers a single table.

Gate

Draft (GitHub isDraft: true, set by the opencodex-pr-gate bot on the new head). Not WIP/do-not-merge by title or label. Ship-gate result: �locked —
eviewPolicy:draft and wake:trusted_human_feedback_needs_code (both maintainer comments; one is addressed by code, the e2e-test ask remains).

Bottom line

The fix is useful, correct, and now rebased with all maintainer-requested code changes landed and verified (union vision list, per-model effort helpers, �ig-pickle coverage). The PR is draft-gated: it cannot be merge-ready until the owner (1) adds the end-to-end Claude /v1/messages continuation regression the maintainer asked for, and (2) clears the draft via the readiness checklist. No security or spec blockers.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

@github-actions[bot] The review-readiness checklist is complete. I will review the current pull request head.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== PR metadata =="
gh pr view 1068 --repo lidge-jun/opencodex --json headRefOid,isDraft,mergeStateStatus,statusCheckRollup \
  --jq '{headRefOid, isDraft, mergeStateStatus, checks: [.statusCheckRollup[] | {name, conclusion, status}]}'

echo
echo "== Candidate test files =="
fd -t f . tests | rg '(claude|messages|reasoning|replay|zen).*\.test\.(ts|tsx)$' || true

echo
echo "== Test structure =="
for f in tests/opencode-zen-deepseek-reasoning.test.ts tests/deepseek-reasoning-replay.test.ts; do
  if [ -f "$f" ]; then
    echo "--- $f ---"
    ast-grep outline "$f" --items all --type function --view expanded || true
  fi
done

echo
echo "== Claude Messages continuation / thinking replay references =="
rg -n -i -C 3 '(\/v1\/messages|claude.*continuation|continuation.*claude|thinking.*replay|replay.*thinking)' tests src || true

Length of output: 65653


@github-actions[bot] The PR is ready for a review pass. I found two items that the checklist does not currently prove:

  • Several CI jobs are still in progress at 957990a91cbb1694a11bf40d8689a26cba38e33a: test 1/4 through test 4/4, macos, keyring windows, and npm-global windows-latest.
  • The requested end-to-end Claude /v1/messages continuation test is not present. The current tests validate the OpenAI-compatible translated continuation. They do not send a real Claude Messages request, capture the second upstream request, and assert that the preceding thinking block is replayed with the tool call.

src/claude/inbound.ts also documents that the current v1 inbound policy drops thinking and redacted_thinking blocks. Therefore, the requested Claude Messages replay scenario remains a separate coverage and behavior gap.

I will review the current ready-for-review head.

⚠️ Action not completed

Review rate limited.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@Wibias
Wibias merged commit 7d0c02d into lidge-jun:dev Aug 6, 2026
24 of 26 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 957990a91c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment thread src/providers/registry.ts
Comment on lines +1911 to +1914
[...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS].map(id => [id, deepseekThinkingEffortsFor(id)]),
),
modelReasoningEffortMap: Object.fromEntries(
[...DEEPSEEK_THINKING_MODELS, ...OPENCODE_FREE_DEEPSEEK_MODELS].map(id => [id, deepseekReasoningMapFor(id)]),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add opencode-zen to the DeepSeek parity matrix

These new opencode-zen calls to deepseekThinkingEffortsFor / deepseekReasoningMapFor put three more model ids under the shared Flash-vs-Pro substring classifier, but tests/provider-registry-parity.test.ts’s “every DeepSeek V4 entry…” matrix still omits this provider. That matrix is the existing guard for every registry id that uses the classifier; without the Zen cases, a future Zen-specific id typo/name change could be mis-advertised without failing the parity test, so please add the three opencode-zen models there.

AGENTS.md reference: src/AGENTS.md:L22-L26

Useful? React with 👍 / 👎.

@justjxke
justjxke deleted the fix/opencode-zen-reasoning-replay branch August 6, 2026 10:50
lidge-jun added a commit that referenced this pull request Aug 6, 2026
Second loop of the bug campaign, scoped to author corrected replacements for
four contributor PRs and close theirs as absorbed. Three adversarial audit
rounds refuted the premise, and the plan now records that instead of the
outcome it was written to produce.

The decisive finding: I judged "has the author responded to our review" by
`updatedAt`, which moves when WE comment and therefore can never show author
activity. Comparing last-commit time against review time gives the real
picture:

    #1092  commits 09:38:19Z  review 09:09:51Z  -> acted, in under 30 minutes
    #1068  commits 08:52:23Z  review 09:13:15Z  -> predates the review
    #1036  commits 08-05      review 09:12:51Z  -> no response yet
    #997   commits 02:51Z     review 09:16:02Z  -> no response yet

Under the wrong reading I was about to close #1092 as absorbed — taking
credit for work its author did in direct response to my own request — and to
credit #1068 with agreeing to a review it had not yet read. Neither is a
process nit; both would have been visible to the contributor.

So the plan changes shape. #1092 and #1068 become re-reviews. #1036 and #997
get a stated 72-hour response window with a mandatory head re-check before
anything is authored or closed; "has not replied within an hour" is not
abandonment, and #997's author was active at 02:51Z. This loop therefore
authors no absorbed layer at all, and says so.

#1068's re-review carries a finding neither side has: its new test asserts
all three DeepSeek ids are in `noVisionModels`, but routing merges the
registry list, which holds only the `-free` one. Reproduced with the test's
own routeModel config — Pro=false, Flash=false, Flash-free=true — so two of
three cases fail. Latent because no check currently runs that suite.

Also corrected: the layers were called dependency-ordered when they share no
files, so s3/s4 are independent heads off `origin/dev` and the
`--update-refs` cascade is reserved for genuine chains; and #978's exclusion
no longer claims it is "already correct" when it needs an author-side docs
change.

Terminal outcome is deferred, not DONE. Shrinking the criteria to match what
finished would have hidden exactly the thing worth recording.
@lidge-jun

Copy link
Copy Markdown
Owner

Re-reviewed your current head (ac63b73a5). Two things, and the second one I would want to know about if it were my branch.

First, an apology for the last review's framing. I told you the enforce-target failure was substantive. It is not — it is a repository-side gate artifact where a stale head's workflow YAML calls into base-pinned scripts, the same thing hitting #978. That was our bug to explain, not yours to chase.

Second: the new noVisionModels test cannot pass as written.

test.each(["deepseek-v4-flash-free", "deepseek-v4-flash", "deepseek-v4-pro"])(
  "%s is listed in opencode-zen noVisionModels for the vision sidecar",
  modelId => {
    const route = routeModel(configFor(modelId), `opencode-zen/${modelId}`);
    expect(route.provider.noVisionModels).toContain(modelId);
  },
);

The entry keeps noVisionModels: OPENCODE_ZEN_TEXT_ONLY_MODELS, which is the right call and exactly what I asked for. But that list holds only deepseek-v4-flash-free of the three ids you parameterize, and routing merges the registry list (src/router.ts:254-282). I ran your own routeModel configuration locally:

deepseek-v4-flash-free: inNoVision=true
deepseek-v4-flash:      inNoVision=false
deepseek-v4-pro:        inNoVision=false

So two of the three cases fail. It has not surfaced because no check currently runs that suite on this PR — which is why I am telling you rather than letting CI do it later.

The underlying question is genuinely open, and it is not one I can answer for you. OPENCODE_ZEN_TEXT_ONLY_MODELS is a dated exception list from a single live probe on 2026-08-05, and Zen exposes no modality metadata, so nobody has measured whether deepseek-v4-pro and deepseek-v4-flash accept images through that gateway. Two honest ways forward:

  • Narrow the test to deepseek-v4-flash-free and note that the other two are unmeasured. Smallest change, ships the replay fix now.
  • Probe Pro and Flash against Zen with a text control then an image, the same method that produced the existing list, and if they reject images add them to OPENCODE_ZEN_TEXT_ONLY_MODELS with the evidence. Then the test passes as written and the list gets better.

Either is fine by me. The first unblocks you today; the second is more valuable and you have the Zen access to do it properly.

The replay half — mirroring preserveReasoningContentModels and the per-model ladders from opencode-free onto opencode-zen — is right, and it is what #994 has been waiting on. Nice catch that the two providers share a gateway.

@lidge-jun

Copy link
Copy Markdown
Owner

Correction — my previous comment was stale, and the merged result is right.

I posted that eight minutes after this merged, against the head I had fetched earlier, and it does not describe what actually landed. The merged entry is:

noVisionModels: [...OPENCODE_ZEN_TEXT_ONLY_MODELS, ...DEEPSEEK_THINKING_MODELS],

That is a union, which is exactly what the review asked for and what I claimed was missing. I ran the merged suite against current dev: 9 pass, 0 fail, including the three-id noVisionModels cases and the "Zen text-only free models (measured #1043) stay in noVisionModels" test that pins the original list.

So both of my objections are resolved in the merged code: the six probed text-only models keep their guard, and the DeepSeek thinking models are added rather than substituted. Whoever tightened it before merge got it right.

What remains true and worth carrying forward: whether deepseek-v4-pro and deepseek-v4-flash actually reject images through Zen is still unmeasured — they are now guarded on the safe assumption. That is the correct default (a stripped image degrades to a caption; an unguarded one 400s the whole request), so this is a note for the record rather than a defect.

Apologies for the noise. The lesson on my side is not subtle: I read a head, wrote a finding, and posted it after the PR had moved. Re-fetching before commenting is cheap and I did not do it.

Thanks for the fix — #994 has been waiting on the replay half, and the shared-gateway insight between opencode-zen and opencode-free is what unlocked it.

lidge-jun added a commit that referenced this pull request Aug 6, 2026
Records what the stack-and-absorb campaign actually produced once live data
replaced its assumptions.

#1068 merged at 10:45:57Z while I was writing its review, and the merged code
is not what I reviewed: `noVisionModels: [...OPENCODE_ZEN_TEXT_ONLY_MODELS,
...DEEPSEEK_THINKING_MODELS]` — the union the review asked for. Running the
merged suite against `origin/dev` gives 9 pass / 0 fail, including a new test
pinning the six probed text-only models. My 10:53Z comment claiming a failing
test was true of the head I had fetched and false of what landed, so it got a
public correction eight minutes later.

That is the second process error in this unit, and both are now written down
rather than quietly fixed. First: judging author activity by `updatedAt`,
which moves when WE comment. Second: commenting against a stale fetched head.
Each produced a wrong public statement to a contributor. The rules are
re-fetch immediately before commenting, and compare last-commit time against
review time.

#1092's author restored the fail-closed guard within 30 minutes of the
review, with a comment keeping `unknown` distinct in debug. Credited
explicitly; asked only to split the unrelated `imageInput` scope.

#1036 and #997 are deferred, not absorbed. Their last commits (08-05 07:18Z,
08-06 02:51Z) predate our reviews and neither carries the requested change,
but roughly two hours have passed and #997's author was active that morning.
050 states a 72-hour response window with a mandatory head re-check before
anything is authored or closed. The window exists because this unit
demonstrated the alternative: two of four absorb targets were being actively
fixed by their authors while we drafted replacements.

#994 updated with the dev-only landing (merge 7d0c02d, ancestor of
`origin/dev`) and deliberately left open pending the reporter's provider
confirmation and a release.

Zero contributor PRs closed by this loop.
lidge-jun added a commit that referenced this pull request Aug 6, 2026
Two loops circled a problem the campaign had invented. The user named the
answer in one line: their PRs report maintainerCanModify=true, so push our
completion commit onto their branch. Their commits stay, blame stays
accurate, their PR merges, and attribution is the commit graph rather than a
paragraph. No replacement PR, no close, no "absorbed with credit to" prose.

#1036 landed that way. Four Agent59353 commits, then ours on top, pushed
with a lease pinned to their head after re-verifying the remote. The change
is bounded: live-transport records the bare names we actually advertised
this request, the event state carries them, and both translate call sites
convert only for names in that set. Their conversion logic is byte-
unchanged. The stateless fallback passes through, since it has no state to
consult and an unconverted call is recoverable while a wrongly converted one
edits a file — disclosed in the PR comment as a judgment call open to
disagreement. Ablation: restoring the name-only gate gives 21 pass / 1 fail,
red on exactly the new collision test.

#997 was not ours to push. The lease rejected it as stale: the author landed
their own fix mid-flight, and theirs is stronger than what we staged — we
pinned getConfigDir(), they assert the resolved usage.jsonl receives the row
and the default location does not. Verified instead of overwritten, 10 pass
with a 9/1 ablation on their own assertion.

That is the third time in this campaign that acting on a stale head produced
wasted or wrong work: updatedAt as an activity signal, a "failing test"
comment posted eight minutes after #1068 merged with the fix, and a commit
built against a head the author had already improved. The lease caught the
third; the first two reached a contributor as a wrong public statement. The
rule is now written down — re-fetch immediately before preparing a commit,
not before pushing.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working review-ready

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants