mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-08-31 01:13:06 +08:00
fix(openai): honor Codex session-id header
This commit is contained in:
@@ -28,6 +28,7 @@ const (
|
||||
)
|
||||
|
||||
var explicitOpenAIHeaderSessionNames = []string{
|
||||
"session-id",
|
||||
"session_id",
|
||||
"conversation_id",
|
||||
openCodeSessionAffinityHeader,
|
||||
@@ -145,7 +146,7 @@ func (s *OpenAIGatewayService) GenerateExplicitSessionHash(c *gin.Context, body
|
||||
// GenerateSessionHash generates a sticky-session hash for OpenAI requests.
|
||||
//
|
||||
// Priority:
|
||||
// 1. Header: session_id
|
||||
// 1. Header: session-id / session_id
|
||||
// 2. Header: conversation_id
|
||||
// 3. Header: x-session-affinity / x-session-id / x-opencode-session (OpenCode)
|
||||
// 4. Header: x-conversation-id (CodeBuddy)
|
||||
|
||||
@@ -391,6 +391,7 @@ func TestOpenAIGatewayService_ClientSessionHeaderPriority(t *testing.T) {
|
||||
name string
|
||||
value string
|
||||
}{
|
||||
{name: "session-id", value: "codex-session"},
|
||||
{name: "session_id", value: "generic-session"},
|
||||
{name: "conversation_id", value: "generic-conversation"},
|
||||
{name: openCodeSessionAffinityHeader, value: "opencode-affinity"},
|
||||
@@ -416,6 +417,31 @@ func TestOpenAIGatewayService_ClientSessionHeaderPriority(t *testing.T) {
|
||||
require.Equal(t, "body-session", svc.ExtractSessionID(c, body))
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayService_CodexSessionIDKeepsReconnectHashStable(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/v1/responses", nil)
|
||||
c.Request.Header.Set("session-id", "codex-reconnect-session")
|
||||
|
||||
svc := &OpenAIGatewayService{}
|
||||
warmup := []byte(`{
|
||||
"type":"response.create",
|
||||
"model":"gpt-5.6-sol",
|
||||
"generate":false,
|
||||
"tools":[{"type":"custom","name":"exec"}],
|
||||
"input":[{"role":"user","content":"warmup"}]
|
||||
}`)
|
||||
business := []byte(`{
|
||||
"type":"response.create",
|
||||
"model":"gpt-5.6-sol",
|
||||
"input":[{"role":"user","content":"install codex"}]
|
||||
}`)
|
||||
|
||||
require.Equal(t, svc.GenerateSessionHash(c, warmup), svc.GenerateSessionHash(c, business))
|
||||
require.Equal(t, "codex-reconnect-session", svc.ExtractSessionID(c, business))
|
||||
}
|
||||
|
||||
func TestOpenAIGatewayService_ClientSessionHeadersIgnorePerRequestIDs(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
recorder := httptest.NewRecorder()
|
||||
|
||||
@@ -65,7 +65,10 @@ func resolveOpenAIWSSessionHeaders(c *gin.Context, promptCacheKey string) openAI
|
||||
ConversationSource: "none",
|
||||
}
|
||||
if c != nil && c.Request != nil {
|
||||
if sessionID := strings.TrimSpace(c.Request.Header.Get("session_id")); sessionID != "" {
|
||||
if sessionID := strings.TrimSpace(c.Request.Header.Get("session-id")); sessionID != "" {
|
||||
resolution.SessionID = sessionID
|
||||
resolution.SessionSource = "header_session-id"
|
||||
} else if sessionID := strings.TrimSpace(c.Request.Header.Get("session_id")); sessionID != "" {
|
||||
resolution.SessionID = sessionID
|
||||
resolution.SessionSource = "header_session_id"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestResolveOpenAIWSSessionHeadersPrefersCodexHyphenHeader(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/v1/responses", nil)
|
||||
c.Request.Header.Set("session-id", "codex-session")
|
||||
c.Request.Header.Set("session_id", "legacy-session")
|
||||
|
||||
resolution := resolveOpenAIWSSessionHeaders(c, "prompt-cache")
|
||||
|
||||
require.Equal(t, "codex-session", resolution.SessionID)
|
||||
require.Equal(t, "header_session-id", resolution.SessionSource)
|
||||
}
|
||||
|
||||
func TestResolveOpenAIWSSessionHeadersFallsBackToLegacyHeader(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
recorder := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(recorder)
|
||||
c.Request = httptest.NewRequest(http.MethodGet, "/v1/responses", nil)
|
||||
c.Request.Header.Set("session_id", "legacy-session")
|
||||
|
||||
resolution := resolveOpenAIWSSessionHeaders(c, "prompt-cache")
|
||||
|
||||
require.Equal(t, "legacy-session", resolution.SessionID)
|
||||
require.Equal(t, "header_session_id", resolution.SessionSource)
|
||||
}
|
||||
Reference in New Issue
Block a user