diff --git a/cmd/engine/main.go b/cmd/engine/main.go index 5e1968f..3f2742b 100644 --- a/cmd/engine/main.go +++ b/cmd/engine/main.go @@ -350,6 +350,7 @@ func buildLLM(c config.LLMConfig) (llmgate.Client, error) { APIKey: c.Anthropic.APIKey, Model: c.Anthropic.Model, ReasoningModel: c.Anthropic.ReasoningModel, + BaseURL: c.Anthropic.BaseURL, }) case "openai": return openai.New(openai.Config{ diff --git a/cmd/server/main.go b/cmd/server/main.go index 697ecb9..a241eda 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -393,6 +393,7 @@ func buildLLM(c enginecfg.LLMConfig) (llmgate.Client, error) { APIKey: c.Anthropic.APIKey, Model: c.Anthropic.Model, ReasoningModel: c.Anthropic.ReasoningModel, + BaseURL: c.Anthropic.BaseURL, }) case "openai": return openai.New(openai.Config{ diff --git a/internal/config/config.go b/internal/config/config.go index c6ca1cf..82b8118 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -320,6 +320,16 @@ func applyEnvOverrides(c *Config) { if v := firstEnv("VLS_LLM_DRIVER", "VLE_LLM_DRIVER"); v != "" { c.Engine.LLM.Driver = v } + // Anthropic-compatible gateway overrides (e.g. GLM/Zhipu via + // https://api.z.ai/api/anthropic): base URL + model, so the + // anthropic driver can run a non-Anthropic model without a secret + // edit. + if v := firstEnv("VLS_LLM_ANTHROPIC_BASE_URL", "VLE_LLM_ANTHROPIC_BASE_URL"); v != "" { + c.Engine.LLM.Anthropic.BaseURL = v + } + if v := firstEnv("VLS_LLM_ANTHROPIC_MODEL", "VLE_LLM_ANTHROPIC_MODEL"); v != "" { + c.Engine.LLM.Anthropic.Model = v + } } // firstEnv returns the first non-empty value from the named env vars. diff --git a/pkg/config/config.go b/pkg/config/config.go index ba40628..3add5b0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -332,6 +332,12 @@ type AnthropicBlock struct { APIKey string `yaml:"api_key"` Model string `yaml:"model"` ReasoningModel string `yaml:"reasoning_model"` + // BaseURL overrides the Anthropic API endpoint. Empty = official + // api.anthropic.com. Set this to point the Anthropic driver at any + // Anthropic-compatible gateway — e.g. GLM/Zhipu's + // https://api.z.ai/api/anthropic — so the same driver can drive a + // non-Anthropic model that speaks the Messages API. + BaseURL string `yaml:"base_url"` } // OpenAIBlock configures the OpenAI provider. @@ -805,6 +811,19 @@ func applyEnvOverrides(c *Config) { if v := os.Getenv("VLE_LLM_DRIVER"); v != "" { c.LLM.Driver = v } + // Anthropic-driver overrides. These let an operator point the + // anthropic driver at an Anthropic-compatible gateway (e.g. GLM via + // https://api.z.ai/api/anthropic) without baking the values into the + // config file or secret. + if v := os.Getenv("VLE_LLM_ANTHROPIC_API_KEY"); v != "" { + c.LLM.Anthropic.APIKey = v + } + if v := os.Getenv("VLE_LLM_ANTHROPIC_BASE_URL"); v != "" { + c.LLM.Anthropic.BaseURL = v + } + if v := os.Getenv("VLE_LLM_ANTHROPIC_MODEL"); v != "" { + c.LLM.Anthropic.Model = v + } if v := os.Getenv("VLE_TLS_CERT_FILE"); v != "" { c.Server.TLS.CertFile = v }