mirror of
https://github.com/Wei-Shaw/sub2api.git
synced 2026-10-07 16:37:52 +08:00
Merge pull request #4612 from catoncat/fix/codex-call-id-length
fix(openai): 限制 Codex call_id 归一化后的长度
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -84,6 +86,34 @@ type codexOAuthTransformOptions struct {
|
||||
OmitPromotedSystemMessagesFromInput bool
|
||||
}
|
||||
|
||||
const (
|
||||
codexCallIDMaxLength = 64
|
||||
codexCallIDPrefix = "fc_"
|
||||
)
|
||||
|
||||
func normalizeCodexCallID(id string) string {
|
||||
candidate := id
|
||||
switch {
|
||||
case id == "":
|
||||
return ""
|
||||
case strings.HasPrefix(id, "fc"):
|
||||
case strings.HasPrefix(id, "call_"):
|
||||
candidate = codexCallIDPrefix + strings.TrimPrefix(id, "call_")
|
||||
default:
|
||||
candidate = codexCallIDPrefix + id
|
||||
}
|
||||
if len(candidate) <= codexCallIDMaxLength {
|
||||
return candidate
|
||||
}
|
||||
return compactCodexCallID(candidate)
|
||||
}
|
||||
|
||||
func compactCodexCallID(id string) string {
|
||||
digest := sha256.Sum256([]byte("sub2api:codex-call-id:v1:" + id))
|
||||
encoded := hex.EncodeToString(digest[:])
|
||||
return codexCallIDPrefix + encoded[:codexCallIDMaxLength-len(codexCallIDPrefix)]
|
||||
}
|
||||
|
||||
const codexImageGenerationFunctionToolName = "image_gen.imagegen"
|
||||
|
||||
const (
|
||||
@@ -1381,13 +1411,7 @@ func filterCodexInputWithOptions(input []any, opts codexInputFilterOptions) []an
|
||||
if opts.PreserveCallIDs {
|
||||
return id
|
||||
}
|
||||
if id == "" || strings.HasPrefix(id, "fc") {
|
||||
return id
|
||||
}
|
||||
if strings.HasPrefix(id, "call_") {
|
||||
return "fc_" + strings.TrimPrefix(id, "call_")
|
||||
}
|
||||
return "fc_" + id
|
||||
return normalizeCodexCallID(id)
|
||||
}
|
||||
|
||||
if typ == "item_reference" {
|
||||
|
||||
@@ -127,6 +127,70 @@ func TestApplyCodexOAuthTransform_ToolContinuationNormalizesToolReferenceIDsOnly
|
||||
require.Equal(t, "fc_1", second["call_id"])
|
||||
}
|
||||
|
||||
func TestApplyCodexOAuthTransform_BoundsLongCallIDsAndPreservesPairing(t *testing.T) {
|
||||
suffix := strings.Repeat("z", 62)
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
callID string
|
||||
outputCallID string
|
||||
}{
|
||||
{name: "non-native boundary id", callID: "call-" + strings.Repeat("x", 59), outputCallID: "call-" + strings.Repeat("x", 59)},
|
||||
{name: "overlong fc id", callID: "fc_" + strings.Repeat("y", 62), outputCallID: "fc_" + strings.Repeat("y", 62)},
|
||||
{name: "equivalent prefixes", callID: "call_" + suffix, outputCallID: "fc_" + suffix},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
reqBody := map[string]any{
|
||||
"model": "gpt-5.2",
|
||||
"input": []any{
|
||||
map[string]any{"type": "function_call", "call_id": tc.callID, "name": "shell"},
|
||||
map[string]any{"type": "function_call_output", "call_id": tc.outputCallID, "output": "done"},
|
||||
},
|
||||
}
|
||||
|
||||
applyCodexOAuthTransform(reqBody, false, false)
|
||||
|
||||
input, ok := reqBody["input"].([]any)
|
||||
require.True(t, ok)
|
||||
call, ok := input[0].(map[string]any)
|
||||
require.True(t, ok)
|
||||
output, ok := input[1].(map[string]any)
|
||||
require.True(t, ok)
|
||||
|
||||
fixedCallID, ok := call["call_id"].(string)
|
||||
require.True(t, ok)
|
||||
require.LessOrEqual(t, len(fixedCallID), codexCallIDMaxLength)
|
||||
require.True(t, strings.HasPrefix(fixedCallID, codexCallIDPrefix))
|
||||
require.Equal(t, fixedCallID, output["call_id"])
|
||||
require.Equal(t, fixedCallID, normalizeCodexCallID(tc.callID))
|
||||
require.Equal(t, fixedCallID, normalizeCodexCallID(tc.outputCallID))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestApplyCodexOAuthTransform_PreservesLongCallIDsWhenRequested(t *testing.T) {
|
||||
callID := "call-" + strings.Repeat("x", 70)
|
||||
reqBody := map[string]any{
|
||||
"model": "gpt-5.2",
|
||||
"input": []any{
|
||||
map[string]any{"type": "function_call", "call_id": callID, "name": "shell"},
|
||||
map[string]any{"type": "function_call_output", "call_id": callID, "output": "done"},
|
||||
},
|
||||
}
|
||||
|
||||
applyCodexOAuthTransformWithOptions(reqBody, codexOAuthTransformOptions{
|
||||
PreserveToolCallIDs: true,
|
||||
})
|
||||
|
||||
input, ok := reqBody["input"].([]any)
|
||||
require.True(t, ok)
|
||||
call, ok := input[0].(map[string]any)
|
||||
require.True(t, ok)
|
||||
output, ok := input[1].(map[string]any)
|
||||
require.True(t, ok)
|
||||
require.Equal(t, callID, call["call_id"])
|
||||
require.Equal(t, callID, output["call_id"])
|
||||
}
|
||||
|
||||
func TestApplyCodexOAuthTransform_ToolSearchOutputPreservesCallID(t *testing.T) {
|
||||
reqBody := map[string]any{
|
||||
"model": "gpt-5.2",
|
||||
|
||||
Reference in New Issue
Block a user