From 917a920a466fde1d75463d1dfa0a9458ed59d3f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Badyl?= Date: Sat, 28 Feb 2026 23:13:04 +0100 Subject: [PATCH 1/4] fix(agent, config): remove provider-specific API key fallbacks and add ExportTests tool to prompt --- internal/agents/chat.go | 4 ++++ internal/config/config.go | 7 ------- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/internal/agents/chat.go b/internal/agents/chat.go index 139a00c..3c53193 100644 --- a/internal/agents/chat.go +++ b/internal/agents/chat.go @@ -114,6 +114,10 @@ Use assertions to verify specific fields in the response body: {"field":"token","op":"contains","value":"Bearer"} — substring Operators: eq, neq, exists, not_exists, contains, gt, gte, lt, lte +## ExportTests +Export API tests to formats strictly when the user requests it (e.g. "zapisz do postmana", "eksportuj testy do pliku sh"). +Can export combinations of "postman", "pytest" or "sh". + ## wait Wait N seconds before proceeding. Use when: - You receive a 429 status code diff --git a/internal/config/config.go b/internal/config/config.go index 441ac05..2471fb2 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -137,13 +137,6 @@ func GetActiveLLMConfig() (provider, apiKey, baseURL, modelName string) { if provider == "" { provider = "claude" } - if apiKey == "" { - if provider == "openai" || provider == "openrouter" { - apiKey = os.Getenv("OPENAI_API_KEY") - } else { - apiKey = os.Getenv("ANTHROPIC_API_KEY") - } - } return provider, apiKey, baseURL, modelName } From 2a3facc93a0ba64a694a90c001a089b27dc89232 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Badyl?= Date: Sat, 28 Feb 2026 23:16:25 +0100 Subject: [PATCH 2/4] refactor(llm): remove legacy environment variable configuration and rely solely on config package --- internal/llm/claude/client.go | 22 +++++----------------- internal/llm/claude/provider.go | 2 +- internal/llm/gemini/client.go | 11 ++--------- internal/llm/openai/client.go | 23 +++-------------------- 4 files changed, 11 insertions(+), 47 deletions(-) diff --git a/internal/llm/claude/client.go b/internal/llm/claude/client.go index 3e95719..d000efd 100644 --- a/internal/llm/claude/client.go +++ b/internal/llm/claude/client.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "os" "github.com/Octrafic/octrafic-cli/internal/infra/logger" @@ -59,25 +58,14 @@ type Tool struct { InputSchema map[string]interface{} } -// NewClient creates a new Claude client (uses env vars) -func NewClient() (*Client, error) { - return NewClientWithConfig("", "") -} - -// NewClientWithConfig creates a new Claude client with explicit API key and model -func NewClientWithConfig(apiKey, model string) (*Client, error) { +// NewClientWithConfig creates a new Claude client with explicit API key, model and base URL +func NewClientWithConfig(apiKey, model, baseURL string) (*Client, error) { if apiKey == "" { - apiKey = os.Getenv("ANTHROPIC_API_KEY") - if apiKey == "" { - return nil, fmt.Errorf("ANTHROPIC_API_KEY not set") - } + return nil, fmt.Errorf("anthropic API key is required") } if model == "" { - model = os.Getenv("ANTHROPIC_MODEL") - if model == "" { - model = string(anthropic.ModelClaudeSonnet4_20250514) - } + model = string(anthropic.ModelClaudeSonnet4_20250514) } ctx := context.Background() @@ -88,7 +76,7 @@ func NewClientWithConfig(apiKey, model string) (*Client, error) { } // Add custom base URL if provided (for proxies) - if baseURL := os.Getenv("ANTHROPIC_BASE_URL"); baseURL != "" { + if baseURL != "" { opts = append(opts, option.WithBaseURL(baseURL)) } diff --git a/internal/llm/claude/provider.go b/internal/llm/claude/provider.go index 7a7a195..aa314d7 100644 --- a/internal/llm/claude/provider.go +++ b/internal/llm/claude/provider.go @@ -12,7 +12,7 @@ type ClaudeProvider struct { // NewClaudeProvider creates a new Claude provider func NewClaudeProvider(config common.ProviderConfig) (*ClaudeProvider, error) { - client, err := NewClientWithConfig(config.APIKey, config.Model) + client, err := NewClientWithConfig(config.APIKey, config.Model, config.BaseURL) if err != nil { return nil, fmt.Errorf("failed to create Claude client: %w", err) } diff --git a/internal/llm/gemini/client.go b/internal/llm/gemini/client.go index 9c9e64e..ca1468c 100644 --- a/internal/llm/gemini/client.go +++ b/internal/llm/gemini/client.go @@ -5,7 +5,6 @@ import ( "encoding/base64" "encoding/json" "fmt" - "os" "github.com/Octrafic/octrafic-cli/internal/infra/logger" @@ -75,17 +74,11 @@ type Tool struct { // NewClientWithConfig creates a new Gemini client with explicit API key and model. func NewClientWithConfig(apiKey, model string) (*Client, error) { if apiKey == "" { - apiKey = os.Getenv("GOOGLE_API_KEY") - if apiKey == "" { - return nil, fmt.Errorf("GOOGLE_API_KEY not set") - } + return nil, fmt.Errorf("gemini API key is required") } if model == "" { - model = os.Getenv("GEMINI_MODEL") - if model == "" { - model = "gemini-2.5-flash" - } + model = "gemini-2.5-flash" } ctx := context.Background() diff --git a/internal/llm/openai/client.go b/internal/llm/openai/client.go index 3698fb8..bd98e62 100644 --- a/internal/llm/openai/client.go +++ b/internal/llm/openai/client.go @@ -8,7 +8,6 @@ import ( "fmt" "io" "net/http" - "os" "strings" "regexp" @@ -191,28 +190,12 @@ type Client struct { ctx context.Context } -// NewClient creates a new client from environment variables -func NewClient() (*Client, error) { - apiKey := os.Getenv("OPENAI_API_KEY") +// NewClientWithConfig creates a new client with explicit configuration +func NewClientWithConfig(apiKey, model, baseURL string) (*Client, error) { if apiKey == "" { - return nil, fmt.Errorf("OPENAI_API_KEY not set") + return nil, fmt.Errorf("openai API key is required") } - model := os.Getenv("SEARCH_SPEC_MODEL") - if model == "" { - model = "gpt-4o-mini" - } - - baseURL := os.Getenv("OPENAI_BASE_URL") - if baseURL == "" { - baseURL = "https://api.openai.com/v1" - } - - return NewClientWithConfig(apiKey, model, baseURL) -} - -// NewClientWithConfig creates a new client with explicit configuration -func NewClientWithConfig(apiKey, model, baseURL string) (*Client, error) { if model == "" { return nil, fmt.Errorf("model is required") } From e7078a11282e7598d4cd34df95c33b0415716660 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Badyl?= Date: Sat, 28 Feb 2026 23:24:31 +0100 Subject: [PATCH 3/4] fix(ui): use active LLM config for model name display instead of raw config file --- internal/cli/tui.go | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/internal/cli/tui.go b/internal/cli/tui.go index fe2ecd0..cd06ae9 100644 --- a/internal/cli/tui.go +++ b/internal/cli/tui.go @@ -324,9 +324,10 @@ func NewTestUIModel(baseURL string, specPath string, analysis *analyzer.Analysis if cfg.LatestVersion != "" && updater.IsNewer(cfg.LatestVersion, version) { model.latestVersion = cfg.LatestVersion } - if cfg.Model != "" { - model.modelName = cfg.Model - } + } + _, _, _, activeModel := config.GetActiveLLMConfig() + if activeModel != "" { + model.modelName = activeModel } // Add header (logo + info) From bf6d325115ad992abb468fa176419fcf6bdb8f79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miko=C5=82aj=20Badyl?= Date: Sat, 28 Feb 2026 23:30:59 +0100 Subject: [PATCH 4/4] docs: translate ExportTests prompt examples from Polish to English --- internal/agents/chat.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/agents/chat.go b/internal/agents/chat.go index 3c53193..0cd8c13 100644 --- a/internal/agents/chat.go +++ b/internal/agents/chat.go @@ -115,7 +115,7 @@ Use assertions to verify specific fields in the response body: Operators: eq, neq, exists, not_exists, contains, gt, gte, lt, lte ## ExportTests -Export API tests to formats strictly when the user requests it (e.g. "zapisz do postmana", "eksportuj testy do pliku sh"). +Export API tests to formats strictly when the user requests it (e.g. "save to postman", "export tests to sh file"). Can export combinations of "postman", "pytest" or "sh". ## wait