Skip to content

fix(translator): map non-streaming Claude stop reasons the way the streaming path does - #16544

Merged
diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.52from
pacocartones:fix/claude-nonstream-stop-reasons
Oct 15, 2026
Merged

diegosouzapw merged 2 commits into
cheaper-inference:release/v3.8.52from
pacocartones:fix/claude-nonstream-stop-reasons

Conversation

@pacocartones

Copy link
Copy Markdown
Contributor

Summary

  • A non-streaming Claude response only translated end_turn, tool_use and max_tokens (responseTranslator.ts, the Claude branch of translateNonStreamingResponse). refusal, model_context_window_exceeded, stop_sequence and pause_turn stayed raw.
  • For an OpenAI client, sanitizeOpenAIResponse normalises them later. A Gemini client has no such step: OPENAI_TO_GEMINI_FINISH_REASON falls back to STOP, so a refusal or a context-window stop reached it as a clean STOP. Measured on e23fb0f: refusal -> STOP, model_context_window_exceeded -> STOP.
  • The branch now uses normalizeOpenAICompatibleFinishReasonString, which already holds the same mapping as the streaming convertStopReason: refusal -> content_filter, max_tokens and model_context_window_exceeded -> length, stop_sequence and pause_turn -> stop. A Gemini client now gets SAFETY and MAX_TOKENS.

Related Issues

Target Branch

  • Base is the active release/v3.8.x branch (the highest open release/v*), not main
  • New feature? From 3.8.55 on it is held with the v4-feature label for the v4 channel

Validation

  • Change type: other (translator)
  • Focused tests and category gates from the golden path
  • npm run lint (eslint on the changed files: clean)
  • Reconciled with the current active release base; focused checks rerun afterward
  • Production-code changes include a new or updated automated test in this PR

Tests Added Or Updated

  • tests/unit/claude-nonstream-stop-reasons.test.ts (new): 6 tests. On the base 5 fail and 1 passes; with the fix all 6 pass. One of them checks that end_turn, tool_use and max_tokens keep their mappings for both OpenAI and Gemini clients.

Coverage Notes

  • The 28 test files that import responseTranslator: 375/375 pass with the fix.

Reviewer Notes

…reaming path does

A non-streaming Claude response only translated end_turn, tool_use and
max_tokens. refusal, model_context_window_exceeded, stop_sequence and
pause_turn stayed raw, so a Gemini client got a refusal or a context-window
stop as a clean STOP. Use the shared OpenAI-compatible normalizer, which
already holds the same mapping as convertStopReason.
@diegosouzapw
diegosouzapw merged commit 607072b into cheaper-inference:release/v3.8.52 Oct 15, 2026
32 of 51 checks passed
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.

2 participants