feat(translator): normalize service_tier in Codex requests and add tests

- Added `normalizeCodexServiceTier` to standardize `service_tier` values (`fast` to `priority`, omit unsupported tiers).
- Updated `ConvertClaudeRequestToCodex` to apply normalization logic.
- Introduced `TestConvertClaudeRequestToCodex_ServiceTier` to validate behavior across various `service_tier` inputs.

Closes: #3276 #3294
This commit is contained in:
Luis Pater
2026-06-19 03:58:55 +08:00
parent c020e2d03f
commit 893412e965
2 changed files with 68 additions and 0 deletions
@@ -327,6 +327,9 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
}
template, _ = sjson.SetBytes(template, "reasoning.effort", reasoningEffort)
template, _ = sjson.SetBytes(template, "reasoning.summary", "auto")
if serviceTier := normalizeCodexServiceTier(rootResult.Get("service_tier")); serviceTier != "" {
template, _ = sjson.SetBytes(template, "service_tier", serviceTier)
}
template, _ = sjson.SetBytes(template, "stream", true)
template, _ = sjson.SetBytes(template, "store", false)
template, _ = sjson.SetBytes(template, "include", []string{"reasoning.encrypted_content"})
@@ -334,6 +337,19 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
return template
}
func normalizeCodexServiceTier(result gjson.Result) string {
if !result.Exists() || result.Type != gjson.String {
return ""
}
switch strings.ToLower(strings.TrimSpace(result.String())) {
case "fast", "priority":
return "priority"
default:
return ""
}
}
// shortenCodexCallIDIfNeeded keeps Claude tool IDs within the OpenAI Responses
// API call_id limit while preserving a stable, low-collision mapping.
func shortenCodexCallIDIfNeeded(id string) string {
@@ -148,6 +148,58 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) {
}
}
func TestConvertClaudeRequestToCodex_ServiceTier(t *testing.T) {
tests := []struct {
name string
serviceTierJSON string
want string
wantExists bool
}{
{
name: "Priority passes through",
serviceTierJSON: `"priority"`,
want: "priority",
wantExists: true,
},
{
name: "Fast normalizes to priority",
serviceTierJSON: `"fast"`,
want: "priority",
wantExists: true,
},
{
name: "Unsupported tier is omitted",
serviceTierJSON: `"default"`,
},
{
name: "Non-string tier is omitted",
serviceTierJSON: `true`,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
inputJSON := `{
"model": "gpt-5.4",
"service_tier": ` + tt.serviceTierJSON + `,
"messages": [{"role": "user", "content": "Reply with OK"}]
}`
result := ConvertClaudeRequestToCodex("gpt-5.4", []byte(inputJSON), false)
serviceTierResult := gjson.GetBytes(result, "service_tier")
if serviceTierResult.Exists() != tt.wantExists {
t.Fatalf("service_tier exists = %v, want %v. Output: %s", serviceTierResult.Exists(), tt.wantExists, string(result))
}
if !tt.wantExists {
return
}
if got := serviceTierResult.String(); got != tt.want {
t.Fatalf("service_tier = %q, want %q. Output: %s", got, tt.want, string(result))
}
})
}
}
func TestConvertClaudeRequestToCodex_ShortenLongToolUseIDs(t *testing.T) {
longID := "toolu_" + strings.Repeat("a", 62)
if len(longID) <= 64 {