package config import ( "github.com/spf13/viper" ) type NodeConfig struct { Transport TransportConf `mapstructure:"transport" yaml:"transport"` Logging LoggingConf `mapstructure:"logging" yaml:"logging"` Metrics MetricsConf `mapstructure:"metrics" yaml:"metrics"` } type EdgeConfig struct { Server EdgeServerConf `mapstructure:"server" yaml:"server"` TLS TLSConf `mapstructure:"tls" yaml:"tls"` Logging LoggingConf `mapstructure:"logging" yaml:"logging"` Metrics MetricsConf `mapstructure:"metrics" yaml:"metrics"` Console EdgeConsoleConf `mapstructure:"console" yaml:"console"` Nodes []NodeDefinition `mapstructure:"nodes" yaml:"nodes"` } // NodeDefinition is the edge-side record for a pre-registered node. type NodeDefinition struct { ID string `mapstructure:"id" yaml:"id"` // optional; UUID v4 auto-assigned if empty Alias string `mapstructure:"alias" yaml:"alias"` Token string `mapstructure:"token" yaml:"token"` Adapters AdaptersConf `mapstructure:"adapters" yaml:"adapters"` Runtime RuntimeConf `mapstructure:"runtime" yaml:"runtime"` } type NodeInfo struct { ID string `mapstructure:"id" yaml:"id"` Name string `mapstructure:"name" yaml:"name"` } type EdgeServerConf struct { Listen string `mapstructure:"listen" yaml:"listen"` } type EdgeConsoleConf struct { Adapter string `mapstructure:"adapter" yaml:"adapter"` Agent string `mapstructure:"agent" yaml:"agent"` Model string `mapstructure:"model" yaml:"model"` SessionID string `mapstructure:"session_id" yaml:"session_id"` Background bool `mapstructure:"background" yaml:"background"` TimeoutSec int `mapstructure:"timeout_sec" yaml:"timeout_sec"` } func (c EdgeConsoleConf) ResolveAgent() string { if c.Agent != "" { return c.Agent } return c.Model } type TransportConf struct { EdgeAddr string `mapstructure:"edge_addr" yaml:"edge_addr"` Token string `mapstructure:"token" yaml:"token"` } type TLSConf struct { Enabled bool `mapstructure:"enabled" yaml:"enabled"` Cert string `mapstructure:"cert" yaml:"cert"` Key string `mapstructure:"key" yaml:"key"` CA string `mapstructure:"ca" yaml:"ca"` } type RuntimeConf struct { Concurrency int `mapstructure:"concurrency" yaml:"concurrency"` WorkspaceRoot string `mapstructure:"workspace_root" yaml:"workspace_root"` } type SQLiteConf struct { DSN string `mapstructure:"dsn" yaml:"dsn"` } type LoggingConf struct { Level string `mapstructure:"level" yaml:"level"` Pretty bool `mapstructure:"pretty" yaml:"pretty"` } type MetricsConf struct { Port int `mapstructure:"port" yaml:"port"` } type AdaptersConf struct { Ollama OllamaConf `mapstructure:"ollama" yaml:"ollama"` Vllm VllmConf `mapstructure:"vllm" yaml:"vllm"` CLI CLIConf `mapstructure:"cli" yaml:"cli"` } type OllamaConf struct { Enabled bool `mapstructure:"enabled" yaml:"enabled"` BaseURL string `mapstructure:"base_url" yaml:"base_url"` } type VllmConf struct { Enabled bool `mapstructure:"enabled" yaml:"enabled"` Endpoint string `mapstructure:"endpoint" yaml:"endpoint"` } type CLIConf struct { Enabled bool `mapstructure:"enabled" yaml:"enabled"` Profiles map[string]CLIProfileConf `mapstructure:"profiles" yaml:"profiles"` } type CLIProfileConf struct { Command string `mapstructure:"command" yaml:"command"` Args []string `mapstructure:"args" yaml:"args"` Env []string `mapstructure:"env" yaml:"env"` Persistent bool `mapstructure:"persistent" yaml:"persistent"` Terminal bool `mapstructure:"terminal" yaml:"terminal"` ResponseIdleTimeoutMS int `mapstructure:"response_idle_timeout_ms" yaml:"response_idle_timeout_ms"` StartupIdleTimeoutMS int `mapstructure:"startup_idle_timeout_ms" yaml:"startup_idle_timeout_ms"` OutputFormat string `mapstructure:"output_format" yaml:"output_format"` CompletionMarker CompletionMarkerConf `mapstructure:"completion_marker" yaml:"completion_marker"` Mode string `mapstructure:"mode" yaml:"mode"` ResumeArgs []string `mapstructure:"resume_args" yaml:"resume_args"` } type CompletionMarkerConf struct { Line string `mapstructure:"line" yaml:"line"` Regex string `mapstructure:"regex" yaml:"regex"` } func (m CompletionMarkerConf) Empty() bool { return m.Line == "" && m.Regex == "" } func Load(cfgFile string) (*NodeConfig, error) { v := viper.New() v.SetConfigFile(cfgFile) setDefaults(v) if err := v.ReadInConfig(); err != nil { return nil, err } var cfg NodeConfig if err := v.Unmarshal(&cfg); err != nil { return nil, err } return &cfg, nil } func LoadEdge(cfgFile string) (*EdgeConfig, error) { v := viper.New() v.SetConfigFile(cfgFile) setEdgeDefaults(v) if err := v.ReadInConfig(); err != nil { return nil, err } var cfg EdgeConfig if err := v.Unmarshal(&cfg); err != nil { return nil, err } if !v.InConfig("console.agent") && v.InConfig("console.model") { cfg.Console.Agent = cfg.Console.Model } return &cfg, nil } func setDefaults(v *viper.Viper) { v.SetDefault("transport.edge_addr", "localhost:9090") v.SetDefault("logging.level", "info") v.SetDefault("metrics.port", 9091) } func setEdgeDefaults(v *viper.Viper) { v.SetDefault("server.listen", "0.0.0.0:9090") v.SetDefault("logging.level", "info") v.SetDefault("metrics.port", 9092) v.SetDefault("tls.enabled", false) v.SetDefault("console.adapter", "cli") v.SetDefault("console.agent", "claude") v.SetDefault("console.session_id", "default") v.SetDefault("console.background", false) v.SetDefault("console.timeout_sec", 120) }