Skip to content

Commit 6706e73

Browse files
authored
refactor: centralize runtime provider policy (#55)
* refactor: centralize runtime provider policy * test: isolate opencodego protocol map tests
1 parent b3c30a6 commit 6706e73

9 files changed

Lines changed: 240 additions & 159 deletions

File tree

catalog/opencodego/opencodego_test.go

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,9 @@ func TestProtocolForModel(t *testing.T) {
4848
}
4949

5050
func TestUsesMessagesAPI_HeuristicFallback(t *testing.T) {
51-
t.Parallel()
5251
// Reset map so we test the heuristic fallback.
5352
ResetProtocolMap()
53+
t.Cleanup(ResetProtocolMap)
5454
tests := []struct {
5555
model string
5656
want bool
@@ -75,8 +75,8 @@ func TestUsesMessagesAPI_HeuristicFallback(t *testing.T) {
7575
}
7676

7777
func TestUsesMessagesAPI_DynamicMapOverrides(t *testing.T) {
78-
t.Parallel()
7978
ResetProtocolMap()
79+
t.Cleanup(ResetProtocolMap)
8080
// Simulate live fetch returning protocol data.
8181
UpdateProtocolMap([]struct{ ID, Protocol string }{
8282
{"kimi-k2.6", "openai"},
@@ -100,13 +100,11 @@ func TestUsesMessagesAPI_DynamicMapOverrides(t *testing.T) {
100100
if UsesMessagesAPI("totally-new-model") {
101101
t.Error("totally-new-model should default to openai (heuristic fallback)")
102102
}
103-
104-
ResetProtocolMap()
105103
}
106104

107105
func TestProtocolMapSnapshot(t *testing.T) {
108-
t.Parallel()
109106
ResetProtocolMap()
107+
t.Cleanup(ResetProtocolMap)
110108
UpdateProtocolMap([]struct{ ID, Protocol string }{
111109
{"kimi-k2.6", "openai"},
112110
{"minimax-m3", "anthropic"},
@@ -118,7 +116,6 @@ func TestProtocolMapSnapshot(t *testing.T) {
118116
if snap["minimax-m3"] != "anthropic" {
119117
t.Errorf("snapshot minimax-m3 = %q, want anthropic", snap["minimax-m3"])
120118
}
121-
ResetProtocolMap()
122119
}
123120

124121
func TestUsageTracker_RecordAndSpend(t *testing.T) {

catalog/registry/derive.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,82 @@ func DisplayName(providerID string) string {
4646
return providerID
4747
}
4848

49+
// ChatProviderPreferenceOrder returns provider ids ordered by chat/runtime preference.
50+
func ChatProviderPreferenceOrder() []string {
51+
specs := DefaultRegistry.All()
52+
sort.Slice(specs, func(i, j int) bool {
53+
left := specs[i].ChatPreference
54+
right := specs[j].ChatPreference
55+
if left == 0 {
56+
left = specs[i].SortOrder + 10_000
57+
}
58+
if right == 0 {
59+
right = specs[j].SortOrder + 10_000
60+
}
61+
if left != right {
62+
return left < right
63+
}
64+
return specs[i].ProviderID < specs[j].ProviderID
65+
})
66+
out := make([]string, 0, len(specs))
67+
for _, spec := range specs {
68+
if spec.ProviderID != "" {
69+
out = append(out, spec.ProviderID)
70+
}
71+
}
72+
return out
73+
}
74+
75+
// RuntimeProfileKey returns the config runtime-profile key for a provider.
76+
func RuntimeProfileKey(providerID string) string {
77+
if spec, ok := SpecByProviderID(providerID); ok {
78+
return strings.TrimSpace(spec.RuntimeProfileKey)
79+
}
80+
return ""
81+
}
82+
83+
// DirectFallbackProviderIDs returns direct-provider fallback ids for providerID.
84+
func DirectFallbackProviderIDs(providerID string) []string {
85+
spec, ok := SpecByProviderID(providerID)
86+
if !ok || len(spec.DirectFallbacks) == 0 {
87+
return nil
88+
}
89+
out := make([]string, 0, len(spec.DirectFallbacks))
90+
for _, id := range spec.DirectFallbacks {
91+
if trimmed := strings.TrimSpace(id); trimmed != "" {
92+
out = append(out, trimmed)
93+
}
94+
}
95+
return out
96+
}
97+
98+
// CredentialAliases returns compatibility env var names for providerID.
99+
func CredentialAliases(providerID string) []string {
100+
spec, ok := SpecByProviderID(providerID)
101+
if !ok || len(spec.CredentialAliases) == 0 {
102+
return nil
103+
}
104+
out := make([]string, 0, len(spec.CredentialAliases))
105+
for _, env := range spec.CredentialAliases {
106+
if trimmed := strings.TrimSpace(env); trimmed != "" {
107+
out = append(out, trimmed)
108+
}
109+
}
110+
return out
111+
}
112+
113+
// CredentialEnvPreparedProviders returns providers that need config-derived env before discovery.
114+
func CredentialEnvPreparedProviders() []string {
115+
var out []string
116+
for _, spec := range DefaultRegistry.All() {
117+
if spec.PrepareCredentialEnv && spec.ProviderID != "" {
118+
out = append(out, spec.ProviderID)
119+
}
120+
}
121+
sort.Strings(out)
122+
return out
123+
}
124+
49125
// CredentialRegistry derives credential rows from provider specs.
50126
func CredentialRegistry() []CredentialSpec {
51127
specs := DefaultRegistry.All()

catalog/registry/provider_spec_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,44 @@ func TestOpenCodeGo_HasProbeBaseURL(t *testing.T) {
4646
}
4747
}
4848

49+
func TestProviderRuntimePolicy_Metadata(t *testing.T) {
50+
t.Parallel()
51+
52+
order := registry.ChatProviderPreferenceOrder()
53+
if len(order) < 3 {
54+
t.Fatalf("runtime preference order too short: %v", order)
55+
}
56+
if order[0] != "openai" || order[1] != "anthropic" || order[2] != "openrouter" {
57+
t.Fatalf("unexpected runtime preference prefix: %v", order[:3])
58+
}
59+
60+
if got := registry.DirectFallbackProviderIDs("openai"); len(got) != 1 || got[0] != "anthropic" {
61+
t.Fatalf("openai direct fallbacks = %v, want [anthropic]", got)
62+
}
63+
if got := registry.DirectFallbackProviderIDs("anthropic"); len(got) != 1 || got[0] != "openai" {
64+
t.Fatalf("anthropic direct fallbacks = %v, want [openai]", got)
65+
}
66+
67+
if got := registry.CredentialAliases("anthropic"); len(got) != 1 || got[0] != "CLAUDE_API_KEY" {
68+
t.Fatalf("anthropic credential aliases = %v", got)
69+
}
70+
71+
prepared := registry.CredentialEnvPreparedProviders()
72+
wantPrepared := map[string]bool{
73+
"xiaomi_mimo_token_plan": true,
74+
"zai_coding": true,
75+
"zai_payg": true,
76+
}
77+
if len(prepared) != len(wantPrepared) {
78+
t.Fatalf("prepared providers = %v", prepared)
79+
}
80+
for _, providerID := range prepared {
81+
if !wantPrepared[providerID] {
82+
t.Fatalf("unexpected prepared provider %q in %v", providerID, prepared)
83+
}
84+
}
85+
}
86+
4987
func TestProviderSpecs_TableDriven(t *testing.T) {
5088
t.Parallel()
5189
tests := []struct {

0 commit comments

Comments
 (0)