Repository navigation
[Feature] Preserve Claude Code /v1/messages payload semantics - #2351
Conversation
…fix+providers-missing-button-i18n fix(providers): fix missing i18n keys and add 'Add Provider' button to empty state
… enhancement/claude-code-payload-passthrough
There was a problem hiding this comment.
Code Review
This pull request introduces a 'semantic passthrough' mechanism for Claude Code and CLI requests, allowing them to bypass standard message normalization and preserve complex content blocks like documents and tool results. It includes detection logic based on headers and User-Agent strings, updates to the translation service to handle preserved messages, and comprehensive unit tests. A review comment identified an opportunity to optimize performance by removing redundant deep cloning of the messages array during the semantic body preparation.
| messages: Array.isArray(claudeBody.messages) | ||
| ? (cloneValue(claudeBody.messages) as Array<Record<string, unknown>>) | ||
| : [], |
There was a problem hiding this comment.
The messages array is being deep-cloned twice when preserveClaudeMessages is enabled. First, prepareClaudeCodeCompatibleSemanticBody performs a deep clone of the entire array. Subsequently, cloneClaudeCodeCompatibleMessagesFromClaude (called from buildClaudeCodeCompatibleRequest) iterates over this already-cloned array and performs another deep clone on each individual message object. For large conversation histories typical in Claude Code sessions, this redundant deep cloning can impact performance and memory usage.
| messages: Array.isArray(claudeBody.messages) | |
| ? (cloneValue(claudeBody.messages) as Array<Record<string, unknown>>) | |
| : [], | |
| messages: Array.isArray(claudeBody.messages) | |
| ? (claudeBody.messages as Array<Record<string, unknown>>) | |
| : [], |
db8a2dc
into
cheaper-inference:release/v3.8.0
|
Thank you @terence71-glitch for this excellent contribution! 🎉 Your semantic passthrough implementation is exactly what Claude Code users need — preserving the carefully structured The 87-test coverage is outstanding, and the narrowly scoped detection logic (User-Agent + x-app + session-id headers) is clean and robust. This has been merged into release/v3.8.0 and will ship in the upcoming release. Thanks again for the quality work! 🚀 |
- feat(claude-code): semantic passthrough (#2351 — thanks @terence71-glitch) - fix(usage): flat cached_tokens/reasoning_tokens extraction (#2350 — thanks @TF0rd)
…assthrough (#2472) PR #2351 introduced isClaudeCodeSemanticPassthrough to preserve native Claude Code payloads by skipping normalizeClaudeUpstreamMessages — but that was the only path that lifted role:"system"/"developer" messages from messages[] to the top-level system parameter, which Anthropic requires. Memory/system injection was silently 400ing. Rebased linearly onto the repaired release/v3.8.2; coexists with the Claude passthrough beta-flag/thinking changes (tests: system-role-extraction 9/9).
…e#2351) Integrated into release/v3.8.0 — Claude Code semantic passthrough for /v1/messages payloads
…nference#2350 - feat(claude-code): semantic passthrough (cheaper-inference#2351 — thanks @terence71-glitch) - fix(usage): flat cached_tokens/reasoning_tokens extraction (cheaper-inference#2350 — thanks @TF0rd)
…e#2351) Integrated into release/v3.8.0 — Claude Code semantic passthrough for /v1/messages payloads
…nference#2350 - feat(claude-code): semantic passthrough (cheaper-inference#2351 — thanks @terence71-glitch) - fix(usage): flat cached_tokens/reasoning_tokens extraction (cheaper-inference#2350 — thanks @TF0rd)
…e#2351) Integrated into release/v3.8.0 — Claude Code semantic passthrough for /v1/messages payloads
…nference#2350 - feat(claude-code): semantic passthrough (cheaper-inference#2351 — thanks @terence71-glitch) - fix(usage): flat cached_tokens/reasoning_tokens extraction (cheaper-inference#2350 — thanks @TF0rd)
Summary
This implements semantic passthrough for valid Claude Code
/v1/messagespayloads on direct Claude-Code-style routes:claudeanthropic-compatible-cc-*For verified Claude Code / Claude CLI requests, OmniRoute now avoids broad message normalization that can rewrite or reorder the client-provided Anthropic Messages payload before it reaches an upstream that already understands Claude Code semantics.
Closes [Feature] Preserve Claude Code
/v1/messagespayload semantics on direct Claude-Code paths #2347What changed
claude-codeclaude-clix-app: clix-claude-code-session-idnormalizeClaudeUpstreamMessages()for verified Claude Code requests on the nativeclaudepath.messages[]through theanthropic-compatible-cc-*relay path before required relay-specific transforms.Why
Claude Code already emits valid Anthropic Messages API payloads for coding tasks, including message ordering, tool-use/tool-result structure, system blocks, cache-control placement, and thinking/context fields.
Broad normalization on direct Claude-Code-style routes can unnecessarily change that structure by:
role: "system"messages into top-levelsystemmessages[]This PR keeps the client-provided
messages[]semantics intact for valid native Claude Code traffic while still allowing OmniRoute to perform routing, model resolution, OAuth/account handling, headers/signing, and provider-specific compatibility work.Scope
This is semantic passthrough, not raw byte-for-byte passthrough.
OmniRoute still parses JSON and may still apply required behavior such as:
anthropic-compatible-cc-*This does not change general cross-provider translation behavior.
Acceptance criteria covered
/v1/messagesrequests toclaudekeepmessages[]unchanged through chatCore translation./v1/messagesrequests toanthropic-compatible-cc-*keepmessages[]unchanged before required relay transforms./v1/messages?beta=true-style path behavior.Tests