package config import ( "fmt" "os" "strconv" "strings" "time" ) // This is a container-adapted version of BZZZ's config system // All configuration comes from environment variables instead of YAML files // Config represents the complete CHORUS configuration loaded from environment variables type Config struct { Agent AgentConfig `yaml:"agent"` Network NetworkConfig `yaml:"network"` License LicenseConfig `yaml:"license"` AI AIConfig `yaml:"ai"` Logging LoggingConfig `yaml:"logging"` V2 V2Config `yaml:"v2"` UCXL UCXLConfig `yaml:"ucxl"` Slurp SlurpConfig `yaml:"slurp"` } // AgentConfig defines agent-specific settings type AgentConfig struct { ID string `yaml:"id"` Specialization string `yaml:"specialization"` MaxTasks int `yaml:"max_tasks"` Capabilities []string `yaml:"capabilities"` Models []string `yaml:"models"` Role string `yaml:"role"` Expertise []string `yaml:"expertise"` ReportsTo string `yaml:"reports_to"` Deliverables []string `yaml:"deliverables"` ModelSelectionWebhook string `yaml:"model_selection_webhook"` DefaultReasoningModel string `yaml:"default_reasoning_model"` } // NetworkConfig defines network and API settings type NetworkConfig struct { P2PPort int `yaml:"p2p_port"` APIPort int `yaml:"api_port"` HealthPort int `yaml:"health_port"` BindAddr string `yaml:"bind_address"` } // LicenseConfig defines licensing settings (adapted from BZZZ) type LicenseConfig struct { Email string `yaml:"email"` LicenseKey string `yaml:"license_key"` ClusterID string `yaml:"cluster_id"` OrganizationName string `yaml:"organization_name"` KachingURL string `yaml:"kaching_url"` IsActive bool `yaml:"is_active"` LastValidated time.Time `yaml:"last_validated"` GracePeriodHours int `yaml:"grace_period_hours"` LicenseType string `yaml:"license_type"` ExpiresAt time.Time `yaml:"expires_at"` MaxNodes int `yaml:"max_nodes"` } // AIConfig defines AI service settings type AIConfig struct { Ollama OllamaConfig `yaml:"ollama"` } // OllamaConfig defines Ollama-specific settings type OllamaConfig struct { Endpoint string `yaml:"endpoint"` Timeout time.Duration `yaml:"timeout"` } // LoggingConfig defines logging settings type LoggingConfig struct { Level string `yaml:"level"` Format string `yaml:"format"` } // V2Config defines v2-specific settings (from BZZZ) type V2Config struct { DHT DHTConfig `yaml:"dht"` } // DHTConfig defines DHT settings type DHTConfig struct { Enabled bool `yaml:"enabled"` BootstrapPeers []string `yaml:"bootstrap_peers"` } // UCXLConfig defines UCXL protocol settings type UCXLConfig struct { Enabled bool `yaml:"enabled"` Server ServerConfig `yaml:"server"` Storage StorageConfig `yaml:"storage"` Resolution ResolutionConfig `yaml:"resolution"` } // ServerConfig defines server settings type ServerConfig struct { Enabled bool `yaml:"enabled"` Port int `yaml:"port"` BasePath string `yaml:"base_path"` } // StorageConfig defines storage settings type StorageConfig struct { Directory string `yaml:"directory"` } // ResolutionConfig defines resolution settings type ResolutionConfig struct { CacheTTL time.Duration `yaml:"cache_ttl"` } // SlurpConfig defines SLURP settings type SlurpConfig struct { Enabled bool `yaml:"enabled"` } // LoadFromEnvironment loads configuration from environment variables func LoadFromEnvironment() (*Config, error) { cfg := &Config{ Agent: AgentConfig{ ID: getEnvOrDefault("CHORUS_AGENT_ID", ""), Specialization: getEnvOrDefault("CHORUS_SPECIALIZATION", "general_developer"), MaxTasks: getEnvIntOrDefault("CHORUS_MAX_TASKS", 3), Capabilities: getEnvArrayOrDefault("CHORUS_CAPABILITIES", []string{"general_development", "task_coordination"}), Models: getEnvArrayOrDefault("CHORUS_MODELS", []string{"llama3.1:8b"}), Role: getEnvOrDefault("CHORUS_ROLE", ""), Expertise: getEnvArrayOrDefault("CHORUS_EXPERTISE", []string{}), ReportsTo: getEnvOrDefault("CHORUS_REPORTS_TO", ""), Deliverables: getEnvArrayOrDefault("CHORUS_DELIVERABLES", []string{}), ModelSelectionWebhook: getEnvOrDefault("CHORUS_MODEL_SELECTION_WEBHOOK", ""), DefaultReasoningModel: getEnvOrDefault("CHORUS_DEFAULT_REASONING_MODEL", "llama3.1:8b"), }, Network: NetworkConfig{ P2PPort: getEnvIntOrDefault("CHORUS_P2P_PORT", 9000), APIPort: getEnvIntOrDefault("CHORUS_API_PORT", 8080), HealthPort: getEnvIntOrDefault("CHORUS_HEALTH_PORT", 8081), BindAddr: getEnvOrDefault("CHORUS_BIND_ADDRESS", "0.0.0.0"), }, License: LicenseConfig{ Email: os.Getenv("CHORUS_LICENSE_EMAIL"), LicenseKey: os.Getenv("CHORUS_LICENSE_KEY"), ClusterID: getEnvOrDefault("CHORUS_CLUSTER_ID", "default-cluster"), OrganizationName: getEnvOrDefault("CHORUS_ORGANIZATION_NAME", ""), KachingURL: getEnvOrDefault("CHORUS_KACHING_URL", "https://kaching.chorus.services"), IsActive: false, // Will be set during validation GracePeriodHours: getEnvIntOrDefault("CHORUS_GRACE_PERIOD_HOURS", 72), }, AI: AIConfig{ Ollama: OllamaConfig{ Endpoint: getEnvOrDefault("OLLAMA_ENDPOINT", "http://localhost:11434"), Timeout: getEnvDurationOrDefault("OLLAMA_TIMEOUT", 30*time.Second), }, }, Logging: LoggingConfig{ Level: getEnvOrDefault("LOG_LEVEL", "info"), Format: getEnvOrDefault("LOG_FORMAT", "structured"), }, V2: V2Config{ DHT: DHTConfig{ Enabled: getEnvBoolOrDefault("CHORUS_DHT_ENABLED", true), BootstrapPeers: getEnvArrayOrDefault("CHORUS_BOOTSTRAP_PEERS", []string{}), }, }, UCXL: UCXLConfig{ Enabled: getEnvBoolOrDefault("CHORUS_UCXL_ENABLED", true), Server: ServerConfig{ Enabled: getEnvBoolOrDefault("CHORUS_UCXL_SERVER_ENABLED", true), Port: getEnvIntOrDefault("CHORUS_UCXL_SERVER_PORT", 8082), BasePath: getEnvOrDefault("CHORUS_UCXL_SERVER_BASE_PATH", ""), }, Storage: StorageConfig{ Directory: getEnvOrDefault("CHORUS_UCXL_STORAGE_DIRECTORY", "/tmp/chorus-ucxi-storage"), }, Resolution: ResolutionConfig{ CacheTTL: getEnvDurationOrDefault("CHORUS_UCXL_CACHE_TTL", 1*time.Hour), }, }, Slurp: SlurpConfig{ Enabled: getEnvBoolOrDefault("CHORUS_SLURP_ENABLED", false), }, } // Validate required configuration if err := cfg.Validate(); err != nil { return nil, fmt.Errorf("configuration validation failed: %w", err) } return cfg, nil } // Validate ensures all required configuration is present func (c *Config) Validate() error { if c.License.Email == "" { return fmt.Errorf("CHORUS_LICENSE_EMAIL is required") } if c.License.LicenseKey == "" { return fmt.Errorf("CHORUS_LICENSE_KEY is required") } if c.Agent.ID == "" { // Auto-generate agent ID if not provided hostname, _ := os.Hostname() containerID := os.Getenv("HOSTNAME") // Docker sets this to container ID if containerID != "" && containerID != hostname { c.Agent.ID = fmt.Sprintf("chorus-%s", containerID[:12]) } else { c.Agent.ID = fmt.Sprintf("chorus-%s", hostname) } } return nil } // ApplyRoleDefinition applies role-based configuration (from BZZZ) func (c *Config) ApplyRoleDefinition(role string) error { // This would contain the role definition logic from BZZZ c.Agent.Role = role return nil } // GetRoleAuthority returns the authority level for a role (from BZZZ) func (c *Config) GetRoleAuthority(role string) (string, error) { // This would contain the authority mapping from BZZZ switch role { case "admin": return "master", nil default: return "member", nil } } // Helper functions for environment variable parsing func getEnvOrDefault(key, defaultValue string) string { if value := os.Getenv(key); value != "" { return value } return defaultValue } func getEnvIntOrDefault(key string, defaultValue int) int { if value := os.Getenv(key); value != "" { if parsed, err := strconv.Atoi(value); err == nil { return parsed } } return defaultValue } func getEnvBoolOrDefault(key string, defaultValue bool) bool { if value := os.Getenv(key); value != "" { if parsed, err := strconv.ParseBool(value); err == nil { return parsed } } return defaultValue } func getEnvDurationOrDefault(key string, defaultValue time.Duration) time.Duration { if value := os.Getenv(key); value != "" { if parsed, err := time.ParseDuration(value); err == nil { return parsed } } return defaultValue } func getEnvArrayOrDefault(key string, defaultValue []string) []string { if value := os.Getenv(key); value != "" { return strings.Split(value, ",") } return defaultValue } // IsSetupRequired checks if setup is required (always false for containers) func IsSetupRequired(configPath string) bool { return false // Containers are always pre-configured via environment } // IsValidConfiguration validates configuration (simplified for containers) func IsValidConfiguration(cfg *Config) bool { return cfg.License.Email != "" && cfg.License.LicenseKey != "" }