Skip to content

将 Claude Code 缓存亲和逻辑改为可配置规则 - #4150

Open
FlamesCN wants to merge 2 commits into
QuantumNous:mainfrom
FlamesCN:pr/claude-code-codex-cache-cn
Open

将 Claude Code 缓存亲和逻辑改为可配置规则#4150
FlamesCN wants to merge 2 commits into
QuantumNous:mainfrom
FlamesCN:pr/claude-code-codex-cache-cn

Conversation

@FlamesCN

@FlamesCN FlamesCN commented Apr 9, 2026

Copy link
Copy Markdown

这次把上一版里对 Claude metadata 的固定解析去掉了,改成走现有的渠道亲和和参数覆盖模板能力。

主要调整:

  • key_sources 增加 request_headergjson.nested_path
  • sync_fields 增加 context: 来源
  • 默认 claude cli trace 规则改成优先从 X-Claude-Code-Session-Id 取值,取不到再从 metadata.user_id 里按 nested_pathsession_id
  • 控制台补了对应配置入口,后面如果客户端再改请求结构,后台改规则就能处理,不用再改代码发版

这样做的目的是把这块逻辑从兼容转换代码里拿出来,避免继续把某一种请求结构写死在 convert.go 里。

验证:

  • go test ./...
  • bun run build
  • 线上 38.76.144.165 实测 /v1/messages -> gpt-5.4
    • 只带 metadata.user_id.session_id:第一次 cache_tokens=0,第二次 cache_tokens=3200
    • 只带 X-Claude-Code-Session-Id:第一次 cache_tokens=0,第二次 cache_tokens=2944

如果这个方向没问题,后面再遇到客户端字段调整,应该只需要在控制台改规则,不需要再补一版代码。

Summary by CodeRabbit

  • New Features

    • Added context-based parameter synchronization for advanced configuration mapping
    • Enabled nested JSON path extraction for channel affinity key sources
    • Added request header support for channel affinity key extraction
    • Enhanced prompt cache parameter preservation across request conversions
    • Expanded Claude CLI header pass-through with session ID tracking
  • Bug Fixes

    • Fixed potential nil reference in model conversion logic
    • Improved metadata handling in backend request processing
  • UI Updates

    • Extended channel affinity configuration to support request header-based key sources
    • Added nested JSON path editor for advanced key value extraction

FlamesCN added 2 commits April 2, 2026 07:23
Claude Code reached Codex through the /v1/messages compatibility path, but
new-api dropped the session-derived cache key before the final Responses
request. This preserved direct Responses caching while leaving Claude Code
turns cold. The fix carries the Claude session id into prompt_cache_key,
forces the equivalent session_id header on the compatibility path, and keeps
Codex-only incompatible metadata out of the upstream request.

Constraint: Codex only accepts /v1/responses and rejects metadata on the final upstream request
Rejected: Rely on pass_headers alone | did not produce cache hits on the Claude compatibility path
Rejected: Only sync prompt_cache_key without session_id header | direct probes still missed cache reads
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep Claude -> Responses compatibility preserving both prompt_cache_key and session_id together for Codex-backed models
Tested: go test ./service/... ./relay/...
Tested: manual production verification with Claude Code gpt-5.4 second-turn cache hit (cache_tokens=9472)
Not-tested: upstream/main latest integration after cherry-pick
Claude Code cache reuse on the /v1/messages -> responses compatibility path
should be driven by channel-affinity rules and override templates, not by
hardcoded metadata parsing. This change adds request-header and nested JSON
key extraction, exposes the resolved affinity key to override context, and
lets templates sync that key into prompt_cache_key and session_id from the
console.

