diff --git a/README.fr.md b/README.fr.md index 61d18792b..c442ffc63 100644 --- a/README.fr.md +++ b/README.fr.md @@ -833,8 +833,8 @@ Cette conception permet également le **support multi-agent** avec une sélectio { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -850,7 +850,7 @@ Cette conception permet également le **support multi-agent** avec une sélectio ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -861,8 +861,8 @@ Cette conception permet également le **support multi-agent** avec une sélectio **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -894,14 +894,14 @@ Configurez plusieurs points de terminaison pour le même nom de modèle—PicoCl { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/README.ja.md b/README.ja.md index c2a88b90c..bcc821703 100644 --- a/README.ja.md +++ b/README.ja.md @@ -769,8 +769,8 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -786,7 +786,7 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -797,8 +797,8 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -830,14 +830,14 @@ HEARTBEAT_OK 応答 ユーザーが直接結果を受け取る { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/README.md b/README.md index 4b4756dd9..b6379a999 100644 --- a/README.md +++ b/README.md @@ -218,7 +218,7 @@ picoclaw onboard "model_list": [ { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "your-api-key" }, { @@ -728,8 +728,8 @@ This design also enables **multi-agent support** with flexible provider selectio { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -745,7 +745,7 @@ This design also enables **multi-agent support** with flexible provider selectio ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -756,8 +756,8 @@ This design also enables **multi-agent support** with flexible provider selectio **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -816,14 +816,14 @@ Configure multiple endpoints for the same model name—PicoClaw will automatical { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/README.pt-br.md b/README.pt-br.md index fbb79bb96..47efc3d58 100644 --- a/README.pt-br.md +++ b/README.pt-br.md @@ -834,8 +834,8 @@ Este design também possibilita o **suporte multi-agent** com seleção flexíve { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -851,7 +851,7 @@ Este design também possibilita o **suporte multi-agent** com seleção flexíve ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -862,8 +862,8 @@ Este design também possibilita o **suporte multi-agent** com seleção flexíve **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -895,14 +895,14 @@ Configure vários endpoints para o mesmo nome de modelo—PicoClaw fará round-r { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/README.vi.md b/README.vi.md index eacf3917e..7e5ac5abc 100644 --- a/README.vi.md +++ b/README.vi.md @@ -811,8 +811,8 @@ Thiết kế này cũng cho phép **hỗ trợ đa tác nhân** với lựa ch { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -828,7 +828,7 @@ Thiết kế này cũng cho phép **hỗ trợ đa tác nhân** với lựa ch ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -839,8 +839,8 @@ Thiết kế này cũng cho phép **hỗ trợ đa tác nhân** với lựa ch **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -872,14 +872,14 @@ Thiết kế này cũng cho phép **hỗ trợ đa tác nhân** với lựa ch { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/README.zh.md b/README.zh.md index 49ff92da3..1030fde49 100644 --- a/README.zh.md +++ b/README.zh.md @@ -227,7 +227,7 @@ picoclaw onboard "model_list": [ { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "your-api-key" }, { @@ -605,8 +605,8 @@ Agent 读取 HEARTBEAT.md { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key" }, { @@ -622,7 +622,7 @@ Agent 读取 HEARTBEAT.md ], "agents": { "defaults": { - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -633,8 +633,8 @@ Agent 读取 HEARTBEAT.md **OpenAI** ```json { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-..." } ``` @@ -693,14 +693,14 @@ Agent 读取 HEARTBEAT.md { "model_list": [ { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api1.example.com/v1", "api_key": "sk-key1" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_base": "https://api2.example.com/v1", "api_key": "sk-key2" } diff --git a/cmd/picoclaw/cmd_auth.go b/cmd/picoclaw/cmd_auth.go index b144fe21d..e7c3f14fc 100644 --- a/cmd/picoclaw/cmd_auth.go +++ b/cmd/picoclaw/cmd_auth.go @@ -9,6 +9,7 @@ import ( "io" "net/http" "os" + "strings" "time" "github.com/sipeed/picoclaw/pkg/auth" @@ -118,7 +119,31 @@ func authLoginOpenAI(useDeviceCode bool) { appCfg, err := loadConfig() if err == nil { + // Update Providers (legacy format) appCfg.Providers.OpenAI.AuthMethod = "oauth" + + // Update or add openai in ModelList + foundOpenAI := false + for i := range appCfg.ModelList { + if isOpenAIModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "oauth" + foundOpenAI = true + break + } + } + + // If no openai in ModelList, add it + if !foundOpenAI { + appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{ + ModelName: "gpt-5.2", + Model: "openai/gpt-5.2", + AuthMethod: "oauth", + }) + } + + // Update default model to use OpenAI + appCfg.Agents.Defaults.Model = "gpt-5.2" + if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) } @@ -128,6 +153,7 @@ func authLoginOpenAI(useDeviceCode bool) { if cred.AccountID != "" { fmt.Printf("Account: %s\n", cred.AccountID) } + fmt.Println("Default model set to: gpt-5.2") } func authLoginGoogleAntigravity() { @@ -167,20 +193,38 @@ func authLoginGoogleAntigravity() { appCfg, err := loadConfig() if err == nil { + // Update Providers (legacy format, for backward compatibility) appCfg.Providers.Antigravity.AuthMethod = "oauth" - if appCfg.Agents.Defaults.Provider == "" { - appCfg.Agents.Defaults.Provider = "antigravity" + + // Update or add antigravity in ModelList + foundAntigravity := false + for i := range appCfg.ModelList { + if isAntigravityModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "oauth" + foundAntigravity = true + break + } } - if appCfg.Agents.Defaults.Provider == "antigravity" || appCfg.Agents.Defaults.Provider == "google-antigravity" { - appCfg.Agents.Defaults.Model = "gemini-3-flash" + + // If no antigravity in ModelList, add it + if !foundAntigravity { + appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{ + ModelName: "gemini-flash", + Model: "antigravity/gemini-3-flash", + AuthMethod: "oauth", + }) } + + // Update default model + appCfg.Agents.Defaults.Model = "gemini-flash" + if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) } } fmt.Println("\n✓ Google Antigravity login successful!") - fmt.Println("Config updated: provider=antigravity, model=gemini-3-flash") + fmt.Println("Default model set to: gemini-flash") fmt.Println("Try it: picoclaw agent -m \"Hello world\"") } @@ -229,8 +273,44 @@ func authLoginPasteToken(provider string) { switch provider { case "anthropic": appCfg.Providers.Anthropic.AuthMethod = "token" + // Update ModelList + found := false + for i := range appCfg.ModelList { + if isAnthropicModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "token" + found = true + break + } + } + if !found { + appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{ + ModelName: "claude-sonnet-4", + Model: "anthropic/claude-sonnet-4-20250514", + AuthMethod: "token", + }) + } + // Update default model + appCfg.Agents.Defaults.Model = "claude-sonnet-4" case "openai": appCfg.Providers.OpenAI.AuthMethod = "token" + // Update ModelList + found := false + for i := range appCfg.ModelList { + if isOpenAIModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "token" + found = true + break + } + } + if !found { + appCfg.ModelList = append(appCfg.ModelList, config.ModelConfig{ + ModelName: "gpt-5.2", + Model: "openai/gpt-5.2", + AuthMethod: "token", + }) + } + // Update default model + appCfg.Agents.Defaults.Model = "gpt-5.2" } if err := config.SaveConfig(getConfigPath(), appCfg); err != nil { fmt.Printf("Warning: could not update config: %v\n", err) @@ -238,6 +318,7 @@ func authLoginPasteToken(provider string) { } fmt.Printf("Token saved for %s!\n", provider) + fmt.Printf("Default model set to: %s\n", appCfg.Agents.Defaults.Model) } func authLogoutCmd() { @@ -262,6 +343,24 @@ func authLogoutCmd() { appCfg, err := loadConfig() if err == nil { + // Clear AuthMethod in ModelList + for i := range appCfg.ModelList { + switch provider { + case "openai": + if isOpenAIModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "" + } + case "anthropic": + if isAnthropicModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "" + } + case "google-antigravity", "antigravity": + if isAntigravityModel(appCfg.ModelList[i].Model) { + appCfg.ModelList[i].AuthMethod = "" + } + } + } + // Clear AuthMethod in Providers (legacy) switch provider { case "openai": appCfg.Providers.OpenAI.AuthMethod = "" @@ -282,6 +381,11 @@ func authLogoutCmd() { appCfg, err := loadConfig() if err == nil { + // Clear all AuthMethods in ModelList + for i := range appCfg.ModelList { + appCfg.ModelList[i].AuthMethod = "" + } + // Clear all AuthMethods in Providers (legacy) appCfg.Providers.OpenAI.AuthMethod = "" appCfg.Providers.Anthropic.AuthMethod = "" appCfg.Providers.Antigravity.AuthMethod = "" @@ -384,3 +488,23 @@ func authModelsCmd() { fmt.Printf(" %s %s\n", status, name) } } + +// isAntigravityModel checks if a model string belongs to antigravity provider +func isAntigravityModel(model string) bool { + return model == "antigravity" || + model == "google-antigravity" || + strings.HasPrefix(model, "antigravity/") || + strings.HasPrefix(model, "google-antigravity/") +} + +// isOpenAIModel checks if a model string belongs to openai provider +func isOpenAIModel(model string) bool { + return model == "openai" || + strings.HasPrefix(model, "openai/") +} + +// isAnthropicModel checks if a model string belongs to anthropic provider +func isAnthropicModel(model string) bool { + return model == "anthropic" || + strings.HasPrefix(model, "anthropic/") +} diff --git a/config/config.example.json b/config/config.example.json index fb970d0be..49de07c96 100644 --- a/config/config.example.json +++ b/config/config.example.json @@ -12,7 +12,7 @@ "model_list": [ { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", "api_base": "https://api.openai.com/v1" }, @@ -34,13 +34,13 @@ }, { "model_name": "loadbalanced-gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-key1", "api_base": "https://api1.example.com/v1" }, { "model_name": "loadbalanced-gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-key2", "api_base": "https://api2.example.com/v1" } diff --git a/docs/design/provider-refactoring.md b/docs/design/provider-refactoring.md index ae60b89a1..91df87f34 100644 --- a/docs/design/provider-refactoring.md +++ b/docs/design/provider-refactoring.md @@ -66,7 +66,7 @@ Problem: Agent needs to know both `provider` and `model`, adding complexity. Inspired by [LiteLLM](https://docs.litellm.ai/docs/proxy/configs) design: 1. **Model-centric**: Users care about models, not providers -2. **Protocol prefix**: Use `protocol/model_name` format, e.g., `openai/gpt-4o`, `anthropic/claude-3-sonnet` +2. **Protocol prefix**: Use `protocol/model_name` format, e.g., `openai/gpt-5.2`, `anthropic/claude-3-sonnet` 3. **Configuration-driven**: Adding new Providers only requires config changes, no code changes ### 2.2 New Configuration Structure @@ -81,8 +81,8 @@ Inspired by [LiteLLM](https://docs.litellm.ai/docs/proxy/configs) design: "api_key": "sk-xxx" }, { - "model_name": "gpt-4o", - "model": "openai/gpt-4o", + "model_name": "gpt-5.2", + "model": "openai/gpt-5.2", "api_key": "sk-xxx" }, { @@ -128,7 +128,7 @@ type Config struct { type ModelConfig struct { // Required ModelName string `json:"model_name"` // user-facing name (alias) - Model string `json:"model"` // protocol/model, e.g., openai/gpt-4o + Model string `json:"model"` // protocol/model, e.g., openai/gpt-5.2 // Common config APIBase string `json:"api_base,omitempty"` @@ -180,7 +180,7 @@ Identify protocol via prefix in `model` field: "model": "deepseek-chat" }, "coder": { - "model": "gpt-4o", + "model": "gpt-5.2", "system_prompt": "You are a coding assistant..." }, "translator": { @@ -200,7 +200,7 @@ Each Agent only needs to specify `model` (corresponds to `model_name` in `model_ model_list: - model_name: gpt-4o litellm_params: - model: openai/gpt-4o + model: openai/gpt-5.2 api_key: xxx - model_name: my-custom litellm_params: diff --git a/docs/migration/model-list-migration.md b/docs/migration/model-list-migration.md index 160fbb209..3e4140357 100644 --- a/docs/migration/model-list-migration.md +++ b/docs/migration/model-list-migration.md @@ -40,7 +40,7 @@ The new `model_list` configuration offers several advantages: "agents": { "defaults": { "provider": "openai", - "model": "gpt-4o" + "model": "gpt-5.2" } } } @@ -53,7 +53,7 @@ The new `model_list` configuration offers several advantages: "model_list": [ { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-your-openai-key", "api_base": "https://api.openai.com/v1" }, @@ -82,7 +82,7 @@ The `model` field uses a protocol prefix format: `[protocol/]model-identifier` | Prefix | Description | Example | |--------|-------------|---------| -| `openai/` | OpenAI API (default) | `openai/gpt-4o` | +| `openai/` | OpenAI API (default) | `openai/gpt-5.2` | | `anthropic/` | Anthropic API | `anthropic/claude-3-opus` | | `antigravity/` | Google via Antigravity OAuth | `antigravity/gemini-2.0-flash` | | `claude-cli/` | Claude CLI (local) | `claude-cli/claude-3-sonnet` | @@ -101,7 +101,7 @@ The `model` field uses a protocol prefix format: `[protocol/]model-identifier` | Field | Required | Description | |-------|----------|-------------| | `model_name` | Yes | User-facing alias for the model | -| `model` | Yes | Protocol and model identifier (e.g., `openai/gpt-4o`) | +| `model` | Yes | Protocol and model identifier (e.g., `openai/gpt-5.2`) | | `api_base` | No | API endpoint URL | | `api_key` | No* | API authentication key | | `proxy` | No | HTTP proxy URL | @@ -121,19 +121,19 @@ Configure multiple endpoints for the same model to distribute load: "model_list": [ { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-key1", "api_base": "https://api1.example.com/v1" }, { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-key2", "api_base": "https://api2.example.com/v1" }, { "model_name": "gpt4", - "model": "openai/gpt-4o", + "model": "openai/gpt-5.2", "api_key": "sk-key3", "api_base": "https://api3.example.com/v1" } diff --git a/pkg/config/defaults.go b/pkg/config/defaults.go index 174cc70c6..b3102a446 100644 --- a/pkg/config/defaults.go +++ b/pkg/config/defaults.go @@ -105,8 +105,8 @@ func DefaultConfig() *Config { // OpenAI - https://platform.openai.com/api-keys { - ModelName: "gpt-4o", - Model: "openai/gpt-4o", + ModelName: "gpt-5.2", + Model: "openai/gpt-5.2", APIBase: "https://api.openai.com/v1", APIKey: "", }, @@ -161,8 +161,8 @@ func DefaultConfig() *Config { // OpenRouter (100+ models) - https://openrouter.ai/keys { - ModelName: "openrouter-gpt-4o", - Model: "openrouter/openai/gpt-4o", + ModelName: "openrouter-gpt-5.2", + Model: "openrouter/openai/gpt-5.2", APIBase: "https://openrouter.ai/api/v1", APIKey: "", }, @@ -208,8 +208,8 @@ func DefaultConfig() *Config { // GitHub Copilot - https://github.com/settings/tokens { - ModelName: "copilot-gpt-4o", - Model: "github-copilot/gpt-4o", + ModelName: "copilot-gpt-5.2", + Model: "github-copilot/gpt-5.2", APIBase: "http://localhost:4321", AuthMethod: "oauth", }, diff --git a/pkg/config/migration.go b/pkg/config/migration.go index bed0c144b..543f2676b 100644 --- a/pkg/config/migration.go +++ b/pkg/config/migration.go @@ -50,7 +50,7 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { } return ModelConfig{ ModelName: "openai", - Model: "openai/gpt-4o", + Model: "openai/gpt-5.2", APIKey: p.OpenAI.APIKey, APIBase: p.OpenAI.APIBase, Proxy: p.OpenAI.Proxy, @@ -276,7 +276,7 @@ func ConvertProvidersToModelList(cfg *Config) []ModelConfig { } return ModelConfig{ ModelName: "github-copilot", - Model: "github-copilot/gpt-4o", + Model: "github-copilot/gpt-5.2", APIBase: p.GitHubCopilot.APIBase, ConnectMode: p.GitHubCopilot.ConnectMode, }, true diff --git a/pkg/config/migration_test.go b/pkg/config/migration_test.go index dad5b32d9..c65775118 100644 --- a/pkg/config/migration_test.go +++ b/pkg/config/migration_test.go @@ -31,8 +31,8 @@ func TestConvertProvidersToModelList_OpenAI(t *testing.T) { if result[0].ModelName != "openai" { t.Errorf("ModelName = %q, want %q", result[0].ModelName, "openai") } - if result[0].Model != "openai/gpt-4o" { - t.Errorf("Model = %q, want %q", result[0].Model, "openai/gpt-4o") + if result[0].Model != "openai/gpt-5.2" { + t.Errorf("Model = %q, want %q", result[0].Model, "openai/gpt-5.2") } if result[0].APIKey != "sk-test-key" { t.Errorf("APIKey = %q, want %q", result[0].APIKey, "sk-test-key") @@ -331,8 +331,8 @@ func TestConvertProvidersToModelList_MultipleProviders_PreservesUserModel(t *tes for _, mc := range result { switch mc.ModelName { case "openai": - if mc.Model != "openai/gpt-4o" { - t.Errorf("OpenAI Model = %q, want %q (default)", mc.Model, "openai/gpt-4o") + if mc.Model != "openai/gpt-5.2" { + t.Errorf("OpenAI Model = %q, want %q (default)", mc.Model, "openai/gpt-5.2") } case "deepseek": if mc.Model != "deepseek/deepseek-reasoner" { diff --git a/pkg/providers/factory_provider.go b/pkg/providers/factory_provider.go index ec0479e24..c1b13434d 100644 --- a/pkg/providers/factory_provider.go +++ b/pkg/providers/factory_provider.go @@ -67,10 +67,29 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err protocol, modelID := ExtractProtocol(cfg.Model) switch protocol { - case "openai", "openrouter", "groq", "zhipu", "gemini", "nvidia", + case "openai": + // OpenAI with OAuth/token auth (Codex-style) + if cfg.AuthMethod == "oauth" || cfg.AuthMethod == "token" { + provider, err := createCodexAuthProvider() + if err != nil { + return nil, "", err + } + return provider, modelID, nil + } + // OpenAI with API key + if cfg.APIKey == "" && cfg.APIBase == "" { + return nil, "", fmt.Errorf("api_key or api_base is required for HTTP-based protocol %q", protocol) + } + apiBase := cfg.APIBase + if apiBase == "" { + apiBase = getDefaultAPIBase(protocol) + } + return NewHTTPProviderWithMaxTokensField(cfg.APIKey, apiBase, cfg.Proxy, cfg.MaxTokensField), modelID, nil + + case "openrouter", "groq", "zhipu", "gemini", "nvidia", "ollama", "moonshot", "shengsuanyun", "deepseek", "cerebras", "volcengine", "vllm", "qwen": - // All OpenAI-compatible HTTP providers + // All other OpenAI-compatible HTTP providers if cfg.APIKey == "" && cfg.APIBase == "" { return nil, "", fmt.Errorf("api_key or api_base is required for HTTP-based protocol %q", protocol) }