Skip to content

Commit 30d5c95

Browse files
committed
feat(registry): refresh model catalog from network
1 parent d1e3195 commit 30d5c95

File tree

5 files changed

+2948
-1586
lines changed

5 files changed

+2948
-1586
lines changed

cmd/server/main.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/router-for-me/CLIProxyAPI/v6/internal/logging"
2525
"github.com/router-for-me/CLIProxyAPI/v6/internal/managementasset"
2626
"github.com/router-for-me/CLIProxyAPI/v6/internal/misc"
27+
"github.com/router-for-me/CLIProxyAPI/v6/internal/registry"
2728
"github.com/router-for-me/CLIProxyAPI/v6/internal/store"
2829
_ "github.com/router-for-me/CLIProxyAPI/v6/internal/translator"
2930
"github.com/router-for-me/CLIProxyAPI/v6/internal/tui"
@@ -494,6 +495,7 @@ func main() {
494495
if standalone {
495496
// Standalone mode: start an embedded local server and connect TUI client to it.
496497
managementasset.StartAutoUpdater(context.Background(), configFilePath)
498+
registry.StartModelsUpdater(context.Background())
497499
hook := tui.NewLogHook(2000)
498500
hook.SetFormatter(&logging.LogFormatter{})
499501
log.AddHook(hook)
@@ -566,6 +568,7 @@ func main() {
566568
} else {
567569
// Start the main proxy service
568570
managementasset.StartAutoUpdater(context.Background(), configFilePath)
571+
registry.StartModelsUpdater(context.Background())
569572
cmd.StartService(cfg, configFilePath, password)
570573
}
571574
}

internal/registry/model_definitions.go

Lines changed: 138 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,137 @@
11
// Package registry provides model definitions and lookup helpers for various AI providers.
2-
// Static model metadata is stored in model_definitions_static_data.go.
2+
// Static model metadata is loaded from the embedded models.json file and can be refreshed from network.
33
package registry
44

55
import (
66
"sort"
77
"strings"
88
)
99

10+
// AntigravityModelConfig captures static antigravity model overrides, including
11+
// Thinking budget limits and provider max completion tokens.
12+
type AntigravityModelConfig struct {
13+
Thinking *ThinkingSupport `json:"thinking,omitempty"`
14+
MaxCompletionTokens int `json:"max_completion_tokens,omitempty"`
15+
}
16+
17+
// staticModelsJSON mirrors the top-level structure of models.json.
18+
type staticModelsJSON struct {
19+
Claude []*ModelInfo `json:"claude"`
20+
Gemini []*ModelInfo `json:"gemini"`
21+
Vertex []*ModelInfo `json:"vertex"`
22+
GeminiCLI []*ModelInfo `json:"gemini-cli"`
23+
AIStudio []*ModelInfo `json:"aistudio"`
24+
CodexFree []*ModelInfo `json:"codex-free"`
25+
CodexTeam []*ModelInfo `json:"codex-team"`
26+
CodexPlus []*ModelInfo `json:"codex-plus"`
27+
CodexPro []*ModelInfo `json:"codex-pro"`
28+
Qwen []*ModelInfo `json:"qwen"`
29+
IFlow []*ModelInfo `json:"iflow"`
30+
Kimi []*ModelInfo `json:"kimi"`
31+
Antigravity map[string]*AntigravityModelConfig `json:"antigravity"`
32+
}
33+
34+
// GetClaudeModels returns the standard Claude model definitions.
35+
func GetClaudeModels() []*ModelInfo {
36+
return cloneModelInfos(getModels().Claude)
37+
}
38+
39+
// GetGeminiModels returns the standard Gemini model definitions.
40+
func GetGeminiModels() []*ModelInfo {
41+
return cloneModelInfos(getModels().Gemini)
42+
}
43+
44+
// GetGeminiVertexModels returns Gemini model definitions for Vertex AI.
45+
func GetGeminiVertexModels() []*ModelInfo {
46+
return cloneModelInfos(getModels().Vertex)
47+
}
48+
49+
// GetGeminiCLIModels returns Gemini model definitions for the Gemini CLI.
50+
func GetGeminiCLIModels() []*ModelInfo {
51+
return cloneModelInfos(getModels().GeminiCLI)
52+
}
53+
54+
// GetAIStudioModels returns model definitions for AI Studio.
55+
func GetAIStudioModels() []*ModelInfo {
56+
return cloneModelInfos(getModels().AIStudio)
57+
}
58+
59+
// GetCodexFreeModels returns model definitions for the Codex free plan tier.
60+
func GetCodexFreeModels() []*ModelInfo {
61+
return cloneModelInfos(getModels().CodexFree)
62+
}
63+
64+
// GetCodexTeamModels returns model definitions for the Codex team plan tier.
65+
func GetCodexTeamModels() []*ModelInfo {
66+
return cloneModelInfos(getModels().CodexTeam)
67+
}
68+
69+
// GetCodexPlusModels returns model definitions for the Codex plus plan tier.
70+
func GetCodexPlusModels() []*ModelInfo {
71+
return cloneModelInfos(getModels().CodexPlus)
72+
}
73+
74+
// GetCodexProModels returns model definitions for the Codex pro plan tier.
75+
func GetCodexProModels() []*ModelInfo {
76+
return cloneModelInfos(getModels().CodexPro)
77+
}
78+
79+
// GetQwenModels returns the standard Qwen model definitions.
80+
func GetQwenModels() []*ModelInfo {
81+
return cloneModelInfos(getModels().Qwen)
82+
}
83+
84+
// GetIFlowModels returns the standard iFlow model definitions.
85+
func GetIFlowModels() []*ModelInfo {
86+
return cloneModelInfos(getModels().IFlow)
87+
}
88+
89+
// GetKimiModels returns the standard Kimi (Moonshot AI) model definitions.
90+
func GetKimiModels() []*ModelInfo {
91+
return cloneModelInfos(getModels().Kimi)
92+
}
93+
94+
// GetAntigravityModelConfig returns static configuration for antigravity models.
95+
// Keys use upstream model names returned by the Antigravity models endpoint.
96+
func GetAntigravityModelConfig() map[string]*AntigravityModelConfig {
97+
data := getModels()
98+
if len(data.Antigravity) == 0 {
99+
return nil
100+
}
101+
out := make(map[string]*AntigravityModelConfig, len(data.Antigravity))
102+
for k, v := range data.Antigravity {
103+
out[k] = cloneAntigravityModelConfig(v)
104+
}
105+
return out
106+
}
107+
108+
func cloneAntigravityModelConfig(cfg *AntigravityModelConfig) *AntigravityModelConfig {
109+
if cfg == nil {
110+
return nil
111+
}
112+
copyConfig := *cfg
113+
if cfg.Thinking != nil {
114+
copyThinking := *cfg.Thinking
115+
if len(cfg.Thinking.Levels) > 0 {
116+
copyThinking.Levels = append([]string(nil), cfg.Thinking.Levels...)
117+
}
118+
copyConfig.Thinking = &copyThinking
119+
}
120+
return &copyConfig
121+
}
122+
123+
// cloneModelInfos returns a shallow copy of the slice with each element deep-cloned.
124+
func cloneModelInfos(models []*ModelInfo) []*ModelInfo {
125+
if len(models) == 0 {
126+
return nil
127+
}
128+
out := make([]*ModelInfo, len(models))
129+
for i, m := range models {
130+
out[i] = cloneModelInfo(m)
131+
}
132+
return out
133+
}
134+
10135
// GetStaticModelDefinitionsByChannel returns static model definitions for a given channel/provider.
11136
// It returns nil when the channel is unknown.
12137
//
@@ -77,27 +202,28 @@ func LookupStaticModelInfo(modelID string) *ModelInfo {
77202
return nil
78203
}
79204

205+
data := getModels()
80206
allModels := [][]*ModelInfo{
81-
GetClaudeModels(),
82-
GetGeminiModels(),
83-
GetGeminiVertexModels(),
84-
GetGeminiCLIModels(),
85-
GetAIStudioModels(),
86-
GetCodexProModels(),
87-
GetQwenModels(),
88-
GetIFlowModels(),
89-
GetKimiModels(),
207+
data.Claude,
208+
data.Gemini,
209+
data.Vertex,
210+
data.GeminiCLI,
211+
data.AIStudio,
212+
data.CodexPro,
213+
data.Qwen,
214+
data.IFlow,
215+
data.Kimi,
90216
}
91217
for _, models := range allModels {
92218
for _, m := range models {
93219
if m != nil && m.ID == modelID {
94-
return m
220+
return cloneModelInfo(m)
95221
}
96222
}
97223
}
98224

99225
// Check Antigravity static config
100-
if cfg := GetAntigravityModelConfig()[modelID]; cfg != nil {
226+
if cfg := cloneAntigravityModelConfig(data.Antigravity[modelID]); cfg != nil {
101227
return &ModelInfo{
102228
ID: modelID,
103229
Thinking: cfg.Thinking,

0 commit comments

Comments
 (0)