Constraint: Operators need to adapt to client header/metadata shape changes without shipping a new binary
Rejected: Keep parsing metadata.user_id.session_id in convert.go | brittle to client request format changes
Rejected: Add a separate Claude-specific settings surface | duplicates existing channel-affinity and param-override controls
Confidence: high
Scope-risk: moderate
Reversibility: clean
Directive: Keep Claude cache-affinity behavior driven by key_sources plus override templates; avoid reintroducing client-specific parsing in convert paths
Tested: go test ./...
Tested: bun run build
Tested: production smoke test on 38.76.144.165 for /v1/messages -> gpt-5.4 with metadata-only and header-only session keys; second request hit cache in both cases
Not-tested: GitHub PR creation via gh CLI (local auth token invalid)
@coderabbitai

coderabbitai Bot commented Apr 9, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

This PR extends parameter override and channel affinity infrastructure to support context-based sync fields, nested JSON path extraction for key sources, and enhanced prompt caching. It adds a new context: sync field type alongside existing json/body and header types, enables nested value extraction from channel affinity sources, integrates runtime header overrides with prompt cache keys in responses flows, and upgrades Claude CLI configuration to handle session headers and metadata extraction.

Changes

Cohort / File(s) Summary
Context Key & Constant Infrastructure
constant/context_key.go
Added new context key constant ContextKeyChannelParamOverrideContext for storing parameter override context in gin context.
Override Mechanism Core Extension
relay/common/override.go, relay/common/override_test.go
Extended sync field target parsing to support context:<key> kind; added snapshot context and context sync read/write operations; enhanced BuildParamOverrideContext to merge channel metadata's param override context without overwriting existing keys. Includes comprehensive unit test covering context-to-json and context-to-header sync operations.
Channel Metadata & Relay Info
relay/common/relay_info.go
Added ParamOverrideContext field to ChannelMeta and updated initialization to populate it from gin context via the new context key constant.
Channel Affinity Service Logic
service/channel_affinity.go, service/channel_affinity_template_test.go
Extended channel affinity extraction to support nested JSON path (NestedPath) for all key source types; added extractNestedChannelAffinityValue helper; updated context-setting behavior to compute and store parameter override context; added buildChannelAffinityParamOverrideContext for constructing affinity metadata context. Includes three new test cases validating Claude template sync, request header extraction, and nested JSON extraction.
Request Conversion & Prompt Cache Support
service/convert.go, service/openaicompat/chat_to_responses.go, service/openaicompat/chat_to_responses_test.go
Propagated claudeRequest.Metadata into OpenAI request conversion with nil-safety guards; added PromptCacheKey and PromptCacheRetention fields to responses request conversion. Includes unit test validating prompt cache key preservation through conversion.
Chat Completions Responses Flow Integration
relay/chat_completions_via_responses.go
Added ensureRuntimeHeaderOverride helper function to set runtime header overrides; integrated prompt cache key syncing by setting session_id runtime header from parameter-overridden request's PromptCacheKey.
Codex Adaptor Request Normalization
relay/channel/codex/adaptor.go
Enhanced ConvertOpenAIResponsesRequest to explicitly clear request.Metadata for non-compact relay mode before sending to backend.
Channel Affinity Configuration Settings
setting/operation_setting/channel_affinity_setting.go
Added NestedPath field to ChannelAffinityKeySource; extended key source types to include request_header; introduced buildClaudeCliHeaderTemplate to construct param override templates with header pass-through and context-to-header/json sync operations; updated Claude CLI rule to match both Claude and GPT models with dual key sources (header + metadata with nested extraction).
Frontend: Param Override Editor
web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx
Extended sync target type selection to support context prefix; updated spec building to preserve context as normalized type; changed quick mapping tags from header:session_id to context:channel_affinity.key.
Frontend: Channel Affinity Template Constants
web/src/constants/channel-affinity-template.constants.js
Added X-Claude-Code-Session-Id to Claude CLI pass-through headers; introduced explicit CLAUDE_CLI_HEADER_PASSTHROUGH_TEMPLATE with sync field operations; updated Claude CLI rule to match both ^claude-.*$ and ^gpt-.*$ models with composite key sources (request header + gjson with nested path extraction).
Frontend: Channel Affinity Settings UI
web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx
Extended key source type support to include request_header; enhanced normalizeKeySource to extract and propagate nested_path field; updated key source rendering to display nested paths in gjson entries; added validation for request_header requiring non-empty key; added editable "内层 JSON Path" column for gjson nested extraction configuration.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested labels

