fix: add env var loading for providers (PICOCLAW_ZAI_API_KEY)

ProviderConfig's env tags used {{.Name}} template placeholders that
caarlos0/env cannot resolve, meaning env vars for ALL providers were
silently ignored. Users with PICOCLAW_ZAI_API_KEY (or any
PICOCLAW_<PROVIDER>_API_KEY) set as GitHub secrets had their keys
not being read.

Added loadProviderEnvVars() that manually checks both formats:
- PICOCLAW_PROVIDERS_ZAI_API_KEY (full path)
- PICOCLAW_ZAI_API_KEY (short form)

This runs after env.Parse() and before migrateProviders(), so env
vars properly feed into the provider resolution chain.

https://claude.ai/code/session_01MYemTMPtHrcgidWs8UdjcG
This commit is contained in:
Claude 2026-02-18 19:06:09 +00:00
parent 47a626fb61
commit 9ca165451e
No known key found for this signature in database

View file

@ -373,12 +373,63 @@ func LoadConfig(path string) (*Config, error) {
return nil, err return nil, err
} }
// Load provider env vars manually since ProviderConfig's env tags
// use {{.Name}} templates that caarlos0/env cannot resolve.
// Supports both PICOCLAW_PROVIDERS_<NAME>_API_KEY and PICOCLAW_<NAME>_API_KEY.
cfg.loadProviderEnvVars()
// Migrate deprecated provider configs to Zai (Z.ai, formerly Zhipu/Moonshot) // Migrate deprecated provider configs to Zai (Z.ai, formerly Zhipu/Moonshot)
cfg.migrateProviders() cfg.migrateProviders()
return cfg, nil return cfg, nil
} }
// loadProviderEnvVars reads provider-specific environment variables.
// ProviderConfig is a shared struct so its env tags use {{.Name}} placeholders
// which caarlos0/env cannot resolve. This function manually checks env vars
// in two formats: PICOCLAW_PROVIDERS_<NAME>_API_KEY and PICOCLAW_<NAME>_API_KEY.
func (c *Config) loadProviderEnvVars() {
providerEnv := []struct {
name string
cfg *ProviderConfig
}{
{"ZAI", &c.Providers.Zai},
{"ZHIPU", &c.Providers.Zhipu},
{"MOONSHOT", &c.Providers.Moonshot},
{"ANTHROPIC", &c.Providers.Anthropic},
{"OPENAI", &c.Providers.OpenAI},
{"OPENROUTER", &c.Providers.OpenRouter},
{"GROQ", &c.Providers.Groq},
{"GEMINI", &c.Providers.Gemini},
{"NVIDIA", &c.Providers.Nvidia},
{"OLLAMA", &c.Providers.Ollama},
{"VLLM", &c.Providers.VLLM},
{"DEEPSEEK", &c.Providers.DeepSeek},
{"SHENGSUANYUN", &c.Providers.ShengSuanYun},
}
for _, p := range providerEnv {
loadProviderField(&p.cfg.APIKey, p.name, "API_KEY")
loadProviderField(&p.cfg.APIBase, p.name, "API_BASE")
loadProviderField(&p.cfg.Proxy, p.name, "PROXY")
}
}
// loadProviderField sets *dst from env var if not already set.
// Checks PICOCLAW_PROVIDERS_<name>_<field> first, then PICOCLAW_<name>_<field>.
func loadProviderField(dst *string, name, field string) {
if *dst != "" {
return
}
if v := os.Getenv("PICOCLAW_PROVIDERS_" + name + "_" + field); v != "" {
*dst = v
return
}
if v := os.Getenv("PICOCLAW_" + name + "_" + field); v != "" {
*dst = v
}
}
// migrateProviders merges deprecated Zhipu provider config into Zai. // migrateProviders merges deprecated Zhipu provider config into Zai.
// Zhipu AI rebranded to Z.ai in 2025 - same company, same API. // Zhipu AI rebranded to Z.ai in 2025 - same company, same API.
// Note: Moonshot (Kimi) is a separate service and is NOT migrated // Note: Moonshot (Kimi) is a separate service and is NOT migrated