Skip to content

Commit 893412e

Browse files
committed
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: router-for-me#3276 router-for-me#3294
1 parent c020e2d commit 893412e

2 files changed

Lines changed: 68 additions & 0 deletions

File tree

internal/translator/codex/claude/codex_claude_request.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,13 +327,29 @@ func ConvertClaudeRequestToCodex(modelName string, inputRawJSON []byte, _ bool)
327327
}
328328
template, _ = sjson.SetBytes(template, "reasoning.effort", reasoningEffort)
329329
template, _ = sjson.SetBytes(template, "reasoning.summary", "auto")
330+
if serviceTier := normalizeCodexServiceTier(rootResult.Get("service_tier")); serviceTier != "" {
331+
template, _ = sjson.SetBytes(template, "service_tier", serviceTier)
332+
}
330333
template, _ = sjson.SetBytes(template, "stream", true)
331334
template, _ = sjson.SetBytes(template, "store", false)
332335
template, _ = sjson.SetBytes(template, "include", []string{"reasoning.encrypted_content"})
333336

334337
return template
335338
}
336339

340+
func normalizeCodexServiceTier(result gjson.Result) string {
341+
if !result.Exists() || result.Type != gjson.String {
342+
return ""
343+
}
344+
345+
switch strings.ToLower(strings.TrimSpace(result.String())) {
346+
case "fast", "priority":
347+
return "priority"
348+
default:
349+
return ""
350+
}
351+
}
352+
337353
// shortenCodexCallIDIfNeeded keeps Claude tool IDs within the OpenAI Responses
338354
// API call_id limit while preserving a stable, low-collision mapping.
339355
func shortenCodexCallIDIfNeeded(id string) string {

internal/translator/codex/claude/codex_claude_request_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,58 @@ func TestConvertClaudeRequestToCodex_ParallelToolCalls(t *testing.T) {
148148
}
149149
}
150150

151+
func TestConvertClaudeRequestToCodex_ServiceTier(t *testing.T) {
152+
tests := []struct {
153+
name string
154+
serviceTierJSON string
155+
want string
156+
wantExists bool
157+
}{
158+
{
159+
name: "Priority passes through",
160+
serviceTierJSON: `"priority"`,
161+
want: "priority",
162+
wantExists: true,
163+
},
164+
{
165+
name: "Fast normalizes to priority",
166+
serviceTierJSON: `"fast"`,
167+
want: "priority",
168+
wantExists: true,
169+
},
170+
{
171+
name: "Unsupported tier is omitted",
172+
serviceTierJSON: `"default"`,
173+
},
174+
{
175+
name: "Non-string tier is omitted",
176+
serviceTierJSON: `true`,
177+
},
178+
}
179+
180+
for _, tt := range tests {
181+
t.Run(tt.name, func(t *testing.T) {
182+
inputJSON := `{
183+
"model": "gpt-5.4",
184+
"service_tier": ` + tt.serviceTierJSON + `,
185+
"messages": [{"role": "user", "content": "Reply with OK"}]
186+
}`
187+
188+
result := ConvertClaudeRequestToCodex("gpt-5.4", []byte(inputJSON), false)
189+
serviceTierResult := gjson.GetBytes(result, "service_tier")
190+
if serviceTierResult.Exists() != tt.wantExists {
191+
t.Fatalf("service_tier exists = %v, want %v. Output: %s", serviceTierResult.Exists(), tt.wantExists, string(result))
192+
}
193+
if !tt.wantExists {
194+
return
195+
}
196+
if got := serviceTierResult.String(); got != tt.want {
197+
t.Fatalf("service_tier = %q, want %q. Output: %s", got, tt.want, string(result))
198+
}
199+
})
200+
}
201+
}
202+
151203
func TestConvertClaudeRequestToCodex_ShortenLongToolUseIDs(t *testing.T) {
152204
longID := "toolu_" + strings.Repeat("a", 62)
153205
if len(longID) <= 64 {

0 commit comments

Comments
 (0)