Translator patches: reasoning fallback + cache_control strip (sc-988867)#1
Merged
Conversation
added 3 commits
May 18, 2026 15:44
…s empty (ampeco fork) Upstream's OpenAI->Claude response translator looks only at `reasoning_content`, but OpenRouter emits the field as `reasoning`. As a result, reasoning blocks from every OpenRouter-backed provider (kimi, qwen, glm, deepseek, minimax, ...) are silently dropped and never surface as Anthropic `thinking` blocks. Add a fallback at all three call sites (streaming chunk converter, non-stream helper, exported non-stream entry point): when `reasoning_content` is empty or absent, use `reasoning` instead. Strict-additive — when both fields are present, `reasoning_content` still wins, so providers that emit it (OpenAI o-series, DeepSeek direct) are unaffected. Cover all three sites and the strict-additive property in `TestConvertOpenAIResponseToClaude_ReasoningFallback`. Refs: AMPECO story sc-988867
…OpenAI (ampeco fork) Anthropic clients embed `cache_control` markers (used for Anthropic prompt caching) on `messages[].content[]`, `system[]`, and `tools[]`. Upstream's Claude->OpenAI request translator has no defined handling for the field; OpenAI- compatible providers either ignore it silently or may reject the request. Add a `stripCacheControl` helper invoked at the top of `ConvertClaudeRequestToOpenAI` that deletes `cache_control` from every location where it can appear in a Claude request. Mirrors CCR's `OpenrouterTransformer` (lines 17-29). Applied universally because the field has no valid meaning on the Claude->OpenAI path — only deletes when the field is present, so providers without it are unaffected. Covered by `TestConvertClaudeRequestToOpenAI_StripsCacheControl` (all four locations), `TestConvertClaudeRequestToOpenAI_PreservesContentWhenStrippingCacheControl` (surrounding content survives), and `TestStripCacheControl_IsIdempotent`. Refs: AMPECO story sc-988867
…cadence Add a fork-specific section at the top of the README describing: - Why the fork exists (validated 2026-05-15: two OpenRouter protocol-translation gaps surfaced; both closed by the patches in this commit series) - Patch 1: `reasoning` fallback in OpenAI->Claude response translator - Patch 2: `cache_control` stripping in Claude->OpenAI request translator - Test coverage for both patches - Monthly intentional-rebase cadence against upstream - Escalation options if rebase cost grows Refs: AMPECO story sc-988867
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First ampeco-specific commit series on this fork. Closes two OpenRouter protocol-translation gaps surfaced during the 2026-05-15 validation of story #988867 (centralized CLIProxyAPI on mm007 — fleet-wide Claude account pool).
Both patches are strict-additive: each only fires when its condition is met, so providers that don't trigger it are unaffected.
Patch series
Patch 1 —
reasoningfield fallback (commit496152ee)internal/translator/openai/claude/openai_claude_response.go— three call sites (streaming chunk, non-stream helper, exported non-stream entry).OpenRouter emits the reasoning field as
reasoning; upstream only looks forreasoning_content. Result: reasoning blocks silently disappear from all OpenRouter-backed providers (kimi, qwen, glm, deepseek, minimax, ...). Patch: whenreasoning_contentis empty/absent, fall back toreasoning. When both are present,reasoning_contentstill wins.Patch 2 — strip
cache_controlmarkers (commit944e6739)internal/translator/openai/claude/openai_claude_request.go— newstripCacheControlhelper invoked at the top ofConvertClaudeRequestToOpenAI.Anthropic clients embed
cache_control(prompt caching) onmessages[].content[],system[], andtools[]. Upstream's Claude→OpenAI request translator has no defined handling; OpenAI-compatible providers either ignore the field silently or may reject the request. Mirrors CCR'sOpenrouterTransformer(lines 17-29).README (commit
5b14d12f)Adds a fork-specific section at the top describing why the fork exists, the patch series, test coverage, the monthly intentional-rebase cadence, and escalation options.
Test plan
go test ./internal/translator/openai/claude/...passes (new tests + existing tests).go test ./...passes for every package that this PR touches.TestUpdateAntigravityCreditsBalance_LoadCodeAssistUserAgentfailure on upstreammainis unrelated to this PR (verified by stashing the patches and running the same test against unmodifiedupstream/main).reasoning_contentstill wins when both fields are present (negative test).stripCacheControlis idempotent and a no-op on clean input (TestStripCacheControl_IsIdempotent).Implementation note (file path)
The implementation plan for sc-988867 referenced
internal/translator/claude/openai/chat-completions/claude_openai_request.gofor Patch 2. That file actually handles the opposite direction (OpenAI→Claude); the correct file for strippingcache_controlon the Claude→OpenAI path isinternal/translator/openai/claude/openai_claude_request.go. Verified via thetranslator.Register(<source>, <destination>, ...)calls in each package'sinit.go. The fix is in the correct file in this PR.🤖 Generated with Claude Code