package config import ( "agent-desk/internal/pkg/enums" "fmt" "strings" "github.com/spf13/viper" ) type Config struct { Server ServerConfig `yaml:"server"` DB DBConfig `yaml:"db"` Logger LoggerConfig `yaml:"logger"` Auth AuthConfig `yaml:"auth"` Storage StorageConfig `yaml:"storage"` VectorDB VectorDBConfig `yaml:"vectorDB"` MCP MCPConfig `yaml:"mcp"` WxWork WxWorkConfig `yaml:"wxWork"` OIDC OIDCConfig `yaml:"oidc"` CustomerSession CustomerSessionConfig `yaml:"customerSession"` } type WxWorkNotifyConfig struct { Enabled bool `yaml:"enabled"` ToUsers []int64 `yaml:"toUsers"` Safe bool `yaml:"safe"` EnableDuplicateCheck bool `yaml:"enableDuplicateCheck"` DuplicateCheckInterval int `yaml:"duplicateCheckInterval"` } type ServerConfig struct { Port int `yaml:"port"` CORS CORSConfig `yaml:"cors"` } func (s ServerConfig) Address() string { if s.Port <= 0 { return ":8080" } return fmt.Sprintf(":%d", s.Port) } type CORSConfig struct { // AllowedOrigins 是允许浏览器跨域访问的 Origin 白名单,必须包含协议和域名。 // 留空表示不允许跨域请求;同源请求通常不会携带 Origin,不受影响。 AllowedOrigins []string `yaml:"allowedOrigins"` } type DBConfig struct { Type string `yaml:"type"` DSN string `yaml:"dsn"` MaxIdleConns int `yaml:"maxIdleConns"` MaxOpenConns int `yaml:"maxOpenConns"` ConnMaxIdleTimeSeconds int `yaml:"connMaxIdleTimeSeconds"` ConnMaxLifetimeSeconds int `yaml:"connMaxLifetimeSeconds"` } type LoggerConfig struct { Level string `yaml:"level"` Format string `yaml:"format"` AddSource bool `yaml:"addSource"` } type AuthConfig struct { TokenTTLHours int `yaml:"tokenTTLHours"` MaxFailedAttempts int `yaml:"maxFailedAttempts"` CredentialLockMinute int `yaml:"credentialLockMinute"` } type CustomerSessionConfig struct { Secret string `yaml:"secret"` TTLMinutes int `yaml:"ttlMinutes"` RefreshThresholdMinutes int `yaml:"refreshThresholdMinutes"` } func (c CustomerSessionConfig) TTL() int { if c.TTLMinutes <= 0 { return 120 } return c.TTLMinutes } func (c CustomerSessionConfig) RefreshThreshold() int { if c.RefreshThresholdMinutes <= 0 { return 30 } return c.RefreshThresholdMinutes } type StorageConfig struct { Default enums.AssetProvider `yaml:"default"` MaxUploadSizeMB int64 `yaml:"maxUploadSizeMB"` Local LocalStorageConfig `yaml:"local"` OSS OSSStorageConfig `yaml:"oss"` } func (s StorageConfig) MaxUploadSizeBytes() int64 { if s.MaxUploadSizeMB <= 0 { return 5 << 20 } return s.MaxUploadSizeMB << 20 } func (s StorageConfig) MaxRequestBodySizeBytes() int64 { limit := s.MaxUploadSizeBytes() return limit + (1 << 20) } type LocalStorageConfig struct { Root string `yaml:"root"` BaseURL string `yaml:"baseUrl"` } type OSSStorageConfig struct { Endpoint string `yaml:"endpoint"` Bucket string `yaml:"bucket"` AccessKeyID string `yaml:"accessKeyId"` AccessKeySecret string `yaml:"accessKeySecret"` BaseURL string `yaml:"baseUrl"` Private bool `yaml:"private"` SignedURLExpire int `yaml:"signedUrlExpireSeconds"` } type VectorDBConfig struct { Type string `yaml:"type"` Qdrant QdrantVectorDBConfig `yaml:"qdrant"` LanceDB LanceDBVectorDBConfig `yaml:"lancedb"` } type QdrantVectorDBConfig struct { Host string `yaml:"host"` GrpcPort int `yaml:"grpcPort"` APIKey string `yaml:"apiKey"` UseTLS bool `yaml:"useTls"` } type LanceDBVectorDBConfig struct { Path string `yaml:"path"` } type MCPConfig struct { Enabled bool `yaml:"enabled"` Servers map[string]MCPServerConfig `yaml:"servers"` } type MCPServerConfig struct { Enabled bool `yaml:"enabled"` Endpoint string `yaml:"endpoint"` TimeoutMS int `yaml:"timeoutMs"` Headers map[string]string `yaml:"headers"` } type OIDCConfig struct { Enabled bool `yaml:"enabled"` Issuer string `yaml:"issuer"` ClientID string `yaml:"clientId"` ClientSecret string `yaml:"clientSecret"` RedirectURL string `yaml:"redirectUrl"` StateSecret string `yaml:"stateSecret"` Scopes []string `yaml:"scopes"` } // WxWorkConfig 定义企业微信接入配置。 // // 当前主要用于后台管理台的企业微信登录流程: // 1. /api/auth/wxwork/login 生成企业微信授权地址 // 2. 企业微信回调到 OAuthRedirect // 3. 后端通过 code 换取企业成员身份并完成系统登录 // // 其中 OAuthRedirect、CorpID、CorpSecret、AgentID 为登录流程核心配置。 type WxWorkConfig struct { // Enabled 表示是否启用企业微信登录能力。 // false 时不会初始化企业微信 SDK,相关登录接口不可用。 Enabled bool `yaml:"enabled"` // CorpID 为企业微信公司 ID,例如 wwxxxxxxxxxxxxxxxx。 CorpID string `yaml:"corpId"` // CorpSecret 为企业微信应用 Secret,用于换取 access_token。 CorpSecret string `yaml:"corpSecret"` // AgentID 为企业微信自建应用 AgentID。 AgentID string `yaml:"agentId"` // OAuthRedirect 为企业微信网页授权回调地址。 // 必须填写完整 URL,且通常指向后端接口 /api/auth/wxwork/callback。 OAuthRedirect string `yaml:"oauthRedirect"` // StateSecret 为登录 state 的签名密钥,用于防止篡改和重放。 // 建议填写独立随机字符串;留空时业务代码会退回使用 CorpSecret。 StateSecret string `yaml:"stateSecret"` // RSAPrivateKey 为企业微信回调解密私钥。 // 当前登录流程未使用,保留给消息回调等场景。 RSAPrivateKey string `yaml:"rsaPrivateKey"` // Token 为企业微信回调 Token。 // 当前登录流程未使用,保留给消息回调等场景。 Token string `yaml:"token"` // EncodingAESKey 为企业微信消息加解密密钥。 // 当前登录流程未使用,保留给消息回调等场景。 EncodingAESKey string `yaml:"encodingAESKey"` // Notify 为企业微信应用消息通知配置。 Notify WxWorkNotifyConfig `yaml:"notify"` } func Load(path string) (*Config, error) { v := viper.New() v.SetConfigFile(path) v.SetConfigType("yaml") v.SetEnvPrefix("AGENT_DESK") v.SetEnvKeyReplacer(strings.NewReplacer(".", "_")) v.AutomaticEnv() if err := v.ReadInConfig(); err != nil { return nil, err } cfg := &Config{} if err := v.Unmarshal(cfg); err != nil { return nil, err } return cfg, nil }