fix(gateway): add content-based session hash fallback for non-Codex clients#1428
Open
YanzheL wants to merge 4 commits intoWei-Shaw:mainfrom
Open
fix(gateway): add content-based session hash fallback for non-Codex clients#1428YanzheL wants to merge 4 commits intoWei-Shaw:mainfrom
YanzheL wants to merge 4 commits intoWei-Shaw:mainfrom
Conversation
…lients When no explicit session signals (session_id, conversation_id, prompt_cache_key) are provided, derive a stable session seed from the request body content (model + tools + system prompt + first user message) to enable sticky routing and prompt caching for non-Codex clients using the Chat Completions API. This mirrors the content-based fallback already present in GatewayService. GenerateSessionHash, adapted for the OpenAI gateway's request formats (both Chat Completions messages and Responses API input). JSON fragments are canonicalized via normalizeCompatSeedJSON to ensure semantically identical requests produce the same seed regardless of whitespace or key ordering. Closes Wei-Shaw#1421
- 20 unit tests for deriveOpenAIContentSessionSeed covering: - Empty/nil inputs, model-only, stable across turns - Different model/system/first-user produce different seeds - Tools, functions, developer role, structured content - Responses API: input string, input array, instructions, input_text typed items - JSON canonicalization (whitespace/key-order insensitive) - Prefix presence, empty tools ignored, messages preferred over input - 3 integration tests for GenerateSessionHash content fallback: - Content fallback produces stable hash - Explicit signals override content fallback - Empty body still returns empty hash
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
OpenAIGatewayService.GenerateSessionHashfor sticky session routing when no explicit session signals are providedderiveOpenAIContentSessionSeedextracts a stable seed from request body content (model + tools + system + first user message)Closes #1421
Problem
Non-Codex clients using the Chat Completions API without sending
session_id,conversation_id, orprompt_cache_keyget""fromGenerateSessionHash. This causesSelectAccountWithSchedulerto fall back to random load-balanced routing, making prompt caching impossible (cache_read_input_tokensalways 0).Solution
Added a 4th priority tier to
GenerateSessionHashthat derives a stable content-based seed from the request body when all explicit signals are absent:The seed includes only fields constant across conversation turns:
model— always the same per conversationtools/functions— tool definitions don't change mid-conversationinstructions— Responses API system promptsystem/developermessages — stable system promptsusermessage — the conversation openerJSON fragments (tools, functions, structured content) are canonicalized via the existing
normalizeCompatSeedJSONto handle whitespace/key-order differences.Files Changed
openai_content_session_seed.goderiveOpenAIContentSessionSeedhelper (~105 lines)openai_gateway_service.goopenai_content_session_seed_test.goopenai_gateway_service_test.goDesign Decisions
No client identity mixing — Unlike
GatewayService.GenerateSessionHashwhich mixes in ClientIP/UserAgent/APIKeyID, the OpenAI content fallback is purely content-based. Two different users with identical prompts route to the same account, maximizing prompt cache hits.JSON canonicalization — Reuses existing
normalizeCompatSeedJSON(json.Unmarshal → json.Marshal) for tools, functions, and structured content to ensure key-order and whitespace differences don't produce different seeds.Responses API
inputsupport — Handles string input, role-based array input, andinput_texttyped items.Prefix
compat_cs_— Prevents collisions between content-derived seeds and explicit session IDs orcompat_cc_prompt cache keys.Test Evidence
go build ./...— exit 0GenerateSessionHashtests: 4/4 pass (zero regressions)Known Trade-offs
GenerateSessionHashWithFallbacknow prefers content seed over the genericfallbackSeedfor first turns. The explicit seed still takes effect when content extraction yields nothing.