Skip to content
Open
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
6 changes: 6 additions & 0 deletions config.example.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ models:
api_version: "2025-04-01-preview"
deployment_name: "gpt-4o"

synthetic-glm-4-6:
provider: "synthetic"
model: "hf:zai-org/GLM-4.6"
api_key: "your-synthetic-api-key"
base_url: "https://api.synthetic.new/openai/v1"

# Confirm before AI executes a command
exec_confirm: true

Expand Down
13 changes: 12 additions & 1 deletion config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ type Config struct {
BlacklistPatterns []string `mapstructure:"blacklist_patterns"`
OpenRouter OpenRouterConfig `mapstructure:"openrouter"`
OpenAI OpenAIConfig `mapstructure:"openai"`
AzureOpenAI AzureOpenAIConfig `mapstructure:"azure_openai"`
AzureOpenAI AzureOpenAIConfig `mapstructure:"azure_open_ai"`
Synthetic SyntheticConfig `mapstructure:"synthetic"`
DefaultModel string `mapstructure:"default_model"`
Models map[string]ModelConfig `mapstructure:"models"`
Prompts PromptsConfig `mapstructure:"prompts"`
Expand Down Expand Up @@ -52,6 +53,13 @@ type AzureOpenAIConfig struct {
DeploymentName string `mapstructure:"deployment_name"`
}

// SyntheticConfig holds Synthetic API configuration
type SyntheticConfig struct {
APIKey string `mapstructure:"api_key"`
Model string `mapstructure:"model"`
BaseURL string `mapstructure:"base_url"`
}


// ModelConfig holds a single model configuration
type ModelConfig struct {
Expand Down Expand Up @@ -100,6 +108,9 @@ func DefaultConfig() *Config {
BaseURL: "https://api.openai.com/v1",
},
AzureOpenAI: AzureOpenAIConfig{},
Synthetic: SyntheticConfig{
BaseURL: "https://api.synthetic.new/openai/v1",
},
DefaultModel: "",
Models: make(map[string]ModelConfig),
Prompts: PromptsConfig{
Expand Down
11 changes: 10 additions & 1 deletion internal/ai_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ func (c *AiClient) determineAPIType(model string) string {
return "responses"
case "azure":
return "azure"
case "openrouter":
case "openrouter", "synthetic":
return "openrouter"
default:
return "openrouter"
Expand All @@ -150,6 +150,11 @@ func (c *AiClient) determineAPIType(model string) string {
return "azure"
}

// If Synthetic is configured, use OpenRouter-compatible Chat Completions
if c.config.Synthetic.APIKey != "" {
return "openrouter"
}

// Default to OpenRouter Chat Completions
return "openrouter"
}
Expand Down Expand Up @@ -239,6 +244,10 @@ func (c *AiClient) ChatCompletion(ctx context.Context, messages []Message, model
apiBase = c.config.AzureOpenAI.APIBase
apiVersion = c.config.AzureOpenAI.APIVersion
deploymentName = c.config.AzureOpenAI.DeploymentName
} else if c.config.Synthetic.APIKey != "" {
provider = "synthetic"
apiKey = c.config.Synthetic.APIKey
baseURL = c.config.Synthetic.BaseURL
} else if c.config.OpenRouter.APIKey != "" {
provider = "openrouter"
apiKey = c.config.OpenRouter.APIKey
Expand Down
56 changes: 54 additions & 2 deletions internal/config_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ var AllowedConfigKeys = []string{
"azure_openai.deployment_name",
"azure_openai.api_base",
"azure_openai.api_version",
"synthetic.api_key",
"synthetic.model",
"synthetic.base_url",
"default_model",
}

Expand Down Expand Up @@ -143,6 +146,36 @@ func (m *Manager) GetAzureOpenAIDeploymentName() string {
return m.Config.AzureOpenAI.DeploymentName
}

// GetSyntheticModel returns the Synthetic model value with session override if present
func (m *Manager) GetSyntheticModel() string {
if override, exists := m.SessionOverrides["synthetic.model"]; exists {
if val, ok := override.(string); ok {
return val
}
}
return m.Config.Synthetic.Model
}

// GetSyntheticAPIKey returns the Synthetic API key value with session override if present
func (m *Manager) GetSyntheticAPIKey() string {
if override, exists := m.SessionOverrides["synthetic.api_key"]; exists {
if val, ok := override.(string); ok {
return val
}
}
return m.Config.Synthetic.APIKey
}

// GetSyntheticBaseURL returns the Synthetic base URL value with session override if present
func (m *Manager) GetSyntheticBaseURL() string {
if override, exists := m.SessionOverrides["synthetic.base_url"]; exists {
if val, ok := override.(string); ok {
return val
}
}
return m.Config.Synthetic.BaseURL
}

// GetModelsDefault returns the default model configuration name with session override if present
func (m *Manager) GetModelsDefault() string {
// Check for session override first
Expand Down Expand Up @@ -231,12 +264,12 @@ func (m *Manager) hasValidAIConfiguration() bool {
}

// Fall back to legacy configuration
return m.Config.OpenRouter.APIKey != "" || m.Config.OpenAI.APIKey != "" || m.Config.AzureOpenAI.APIKey != ""
return m.Config.OpenRouter.APIKey != "" || m.Config.OpenAI.APIKey != "" || m.Config.AzureOpenAI.APIKey != "" || m.Config.Synthetic.APIKey != ""
}

// getLegacyModelConfig converts the legacy provider configuration to a ModelConfig
func (m *Manager) getLegacyModelConfig() config.ModelConfig {
// Priority: OpenAI > Azure > OpenRouter
// Priority: OpenAI > Azure > Synthetic > OpenRouter
if m.GetOpenAIAPIKey() != "" {
return config.ModelConfig{
Provider: "openai",
Expand All @@ -257,6 +290,15 @@ func (m *Manager) getLegacyModelConfig() config.ModelConfig {
}
}

if m.GetSyntheticAPIKey() != "" {
return config.ModelConfig{
Provider: "synthetic",
Model: m.GetSyntheticModel(),
APIKey: m.GetSyntheticAPIKey(),
BaseURL: m.GetSyntheticBaseURL(),
}
}

return config.ModelConfig{
Provider: "openrouter",
Model: m.GetOpenRouterModel(),
Expand Down Expand Up @@ -292,6 +334,16 @@ func (m *Manager) GetModel() string {
return "gpt-4o"
}

// If Synthetic is configured, use Synthetic model
if m.GetSyntheticAPIKey() != "" {
model := m.GetSyntheticModel()
if model != "" {
return model
}
// Default model for Synthetic if not specified
return "hf:zai-org/GLM-4.6"
}

// Default to OpenRouter
return m.GetOpenRouterModel()
}
Expand Down