Skip to content

fix(deepseek): canonical item-id repair for UUID message/reasoning ids (#938) - #1027

Merged
lidge-jun merged 2 commits into
devfrom
codex/stack-05-uuid-item-ids
Aug 5, 2026
Merged

fix(deepseek): canonical item-id repair for UUID message/reasoning ids (#938)#1027
lidge-jun merged 2 commits into
devfrom
codex/stack-05-uuid-item-ids

Conversation

@lidge-jun

Copy link
Copy Markdown
Owner

Summary

Stack 05 of the bug-stack campaign (devlog/_plan/260805_bug_stack_campaign/060), stacked on #1026. Fixes #938.

DeepSeek's Responses route emits bare UUID item ids, which leave Codex clients stuck on Thinking — the lifecycle never correlates into a committed turn.

  • ResponsesItemIdRepairConfig.repairInvalidIds: existing message/reasoning ids without the canonical msg_/rs_ prefix mint stable, type-scoped canonical ids keyed by output_index. function_call ids and call_id pairing are never rewritten; response.id is untouched (no continuation aliasing).
  • Built-in DeepSeek gets the registry-only policy { repairInvalidIds, repairMissingTerminalIds }, filled fill-only-when-absent on the live route (routedProviderConfig) with cloned arrays — explicit config always wins; the policy never seeds into saved config.
  • The bounded-JSON paths from fix(deepseek): transport-neutral bounded-JSON policy with terminal SSE synthesis (#875) #1026 apply the same client normalization on both the HTTP SSE synthesis and WS reframes (repairResponsesJsonItemIds). Raw continuation snapshots keep upstream ids, so synthetic ids never flow back upstream.
  • Supersedes PR fix DeepSeek Responses UUID item ids for Codex #940 with a narrow reimplementation: its id-prefix idea is equivalent to this fix, but its 15-file/~750-line bundle (response-id aliasing, reasoning envelope synthesis, dropped events, relay surgery) is deliberately excluded — recorded in the 060 doc's equivalence analysis.

Tests

  • tests/deepseek-responses-item-id-repair.test.ts: derive/route fill with explicit-override preservation, stable canonical ids across every lifecycle occurrence, function_call identity byte-identical, canonical ids pass through unchanged, whole-JSON repair, and the live un-enriched-seed path (no UUIDs in the synthesized SSE).
  • Independent review: GO-WITH-FIXES(1) folded (live-route backfill gap — saved configs never got the policy).
  • bun run typecheck 0 errors; bun run privacy:scan pass.
  • Full bun run test on Linux (ssh lidge): 8288 pass / 0 fail.

Provider docs

Five locale files document repairInvalidIds and the DeepSeek default.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

🗂️ Base branches to auto review (2)
  • ^dev$
  • ^preview$

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3aefeeed-6dbf-4a30-8047-e4f8bde1aa2a

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

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

@github-actions github-actions Bot added the bug Something isn't working label Aug 4, 2026

@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: 8403fe695e

ℹ️ 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".

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// #938: WS turns reframe this JSON into events in the bridge — normalize
// ids here so both bounded-JSON paths agree (raw record already happened).
const outboundJson = options.inboundTransport === "websocket"
&& providerModelResponsesUpstreamStreaming(route.providerName, route.provider, route.modelId) === false

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Reuse the saved streaming hint for JSON id repair

In DeepSeek’s bounded-JSON path, route.provider has already been mutated by resolveWireProtocolOverride to openai-responses, while providerModelResponsesUpstreamStreaming() only returns DeepSeek’s false hint when providerMatchesRegistryTransport() still sees the registry adapter (openai-chat). This new WS normalization therefore skips the built-in DeepSeek case, so the bridge reframes raw JSON with UUID item ids and Codex can still remain stuck on the uncommitted turn; keep the pre-override streaming hint from request normalization or make this lookup tolerate the wire override.

AGENTS.md reference: src/AGENTS.md:L19-L19

Useful? React with 👍 / 👎.

Comment thread src/providers/derive.ts
// Registry-only repair policy (#938): fill only when the runtime provider has
// no explicit policy, and deep-clone so saved/user values never alias the
// registry constant.
if (prov.responsesItemIdRepair === undefined && entry.responsesItemIdRepair) {

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 Keep repair defaults out of save-time enrichment

This backfill also runs through enrichProviderFromCatalog() before save in src/cli/init.ts:153 and src/server/management/provider-routes.ts:131, so adding DeepSeek through those workflows persists the current registry-only responsesItemIdRepair into config.json. From then on routedProviderConfig() treats it as an explicit user policy and will not inherit future registry fixes/default changes, contrary to the intended route-time fill behavior; keep this repair policy out of the save-time enrichment path or strip it before saving.

AGENTS.md reference: src/AGENTS.md:L18-L18

Useful? React with 👍 / 👎.

@lidge-jun
lidge-jun force-pushed the codex/stack-04-deepseek-bounded-json branch from a3dd247 to ec5e666 Compare August 5, 2026 00:08
@lidge-jun
lidge-jun force-pushed the codex/stack-05-uuid-item-ids branch from 8403fe6 to 68c165e Compare August 5, 2026 00:08
#938)

DeepSeek's Responses route emits bare UUID item ids that leave Codex
stuck on an uncommitted turn.

- ResponsesItemIdRepairConfig.repairInvalidIds: existing message/
  reasoning ids without the canonical msg_/rs_ prefix mint stable
  type-scoped canonical ids (function_call ids and call_id untouched)
- built-in DeepSeek gets the registry-only policy { repairInvalidIds,
  repairMissingTerminalIds } filled by derive (explicit config wins)
- the bounded-JSON paths (#875) apply the same client normalization on
  both HTTP SSE synthesis and WS reframes; raw continuation snapshots
  keep upstream ids

Supersedes PR #940 with a narrow reimplementation (its id-prefix idea;
its response-id aliasing, envelope synthesis, and relay surgery are
deliberately excluded, recorded in the 060 doc).
…e route path (#938)

routedProviderConfig never enriched providers, so saved configs and
fresh provider adds never received the registry repair policy — the
e2e test masked this by enriching manually. Fill-only-when-absent
with cloned arrays, matching the file's established backfill pattern;
activation test now uses the ordinary un-enriched seed.
@lidge-jun
lidge-jun force-pushed the codex/stack-05-uuid-item-ids branch from 68c165e to a26d6a7 Compare August 5, 2026 00:25
@lidge-jun
lidge-jun force-pushed the codex/stack-04-deepseek-bounded-json branch from ec5e666 to 710492c Compare August 5, 2026 00:25
@lidge-jun
lidge-jun changed the base branch from codex/stack-04-deepseek-bounded-json to dev August 5, 2026 00:51
@lidge-jun
lidge-jun merged commit 2d7aa90 into dev Aug 5, 2026
23 of 39 checks passed
@lidge-jun
lidge-jun deleted the codex/stack-05-uuid-item-ids branch August 5, 2026 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant