Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 35 additions & 29 deletions internal/extension/codex/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,40 @@ import (

// ModelInfo represents a model entry in the OpenAI /v1/models response.
type ModelInfo struct {
Slug string `json:"slug"`
DisplayName string `json:"display_name"`
Description string `json:"description,omitempty"`
DefaultReasoningLevel string `json:"default_reasoning_level,omitempty"`
SupportedReasoningLevels []ReasoningLevelPresetDTO `json:"supported_reasoning_levels"`
ShellType string `json:"shell_type"`
Visibility string `json:"visibility"`
SupportedInAPI bool `json:"supported_in_api"`
Priority int `json:"priority"`
AdditionalSpeedTiers []string `json:"additional_speed_tiers"`
AvailabilityNux *ModelAvailabilityNux `json:"availability_nux"`
Upgrade *ModelInfoUpgrade `json:"upgrade"`
BaseInstructions string `json:"base_instructions"`
SupportsReasoningSummaries bool `json:"supports_reasoning_summaries"`
DefaultReasoningSummary string `json:"default_reasoning_summary"`
SupportVerbosity bool `json:"support_verbosity"`
DefaultVerbosity *string `json:"default_verbosity"`
ApplyPatchToolType *string `json:"apply_patch_tool_type"`
WebSearchToolType string `json:"web_search_tool_type"`
TruncationPolicy TruncationPolicyConfig `json:"truncation_policy"`
SupportsParallelToolCalls bool `json:"supports_parallel_tool_calls"`
SupportsImageDetailOriginal bool `json:"supports_image_detail_original"`
ContextWindow *int `json:"context_window,omitempty"`
MaxContextWindow *int `json:"max_context_window,omitempty"`
AutoCompactTokenLimit *int `json:"auto_compact_token_limit,omitempty"`
EffectiveContextWindowPct int `json:"effective_context_window_percent"`
ExperimentalSupportedTools []string `json:"experimental_supported_tools"`
InputModalities []string `json:"input_modalities"`
SupportsSearchTool bool `json:"supports_search_tool"`
Slug string `json:"slug"`
DisplayName string `json:"display_name"`
Description string `json:"description,omitempty"`
DefaultReasoningLevel string `json:"default_reasoning_level,omitempty"`
SupportedReasoningLevels []ReasoningLevelPresetDTO `json:"supported_reasoning_levels"`
ShellType string `json:"shell_type"`
Visibility string `json:"visibility"`
SupportedInAPI bool `json:"supported_in_api"`
Priority int `json:"priority"`
// AutoReviewModelOverride points Codex's automatic approval reviewer at a
// model the bridge actually serves. Without it Codex falls back to its
// built-in "codex-auto-review" id, which Moon Bridge does not route, so
// every approval review fails closed.
AutoReviewModelOverride string `json:"auto_review_model_override"`
AdditionalSpeedTiers []string `json:"additional_speed_tiers"`
AvailabilityNux *ModelAvailabilityNux `json:"availability_nux"`
Upgrade *ModelInfoUpgrade `json:"upgrade"`
BaseInstructions string `json:"base_instructions"`
SupportsReasoningSummaries bool `json:"supports_reasoning_summaries"`
DefaultReasoningSummary string `json:"default_reasoning_summary"`
SupportVerbosity bool `json:"support_verbosity"`
DefaultVerbosity *string `json:"default_verbosity"`
ApplyPatchToolType *string `json:"apply_patch_tool_type"`
WebSearchToolType string `json:"web_search_tool_type"`
TruncationPolicy TruncationPolicyConfig `json:"truncation_policy"`
SupportsParallelToolCalls bool `json:"supports_parallel_tool_calls"`
SupportsImageDetailOriginal bool `json:"supports_image_detail_original"`
ContextWindow *int `json:"context_window,omitempty"`
MaxContextWindow *int `json:"max_context_window,omitempty"`
AutoCompactTokenLimit *int `json:"auto_compact_token_limit,omitempty"`
EffectiveContextWindowPct int `json:"effective_context_window_percent"`
ExperimentalSupportedTools []string `json:"experimental_supported_tools"`
InputModalities []string `json:"input_modalities"`
SupportsSearchTool bool `json:"supports_search_tool"`
}

// ModelAvailabilityNux is a placeholder for Codex model availability nux.
Expand Down Expand Up @@ -425,6 +430,7 @@ func newModelInfo(
Visibility: "list",
SupportedInAPI: true,
Priority: 0,
AutoReviewModelOverride: slug,
AdditionalSpeedTiers: []string{},
BaseInstructions: baseInstructions,
SupportsReasoningSummaries: supportsReasoningSummaries,
Expand Down
13 changes: 13 additions & 0 deletions internal/extension/codex/catalog_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,15 @@ func TestBuildModelInfoFromRouteEnablesApplyPatchFreeform(t *testing.T) {
}
}

func TestBuildModelInfoFromRouteSetsAutoReviewModelOverride(t *testing.T) {
info := codex.BuildModelInfoFromRoute("gpt-test", "default", config.RouteEntry{
ContextWindow: 100000,
})
if info.AutoReviewModelOverride != info.Slug {
t.Fatalf("auto_review_model_override = %q, want slug %q", info.AutoReviewModelOverride, info.Slug)
}
}

func TestBuildModelInfoFromRouteUsesTokenTruncationPolicy(t *testing.T) {
info := codex.BuildModelInfoFromRoute("gpt-5.2", "default", config.RouteEntry{
ContextWindow: 200000,
Expand Down Expand Up @@ -463,6 +472,10 @@ func TestWriteModelsCatalogProducesValidJSON(t *testing.T) {
if len(result.Models) == 0 {
t.Fatal("expected at least 1 model in catalog")
}
if result.Models[0].AutoReviewModelOverride != result.Models[0].Slug {
t.Fatalf("auto_review_model_override = %q, want slug %q",
result.Models[0].AutoReviewModelOverride, result.Models[0].Slug)
}
}

func TestGenerateConfigTomlCatalogIncludesVisualInjectedImageModality(t *testing.T) {
Expand Down