- Add DeepSeekClient implementing LLM interface - Support chat and streaming APIs - Add Provider config option (ollama/deepseek) - Default to DeepSeek with model deepseek-v4-flash - Update CLI to display provider info - Add DeepSeek environment variables (DEEPSEEK_API_KEY, etc.)
183 lines
4.4 KiB
Go
183 lines
4.4 KiB
Go
package config
|
|
|
|
import (
|
|
"os"
|
|
"strconv"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
ProviderOllama = "ollama"
|
|
ProviderDeepSeek = "deepseek"
|
|
)
|
|
|
|
type Config struct {
|
|
Provider string `json:"provider"`
|
|
Ollama OllamaConfig `json:"ollama"`
|
|
DeepSeek DeepSeekConfig `json:"deepseek"`
|
|
Sandbox SandboxConfig `json:"sandbox"`
|
|
Session SessionConfig `json:"session"`
|
|
}
|
|
|
|
type OllamaConfig struct {
|
|
BaseURL string `json:"base_url"`
|
|
Model string `json:"model"`
|
|
Timeout time.Duration `json:"timeout"`
|
|
}
|
|
|
|
type DeepSeekConfig struct {
|
|
BaseURL string `json:"base_url"`
|
|
Model string `json:"model"`
|
|
APIKey string `json:"api_key"`
|
|
Timeout time.Duration `json:"timeout"`
|
|
}
|
|
|
|
type SandboxConfig struct {
|
|
Timeout time.Duration `json:"timeout"`
|
|
MaxMemory int64 `json:"max_memory"`
|
|
WorkingDir string `json:"working_dir"`
|
|
}
|
|
|
|
type SessionConfig struct {
|
|
StorageDir string `json:"storage_dir"`
|
|
MaxHistory int `json:"max_history"`
|
|
}
|
|
|
|
func DefaultConfig() *Config {
|
|
return &Config{
|
|
Provider: ProviderDeepSeek,
|
|
Ollama: OllamaConfig{
|
|
BaseURL: "http://localhost:11434",
|
|
Model: "gemma4:e4b",
|
|
Timeout: 120 * time.Second,
|
|
},
|
|
DeepSeek: DeepSeekConfig{
|
|
BaseURL: "https://api.deepseek.com/v1",
|
|
Model: "deepseek-v4-flash",
|
|
APIKey: "sk-2f1049148e06492dbc304ba49c81c321",
|
|
Timeout: 120 * time.Second,
|
|
},
|
|
Sandbox: SandboxConfig{
|
|
Timeout: 30 * time.Second,
|
|
MaxMemory: 512 * 1024 * 1024,
|
|
WorkingDir: "/tmp/orca/sandbox",
|
|
},
|
|
Session: SessionConfig{
|
|
StorageDir: func() string {
|
|
home, _ := os.UserHomeDir()
|
|
return home + "/.orca/sessions"
|
|
}(),
|
|
MaxHistory: 100,
|
|
},
|
|
}
|
|
}
|
|
|
|
func LoadConfigFromEnv() *Config {
|
|
cfg := DefaultConfig()
|
|
|
|
if v := os.Getenv("ORCA_PROVIDER"); v != "" {
|
|
cfg.Provider = v
|
|
}
|
|
if v := os.Getenv("ORCA_OLLAMA_BASE_URL"); v != "" {
|
|
cfg.Ollama.BaseURL = v
|
|
}
|
|
if v := os.Getenv("ORCA_OLLAMA_MODEL"); v != "" {
|
|
cfg.Ollama.Model = v
|
|
}
|
|
if v := os.Getenv("ORCA_OLLAMA_TIMEOUT"); v != "" {
|
|
if d, err := time.ParseDuration(v); err == nil {
|
|
cfg.Ollama.Timeout = d
|
|
}
|
|
}
|
|
if v := os.Getenv("ORCA_DEEPSEEK_BASE_URL"); v != "" {
|
|
cfg.DeepSeek.BaseURL = v
|
|
}
|
|
if v := os.Getenv("ORCA_DEEPSEEK_MODEL"); v != "" {
|
|
cfg.DeepSeek.Model = v
|
|
}
|
|
if v := os.Getenv("ORCA_DEEPSEEK_API_KEY"); v != "" {
|
|
cfg.DeepSeek.APIKey = v
|
|
}
|
|
if v := os.Getenv("ORCA_DEEPSEEK_TIMEOUT"); v != "" {
|
|
if d, err := time.ParseDuration(v); err == nil {
|
|
cfg.DeepSeek.Timeout = d
|
|
}
|
|
}
|
|
if v := os.Getenv("ORCA_SANDBOX_TIMEOUT"); v != "" {
|
|
if d, err := time.ParseDuration(v); err == nil {
|
|
cfg.Sandbox.Timeout = d
|
|
}
|
|
}
|
|
if v := os.Getenv("ORCA_SANDBOX_MAX_MEMORY"); v != "" {
|
|
if n, err := strconv.ParseInt(v, 10, 64); err == nil {
|
|
cfg.Sandbox.MaxMemory = n
|
|
}
|
|
}
|
|
if v := os.Getenv("ORCA_SANDBOX_WORKING_DIR"); v != "" {
|
|
cfg.Sandbox.WorkingDir = v
|
|
}
|
|
if v := os.Getenv("ORCA_SESSION_STORAGE_DIR"); v != "" {
|
|
cfg.Session.StorageDir = v
|
|
}
|
|
if v := os.Getenv("ORCA_SESSION_MAX_HISTORY"); v != "" {
|
|
if n, err := strconv.Atoi(v); err == nil {
|
|
cfg.Session.MaxHistory = n
|
|
}
|
|
}
|
|
|
|
return cfg
|
|
}
|
|
|
|
func (c *Config) IsValid() error {
|
|
if c.Provider != ProviderOllama && c.Provider != ProviderDeepSeek {
|
|
return errConfig("provider must be 'ollama' or 'deepseek'")
|
|
}
|
|
if c.Provider == ProviderOllama {
|
|
if c.Ollama.BaseURL == "" {
|
|
return errConfig("ollama.base_url must not be empty")
|
|
}
|
|
if c.Ollama.Model == "" {
|
|
return errConfig("ollama.model must not be empty")
|
|
}
|
|
if c.Ollama.Timeout <= 0 {
|
|
return errConfig("ollama.timeout must be positive")
|
|
}
|
|
}
|
|
if c.Provider == ProviderDeepSeek {
|
|
if c.DeepSeek.BaseURL == "" {
|
|
return errConfig("deepseek.base_url must not be empty")
|
|
}
|
|
if c.DeepSeek.Model == "" {
|
|
return errConfig("deepseek.model must not be empty")
|
|
}
|
|
if c.DeepSeek.APIKey == "" {
|
|
return errConfig("deepseek.api_key must not be empty")
|
|
}
|
|
if c.DeepSeek.Timeout <= 0 {
|
|
return errConfig("deepseek.timeout must be positive")
|
|
}
|
|
}
|
|
if c.Sandbox.Timeout <= 0 {
|
|
return errConfig("sandbox.timeout must be positive")
|
|
}
|
|
if c.Sandbox.MaxMemory <= 0 {
|
|
return errConfig("sandbox.max_memory must be positive")
|
|
}
|
|
if c.Session.MaxHistory <= 0 {
|
|
return errConfig("session.max_history must be positive")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func errConfig(msg string) error {
|
|
return &ConfigError{Message: msg}
|
|
}
|
|
|
|
type ConfigError struct {
|
|
Message string
|
|
}
|
|
|
|
func (e *ConfigError) Error() string {
|
|
return "config: " + e.Message
|
|
}
|