fix(gateway): add content-based session hash fallback for non-Codex clients

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 #1421
This commit is contained in:
YanzheL
2026-04-02 00:11:06 +08:00
parent 83a16dec19
commit c5aac1251d
2 changed files with 111 additions and 0 deletions

View File

@@ -1044,6 +1044,7 @@ func (s *OpenAIGatewayService) ExtractSessionID(c *gin.Context, body []byte) str
// 1. Header: session_id
// 2. Header: conversation_id
// 3. Body: prompt_cache_key (opencode)
// 4. Body: content-based fallback (model + system + tools + first user message)
func (s *OpenAIGatewayService) GenerateSessionHash(c *gin.Context, body []byte) string {
if c == nil {
return ""
@@ -1056,6 +1057,9 @@ func (s *OpenAIGatewayService) GenerateSessionHash(c *gin.Context, body []byte)
if sessionID == "" && len(body) > 0 {
sessionID = strings.TrimSpace(gjson.GetBytes(body, "prompt_cache_key").String())
}
if sessionID == "" && len(body) > 0 {
sessionID = deriveOpenAIContentSessionSeed(body)
}
if sessionID == "" {
return ""
}