orca.ai/internal/config/config.go
大森 286d3dae3c feat: add DeepSeek LLM provider support
- 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.)
2026-05-08 22:04:18 +08:00

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
}