mirror of
https://github.com/router-for-me/CLIProxyAPI.git
synced 2026-05-31 20:02:36 +08:00
feat(models): expand supported reasoning levels for Codex
- Added new reasoning levels: `none`, `minimal`, and `unsupported` to Codex model configurations. - Introduced metadata sanitization and normalization for reasoning levels in API response. - Extended unit tests to cover reasoning levels validation and metadata sanitation logic.
This commit is contained in:
@@ -263,7 +263,7 @@ func TestModelsWithClientVersionReturnsCodexCatalog(t *testing.T) {
|
||||
DisplayName: "Custom Codex Model",
|
||||
Description: "Custom model from registry",
|
||||
ContextLength: 123456,
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"low", "medium"}},
|
||||
Thinking: ®istry.ThinkingSupport{Levels: []string{"none", "minimal", "low", "medium", "unsupported", "high", "xhigh"}},
|
||||
},
|
||||
{ID: "grok-imagine-image-quality", Object: "model", OwnedBy: "xai", Type: "openai"},
|
||||
{ID: "gpt-image-2", Object: "model", OwnedBy: "openai", Type: "openai"},
|
||||
@@ -334,6 +334,7 @@ func TestModelsWithClientVersionReturnsCodexCatalog(t *testing.T) {
|
||||
if got, _ := custom["context_window"].(float64); got != 123456 {
|
||||
t.Fatalf("custom context_window = %v, want 123456", custom["context_window"])
|
||||
}
|
||||
assertCodexSupportedReasoningLevels(t, custom, []string{"none", "low", "medium", "high", "xhigh"})
|
||||
if custom["base_instructions"] != gpt55["base_instructions"] {
|
||||
t.Fatal("expected custom model to use gpt-5.5 base_instructions fallback")
|
||||
}
|
||||
@@ -376,6 +377,27 @@ func TestModelsWithClientVersionReturnsCodexCatalog(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func assertCodexSupportedReasoningLevels(t *testing.T, model map[string]any, want []string) {
|
||||
t.Helper()
|
||||
|
||||
rawLevels, ok := model["supported_reasoning_levels"].([]any)
|
||||
if !ok {
|
||||
t.Fatalf("expected supported_reasoning_levels, got %#v", model["supported_reasoning_levels"])
|
||||
}
|
||||
if len(rawLevels) != len(want) {
|
||||
t.Fatalf("supported_reasoning_levels length = %d, want %d: %#v", len(rawLevels), len(want), rawLevels)
|
||||
}
|
||||
for index, rawLevel := range rawLevels {
|
||||
levelEntry, ok := rawLevel.(map[string]any)
|
||||
if !ok {
|
||||
t.Fatalf("supported_reasoning_levels[%d] = %#v, want object", index, rawLevel)
|
||||
}
|
||||
if got, _ := levelEntry["effort"].(string); got != want[index] {
|
||||
t.Fatalf("supported_reasoning_levels[%d].effort = %q, want %q", index, got, want[index])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDefaultRequestLoggerFactory_UsesResolvedLogDirectory(t *testing.T) {
|
||||
t.Setenv("WRITABLE_PATH", "")
|
||||
t.Setenv("writable_path", "")
|
||||
|
||||
@@ -20,6 +20,14 @@ var (
|
||||
codexClientModelTemplatesErr error
|
||||
)
|
||||
|
||||
var codexClientAllowedReasoningLevels = map[string]struct{}{
|
||||
"none": {},
|
||||
"low": {},
|
||||
"medium": {},
|
||||
"high": {},
|
||||
"xhigh": {},
|
||||
}
|
||||
|
||||
func (h *OpenAIAPIHandler) codexClientModelsResponse() map[string]any {
|
||||
return CodexClientModelsResponse(h.Models())
|
||||
}
|
||||
@@ -45,6 +53,7 @@ func buildCodexClientModels(models []map[string]any) []map[string]any {
|
||||
|
||||
if template, ok := templates[id]; ok {
|
||||
entry := cloneCodexClientModelMap(template)
|
||||
sanitizeCodexClientReasoningMetadata(entry)
|
||||
applyCodexClientVisibilityOverride(entry, id)
|
||||
result = append(result, entry)
|
||||
continue
|
||||
@@ -52,6 +61,7 @@ func buildCodexClientModels(models []map[string]any) []map[string]any {
|
||||
|
||||
entry := cloneCodexClientModelMap(defaultTemplate)
|
||||
applyCodexClientModelMetadata(entry, id, model)
|
||||
sanitizeCodexClientReasoningMetadata(entry)
|
||||
applyCodexClientVisibilityOverride(entry, id)
|
||||
result = append(result, entry)
|
||||
}
|
||||
@@ -153,12 +163,16 @@ func applyCodexClientThinkingMetadata(entry map[string]any, thinking *registry.T
|
||||
|
||||
levels := make([]any, 0, len(thinking.Levels))
|
||||
defaultLevel := ""
|
||||
firstLevel := ""
|
||||
for _, rawLevel := range thinking.Levels {
|
||||
level := strings.ToLower(strings.TrimSpace(rawLevel))
|
||||
if level == "" || level == "none" {
|
||||
level := normalizeCodexClientReasoningLevel(rawLevel)
|
||||
if level == "" {
|
||||
continue
|
||||
}
|
||||
if defaultLevel == "" || level == "medium" {
|
||||
if firstLevel == "" {
|
||||
firstLevel = level
|
||||
}
|
||||
if (defaultLevel == "" && level != "none") || level == "medium" {
|
||||
defaultLevel = level
|
||||
}
|
||||
levels = append(levels, map[string]any{
|
||||
@@ -169,15 +183,64 @@ func applyCodexClientThinkingMetadata(entry map[string]any, thinking *registry.T
|
||||
if len(levels) == 0 {
|
||||
return
|
||||
}
|
||||
if defaultLevel == "" {
|
||||
defaultLevel = firstLevel
|
||||
}
|
||||
|
||||
entry["supported_reasoning_levels"] = levels
|
||||
entry["default_reasoning_level"] = defaultLevel
|
||||
}
|
||||
|
||||
func sanitizeCodexClientReasoningMetadata(entry map[string]any) {
|
||||
rawLevels, ok := entry["supported_reasoning_levels"].([]any)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
levels := make([]any, 0, len(rawLevels))
|
||||
allowedDefaults := make(map[string]struct{}, len(rawLevels))
|
||||
for _, rawLevelEntry := range rawLevels {
|
||||
levelEntry, ok := rawLevelEntry.(map[string]any)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
level := normalizeCodexClientReasoningLevel(stringModelValue(levelEntry, "effort"))
|
||||
if level == "" {
|
||||
continue
|
||||
}
|
||||
clonedEntry := cloneCodexClientModelMap(levelEntry)
|
||||
clonedEntry["effort"] = level
|
||||
levels = append(levels, clonedEntry)
|
||||
allowedDefaults[level] = struct{}{}
|
||||
}
|
||||
|
||||
if len(levels) == 0 {
|
||||
delete(entry, "supported_reasoning_levels")
|
||||
delete(entry, "default_reasoning_level")
|
||||
return
|
||||
}
|
||||
|
||||
defaultLevel := normalizeCodexClientReasoningLevel(stringModelValue(entry, "default_reasoning_level"))
|
||||
if _, ok := allowedDefaults[defaultLevel]; !ok {
|
||||
defaultLevel = stringModelValue(levels[0].(map[string]any), "effort")
|
||||
}
|
||||
|
||||
entry["supported_reasoning_levels"] = levels
|
||||
entry["default_reasoning_level"] = defaultLevel
|
||||
}
|
||||
|
||||
func normalizeCodexClientReasoningLevel(rawLevel string) string {
|
||||
level := strings.ToLower(strings.TrimSpace(rawLevel))
|
||||
if _, ok := codexClientAllowedReasoningLevels[level]; !ok {
|
||||
return ""
|
||||
}
|
||||
return level
|
||||
}
|
||||
|
||||
func codexClientReasoningDescription(level string) string {
|
||||
switch level {
|
||||
case "minimal":
|
||||
return "Fastest responses with minimal reasoning"
|
||||
case "none":
|
||||
return "No reasoning"
|
||||
case "low":
|
||||
return "Fast responses with lighter reasoning"
|
||||
case "medium":
|
||||
|
||||
Reference in New Issue
Block a user