Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions internal/agents/chat.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 4 additions & 3 deletions internal/cli/tui.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 5 additions & 6 deletions internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,13 +135,12 @@ func GetActiveLLMConfig() (provider, apiKey, baseURL, modelName string) {
}

if provider == "" {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WARNING: Breaking change - the automatic API key lookup from provider-specific environment variables (OPENAI_API_KEY, ANTHROPIC_API_KEY, GOOGLE_API_KEY) has been removed. Users must now use OCTRAFIC_API_KEY or configure their API key in the saved config file. This may break existing setups that rely on the provider-specific env vars.

provider = "claude"
}
if apiKey == "" {
if provider == "openai" || provider == "openrouter" {
apiKey = os.Getenv("OPENAI_API_KEY")
if strings.HasPrefix(modelName, "gpt-") || strings.HasPrefix(modelName, "o1") || strings.HasPrefix(modelName, "o3") {
provider = "openai"
} else if strings.HasPrefix(modelName, "gemini-") {
provider = "gemini"
} else {
apiKey = os.Getenv("ANTHROPIC_API_KEY")
provider = "claude"
}
}

Expand Down
22 changes: 5 additions & 17 deletions internal/llm/claude/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"encoding/json"
"fmt"
"os"

"github.com/Octrafic/octrafic-cli/internal/infra/logger"

Expand Down Expand Up @@ -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()
Expand All @@ -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))
}

Expand Down
2 changes: 1 addition & 1 deletion internal/llm/claude/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
11 changes: 2 additions & 9 deletions internal/llm/gemini/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"os"

"github.com/Octrafic/octrafic-cli/internal/infra/logger"

Expand Down Expand Up @@ -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()
Expand Down
23 changes: 3 additions & 20 deletions internal/llm/openai/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"fmt"
"io"
"net/http"
"os"
"strings"

"regexp"
Expand Down Expand Up @@ -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")
}
Expand Down