feat: Introduce core configuration management with an example file and a provider factory.

This commit is contained in:
Bob Yang 2026-03-06 11:40:56 -08:00
parent 1945436dd4
commit 06efabf2de
3 changed files with 32 additions and 4 deletions

View file

@ -46,6 +46,14 @@
"model": "openai/gpt-5.2", "model": "openai/gpt-5.2",
"api_key": "sk-key2", "api_key": "sk-key2",
"api_base": "https://api2.example.com/v1" "api_base": "https://api2.example.com/v1"
},
{
"_comment": "Cloudflare AI example: use 'provider' field when model name contains special characters like @cf/",
"model_name": "cf_qwen",
"model": "@cf/qwen/qwen3-30b-a3b-fp8",
"provider": "own",
"api_key": "YOUR_CLOUDFLARE_API_TOKEN",
"api_base": "https://api.cloudflare.com/client/v4/accounts/[YOUR_ACCOUNT_ID]/ai/v1"
} }
], ],
"channels": { "channels": {
@ -423,4 +431,4 @@
"host": "127.0.0.1", "host": "127.0.0.1",
"port": 18790 "port": 18790
} }
} }

View file

@ -501,10 +501,16 @@ type OpenAIProviderConfig struct {
// The model field uses protocol prefix format: [protocol/]model-identifier // The model field uses protocol prefix format: [protocol/]model-identifier
// Supported protocols: openai, anthropic, antigravity, claude-cli, codex-cli, github-copilot // Supported protocols: openai, anthropic, antigravity, claude-cli, codex-cli, github-copilot
// Default protocol is "openai" if no prefix is specified. // Default protocol is "openai" if no prefix is specified.
//
// The optional Provider field explicitly sets the protocol/provider, overriding the
// prefix parsed from the Model field. This is useful when the model identifier
// itself contains slashes that would be misinterpreted as a protocol prefix
// (e.g. Cloudflare AI models like "@cf/qwen/qwen3-30b-a3b-fp8").
type ModelConfig struct { type ModelConfig struct {
// Required fields // Required fields
ModelName string `json:"model_name"` // User-facing alias for the model ModelName string `json:"model_name"` // User-facing alias for the model
Model string `json:"model"` // Protocol/model-identifier (e.g., "openai/gpt-4o", "anthropic/claude-sonnet-4.6") Model string `json:"model"` // Model identifier, optionally prefixed with protocol (e.g., "openai/gpt-4o")
Provider string `json:"provider,omitempty"` // Explicit protocol/provider override (e.g., "openai", "anthropic", "cloudflare", "own")
// HTTP-based providers // HTTP-based providers
APIBase string `json:"api_base,omitempty"` // API endpoint URL APIBase string `json:"api_base,omitempty"` // API endpoint URL

View file

@ -42,6 +42,10 @@ func createCodexAuthProvider() (LLMProvider, error) {
// - "openai/gpt-4o" -> ("openai", "gpt-4o") // - "openai/gpt-4o" -> ("openai", "gpt-4o")
// - "anthropic/claude-sonnet-4.6" -> ("anthropic", "claude-sonnet-4.6") // - "anthropic/claude-sonnet-4.6" -> ("anthropic", "claude-sonnet-4.6")
// - "gpt-4o" -> ("openai", "gpt-4o") // default protocol // - "gpt-4o" -> ("openai", "gpt-4o") // default protocol
//
// Note: use CreateProviderFromConfig when a ModelConfig is available, as it
// respects the explicit Provider override field (needed for models whose
// identifiers contain slashes, e.g. Cloudflare "@cf/qwen/qwen3-30b-a3b-fp8").
func ExtractProtocol(model string) (protocol, modelID string) { func ExtractProtocol(model string) (protocol, modelID string) {
model = strings.TrimSpace(model) model = strings.TrimSpace(model)
protocol, modelID, found := strings.Cut(model, "/") protocol, modelID, found := strings.Cut(model, "/")
@ -64,7 +68,17 @@ func CreateProviderFromConfig(cfg *config.ModelConfig) (LLMProvider, string, err
return nil, "", fmt.Errorf("model is required") return nil, "", fmt.Errorf("model is required")
} }
protocol, modelID := ExtractProtocol(cfg.Model) // If Provider is explicitly set, use it as the protocol and treat the entire
// Model string as the model identifier (no prefix stripping). This handles
// models whose names contain slashes that would otherwise be misinterpreted
// as a protocol prefix (e.g. Cloudflare AI: "@cf/qwen/qwen3-30b-a3b-fp8").
var protocol, modelID string
if cfg.Provider != "" {
protocol = strings.ToLower(strings.TrimSpace(cfg.Provider))
modelID = cfg.Model
} else {
protocol, modelID = ExtractProtocol(cfg.Model)
}
switch protocol { switch protocol {
case "openai": case "openai":