Skip to content

Bug: Codex→Claude SSE content_block.index collisions break Claude clients #539

@fuguiKz

Description

@fuguiKz

Problem / 问题

When translating OpenAI/Codex streaming (/v1/responses) into Claude streaming (/v1/messages), the current translator reuses Codex output_index as Claude content_block.index.

If a single output_index produces multiple block types (e.g. tool_use + thinking + text), the same content_block.index gets reused for different block types. Claude streaming expects each content_block.index to uniquely identify one started block, and deltas for that index must match the started type.

This can cause Claude clients (e.g. Claude Code for VS Code) to fail with errors like:

  • Mismatched content block type content_block_delta thinking

Repro / 复现

A stream where output_index=0 contains both a tool call and reasoning/text, for example:

  • response.output_item.added (function_call, output_index=0)
  • response.function_call_arguments.delta (output_index=0)
  • response.output_item.done (output_index=0)
  • response.reasoning_summary_part.added (output_index=0)
  • response.reasoning_summary_text.delta (output_index=0)

This currently translates into Claude SSE where content_block_start for different types share the same index, and later content_block_delta events can mismatch the type for that index.

Proposed Fix / 修复思路

  • Allocate sequential, unique Claude content_block.index values per logical block (per stream), rather than reusing output_index.
  • Ensure content_block_start is emitted before any content_block_delta for that block.
  • Close any still-open blocks (content_block_stop) before emitting final message_delta/message_stop on completion.

Patch / 补丁

A ready patch + regression test is in PR #538 (note: this repo has a required translator-path-guard check that blocks merging translator path changes via PRs):

Maintainers can cherry-pick from the fork branch used by the PR:

git fetch https://github.com/fuguiKz/CLIProxyAPI.git fix/codex-claude-sse-content-block-index
git cherry-pick a321be1 7761566

Tests

PR adds internal/translator/codex/claude/codex_claude_response_test.go to ensure indexes are not reused across types and deltas always match the started block type for a given index.

(Notes: go test ./internal/translator/codex/claude passes.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions