Skip to content

Commit fb4dfa4

Browse files
committed
feat: support API key resolution from env var
1 parent 0440fb9 commit fb4dfa4

4 files changed

Lines changed: 43 additions & 10 deletions

File tree

internal/agent/session.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -289,13 +289,15 @@ func (s *Session) BaseURL() string {
289289
}
290290

291291
// resolveCredentials returns the API key and base URL for a provider.
292+
// Checks the session providers map first, then falls back to environment variables.
292293
func (s *Session) resolveCredentials(prov string) (apiKey, baseURL string) {
293294
s.mu.Lock()
294-
defer s.mu.Unlock()
295-
if pc, ok := s.providers[prov]; ok {
295+
pc, ok := s.providers[prov]
296+
s.mu.Unlock()
297+
if ok && pc.APIKey != "" {
296298
return pc.APIKey, pc.BaseURL
297299
}
298-
return "", ""
300+
return config.EnvCredentials(prov)
299301
}
300302

301303
// --------------------------------------------------------------------------

internal/bootstrap/boot.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ func Boot(opts Options) (*Runtime, error) {
9191
apiKey, _ := settings.ProviderCredentials(settings.Provider)
9292
if apiKey == "" {
9393
if opts.NonTTYMode {
94-
return nil, fmt.Errorf("api key not set, configure providers in %s",
95-
config.SettingsPath(cwd))
94+
return nil, fmt.Errorf("api key not set; set %s or configure providers in %s",
95+
config.ProviderEnvKey(settings.Provider), config.SettingsPath(cwd))
9696
}
9797
err := config.RunSetup(cwd, settings, func(prov string) []config.ModelOption {
9898
entries := registry.FindByProvider(prov)

internal/bootstrap/subagents.go

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,13 @@ func buildSubAgentTool(deps subAgentDeps) *agentcore.SubAgentTool {
8282
return sat
8383
}
8484

85-
// resolveFromProviders returns credentials for a provider from the map.
85+
// resolveFromProviders returns credentials for a provider from the map,
86+
// falling back to standard environment variables.
8687
func resolveFromProviders(providers map[string]config.ProviderConfig, prov string) (apiKey, baseURL string) {
87-
if pc, ok := providers[prov]; ok {
88+
if pc, ok := providers[prov]; ok && pc.APIKey != "" {
8889
return pc.APIKey, pc.BaseURL
8990
}
90-
return "", ""
91+
return config.EnvCredentials(prov)
9192
}
9293

9394
// readOnlyTools constructs a read-only tool set for explore/plan sub-agents.

internal/config/settings.go

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,42 @@ type Resolved struct {
5050
SearchAPIKey string
5151
}
5252

53+
// providerEnvVars maps provider names to their standard environment variable names.
54+
var providerEnvVars = map[string]struct{ key, base string }{
55+
"anthropic": {"ANTHROPIC_API_KEY", ""},
56+
"openai": {"OPENAI_API_KEY", "OPENAI_BASE_URL"},
57+
"gemini": {"GEMINI_API_KEY", ""},
58+
}
59+
5360
// ProviderCredentials returns API key and base URL for the given provider.
61+
// It checks the providers map first, then falls back to standard environment variables.
5462
func (r Resolved) ProviderCredentials(prov string) (apiKey, baseURL string) {
55-
if pc, ok := r.Providers[prov]; ok {
63+
if pc, ok := r.Providers[prov]; ok && pc.APIKey != "" {
5664
return pc.APIKey, pc.BaseURL
5765
}
58-
return "", ""
66+
return EnvCredentials(prov)
67+
}
68+
69+
// ProviderEnvKey returns the standard environment variable name for a provider's API key.
70+
func ProviderEnvKey(prov string) string {
71+
if ev, ok := providerEnvVars[prov]; ok {
72+
return ev.key
73+
}
74+
return strings.ToUpper(prov) + "_API_KEY"
75+
}
76+
77+
// EnvCredentials returns API key and base URL from standard environment variables
78+
// for the given provider (e.g. ANTHROPIC_API_KEY, OPENAI_API_KEY).
79+
func EnvCredentials(prov string) (apiKey, baseURL string) {
80+
envVars, ok := providerEnvVars[prov]
81+
if !ok {
82+
return "", ""
83+
}
84+
apiKey = os.Getenv(envVars.key)
85+
if envVars.base != "" {
86+
baseURL = os.Getenv(envVars.base)
87+
}
88+
return apiKey, baseURL
5989
}
6090

6191
// ParseModelID splits "provider/model" into (provider, model).

0 commit comments

Comments
 (0)