on main help sign in
feat(config): support `HYPER_API_KEY` for hyper auth (#2583)

Use `HYPER_API_KEY` to configure Hyper for non-interactive workflows and bypass OAuth-driven setup when the environment variable is present. 💘 Generated with Crush Assisted-by: Kimi K2.5 via Crush <crush@charm.land>

commita2081e1f3717e5f8d7ebd23497d5c4c821aad3ed authorAndrey Nering <andreynering@users.noreply.github.com> dateThu 9 Apr 2026, 14:59 (6 months ago) parent56e2ff6
2 files changed+98
internal/config/load.go+14 internal/config/load_test.go+84
internal/config/load.go+14
@@ -295,6 +295,20 @@ func (c *Config) configureProviders(store *ConfigStore, env env.Env, resolver Va
295295 return fmt.Errorf("bedrock provider only supports anthropic models for now, found: %s", model.ID)
296296 }
297297 }
298+ case catwalk.InferenceProvider("hyper"):
299+ if apiKey := env.Get("HYPER_API_KEY"); apiKey != "" {
300+ prepared.APIKey = apiKey
301+ prepared.APIKeyTemplate = apiKey
302+ } else {
303+ v, err := resolver.ResolveValue(p.APIKey)
304+ if v == "" || err != nil {
305+ if configExists {
306+ slog.Warn("Skipping Hyper provider due to missing API key", "provider", p.ID)
307+ c.Providers.Del(string(p.ID))
308+ }
309+ continue
310+ }
311+ }
298312 default:
299313 // if the provider api or endpoint are missing we skip them
300314 v, err := resolver.ResolveValue(p.APIKey)
internal/config/load_test.go+84
@@ -1505,3 +1505,87 @@ func TestConfig_configureSelectedModels(t *testing.T) {
15051505 require.Equal(t, int64(100), large.MaxTokens)
15061506 })
15071507}
1508+
1509+func TestConfig_configureProviders_HyperAPIKeyFromEnv(t *testing.T) {
1510+ // Test that HYPER_API_KEY environment variable works without config
1511+ knownProviders := []catwalk.Provider{
1512+ {
1513+ ID: "hyper",
1514+ APIKey: "", // No API key in provider definition
1515+ DefaultLargeModelID: "large-model",
1516+ DefaultSmallModelID: "small-model",
1517+ Models: []catwalk.Model{
1518+ {
1519+ ID: "large-model",
1520+ DefaultMaxTokens: 1000,
1521+ },
1522+ {
1523+ ID: "small-model",
1524+ DefaultMaxTokens: 500,
1525+ },
1526+ },
1527+ },
1528+ }
1529+
1530+ cfg := &Config{}
1531+ cfg.setDefaults("/tmp", "")
1532+ env := env.NewFromMap(map[string]string{
1533+ "HYPER_API_KEY": "env-api-key",
1534+ })
1535+ resolver := NewEnvironmentVariableResolver(env)
1536+ err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1537+ require.NoError(t, err)
1538+ require.Equal(t, 1, cfg.Providers.Len())
1539+
1540+ // Verify Hyper provider is configured with the env var API key
1541+ pc, ok := cfg.Providers.Get("hyper")
1542+ require.True(t, ok, "Hyper provider should be configured")
1543+ require.Equal(t, "env-api-key", pc.APIKey)
1544+ require.Equal(t, "env-api-key", pc.APIKeyTemplate)
1545+}
1546+
1547+func TestConfig_configureProviders_HyperAPIKeyFromConfigOverrides(t *testing.T) {
1548+ // Test that config API key takes precedence when HYPER_API_KEY is also set
1549+ knownProviders := []catwalk.Provider{
1550+ {
1551+ ID: "hyper",
1552+ APIKey: "provider-api-key",
1553+ DefaultLargeModelID: "large-model",
1554+ DefaultSmallModelID: "small-model",
1555+ Models: []catwalk.Model{
1556+ {
1557+ ID: "large-model",
1558+ DefaultMaxTokens: 1000,
1559+ },
1560+ {
1561+ ID: "small-model",
1562+ DefaultMaxTokens: 500,
1563+ },
1564+ },
1565+ },
1566+ }
1567+
1568+ // User has Hyper configured with an API key
1569+ cfg := &Config{
1570+ Providers: csync.NewMapFrom(map[string]ProviderConfig{
1571+ "hyper": {
1572+ APIKey: "config-api-key",
1573+ },
1574+ }),
1575+ }
1576+ cfg.setDefaults("/tmp", "")
1577+
1578+ // But they also have HYPER_API_KEY set - env var should take precedence
1579+ env := env.NewFromMap(map[string]string{
1580+ "HYPER_API_KEY": "env-api-key",
1581+ })
1582+ resolver := NewEnvironmentVariableResolver(env)
1583+ err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders)
1584+ require.NoError(t, err)
1585+ require.Equal(t, 1, cfg.Providers.Len())
1586+
1587+ // Verify env var takes precedence (as per requirements)
1588+ pc, ok := cfg.Providers.Get("hyper")
1589+ require.True(t, ok, "Hyper provider should be configured")
1590+ require.Equal(t, "env-api-key", pc.APIKey)
1591+}