ready to merge

Suggested reviewers

  • seefs001
  • Calcium-Ion

Poem

🐰✨ Context hops through sync fields bright,
Nested paths extract with gjson's might,
Affinity keys dance to headers' delight,
Prompt caches bloom from override's flight!
A rabbit's dream—pure override choreography. 🎭

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.67% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: converting Claude Code cache affinity logic from hardcoded to configurable rules, which is the core refactoring across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx (1)

276-277: Localize newly added sync-field labels/tags via t(...).

The new context option label and quick-tag texts are hardcoded, so they won’t participate in i18n.

♻️ Proposed refactor
-const SYNC_TARGET_TYPE_OPTIONS = [
-  { label: '请求体字段', value: 'json' },
-  { label: '请求头字段', value: 'header' },
-  { label: '上下文字段', value: 'context' },
-];
+const getSyncTargetTypeOptions = (t) => [
+  { label: t('请求体字段'), value: 'json' },
+  { label: t('请求头字段'), value: 'header' },
+  { label: t('上下文字段'), value: 'context' },
+];
+  const syncTargetTypeOptions = useMemo(
+    () => getSyncTargetTypeOptions(t),
+    [t],
+  );
...
- optionList={SYNC_TARGET_TYPE_OPTIONS}
+ optionList={syncTargetTypeOptions}
...
- {'context:channel_affinity.key -> json:prompt_cache_key'}
+ {t('context:channel_affinity.key -> json:prompt_cache_key')}
...
- {'context:channel_affinity.key -> header:session_id'}
+ {t('context:channel_affinity.key -> header:session_id')}

As per coding guidelines: “Frontend i18n: Use i18next + react-i18next ... Use useTranslation() hook and call t('中文key') in components.”

Also applies to: 2991-3016

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx` around
lines 276 - 277, The new hardcoded sync-field label ('上下文字段' for value
'context') and the quick-tag strings should be localized: in the
ParamOverrideEditorModal component import and call useTranslation(), replace the
literal label and all hardcoded quick-tag texts (the options array entry with
label '上下文字段' and the quick-tag strings around the 2991-3016 region) with
t('...') keys, and ensure you add appropriate i18n keys/strings rather than raw
Chinese text so the labels/tags participate in i18n.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx`:
- Around line 276-277: The new hardcoded sync-field label ('上下文字段' for value
'context') and the quick-tag strings should be localized: in the
ParamOverrideEditorModal component import and call useTranslation(), replace the
literal label and all hardcoded quick-tag texts (the options array entry with
label '上下文字段' and the quick-tag strings around the 2991-3016 region) with
t('...') keys, and ensure you add appropriate i18n keys/strings rather than raw
Chinese text so the labels/tags participate in i18n.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95c6cfff-ddf4-4d82-8f4f-4c39e42b3eac

📥 Commits

Reviewing files that changed from the base of the PR and between 78e4cb3 and 6962756.

📒 Files selected for processing (15)
  • constant/context_key.go
  • relay/channel/codex/adaptor.go
  • relay/chat_completions_via_responses.go
  • relay/common/override.go
  • relay/common/override_test.go
  • relay/common/relay_info.go
  • service/channel_affinity.go
  • service/channel_affinity_template_test.go
  • service/convert.go
  • service/openaicompat/chat_to_responses.go
  • service/openaicompat/chat_to_responses_test.go
  • setting/operation_setting/channel_affinity_setting.go
  • web/src/components/table/channels/modals/ParamOverrideEditorModal.jsx
  • web/src/constants/channel-affinity-template.constants.js
  • web/src/pages/Setting/Operation/SettingsChannelAffinity.jsx

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.

1 participant