From a2081e1f3717e5f8d7ebd23497d5c4c821aad3ed Mon Sep 17 00:00:00 2001 From: Andrey Nering Date: Thu, 9 Apr 2026 14:59:41 -0300 Subject: [PATCH] feat(config): support `HYPER_API_KEY` for hyper auth (#2583) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- internal/config/load.go | 14 ++++++ internal/config/load_test.go | 84 ++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+) diff --git a/internal/config/load.go b/internal/config/load.go index 20ab25d0de44db41d24068b61db8de6dc83e0801..b6a967ca0f48ad01492052cb5d7db92f3fd8aa47 100644 --- a/internal/config/load.go +++ b/internal/config/load.go @@ -295,6 +295,20 @@ func (c *Config) configureProviders(store *ConfigStore, env env.Env, resolver Va return fmt.Errorf("bedrock provider only supports anthropic models for now, found: %s", model.ID) } } + case catwalk.InferenceProvider("hyper"): + if apiKey := env.Get("HYPER_API_KEY"); apiKey != "" { + prepared.APIKey = apiKey + prepared.APIKeyTemplate = apiKey + } else { + v, err := resolver.ResolveValue(p.APIKey) + if v == "" || err != nil { + if configExists { + slog.Warn("Skipping Hyper provider due to missing API key", "provider", p.ID) + c.Providers.Del(string(p.ID)) + } + continue + } + } default: // if the provider api or endpoint are missing we skip them v, err := resolver.ResolveValue(p.APIKey) diff --git a/internal/config/load_test.go b/internal/config/load_test.go index 3f8fc32c1a027071bca0c8346ade894519a357ee..68d52da39fae5000433a47dea2401fd46c193ba3 100644 --- a/internal/config/load_test.go +++ b/internal/config/load_test.go @@ -1505,3 +1505,87 @@ func TestConfig_configureSelectedModels(t *testing.T) { require.Equal(t, int64(100), large.MaxTokens) }) } + +func TestConfig_configureProviders_HyperAPIKeyFromEnv(t *testing.T) { + // Test that HYPER_API_KEY environment variable works without config + knownProviders := []catwalk.Provider{ + { + ID: "hyper", + APIKey: "", // No API key in provider definition + DefaultLargeModelID: "large-model", + DefaultSmallModelID: "small-model", + Models: []catwalk.Model{ + { + ID: "large-model", + DefaultMaxTokens: 1000, + }, + { + ID: "small-model", + DefaultMaxTokens: 500, + }, + }, + }, + } + + cfg := &Config{} + cfg.setDefaults("/tmp", "") + env := env.NewFromMap(map[string]string{ + "HYPER_API_KEY": "env-api-key", + }) + resolver := NewEnvironmentVariableResolver(env) + err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders) + require.NoError(t, err) + require.Equal(t, 1, cfg.Providers.Len()) + + // Verify Hyper provider is configured with the env var API key + pc, ok := cfg.Providers.Get("hyper") + require.True(t, ok, "Hyper provider should be configured") + require.Equal(t, "env-api-key", pc.APIKey) + require.Equal(t, "env-api-key", pc.APIKeyTemplate) +} + +func TestConfig_configureProviders_HyperAPIKeyFromConfigOverrides(t *testing.T) { + // Test that config API key takes precedence when HYPER_API_KEY is also set + knownProviders := []catwalk.Provider{ + { + ID: "hyper", + APIKey: "provider-api-key", + DefaultLargeModelID: "large-model", + DefaultSmallModelID: "small-model", + Models: []catwalk.Model{ + { + ID: "large-model", + DefaultMaxTokens: 1000, + }, + { + ID: "small-model", + DefaultMaxTokens: 500, + }, + }, + }, + } + + // User has Hyper configured with an API key + cfg := &Config{ + Providers: csync.NewMapFrom(map[string]ProviderConfig{ + "hyper": { + APIKey: "config-api-key", + }, + }), + } + cfg.setDefaults("/tmp", "") + + // But they also have HYPER_API_KEY set - env var should take precedence + env := env.NewFromMap(map[string]string{ + "HYPER_API_KEY": "env-api-key", + }) + resolver := NewEnvironmentVariableResolver(env) + err := cfg.configureProviders(testStore(cfg), env, resolver, knownProviders) + require.NoError(t, err) + require.Equal(t, 1, cfg.Providers.Len()) + + // Verify env var takes precedence (as per requirements) + pc, ok := cfg.Providers.Get("hyper") + require.True(t, ok, "Hyper provider should be configured") + require.Equal(t, "env-api-key", pc.APIKey) +}