package agent import ( "bufio" "os" "path/filepath" "strconv" "strings" "time" ) type Config struct { APIKey string BaseURL string Model string Port string Workspace string DataDir string // AuthCode 是 Web/API/WS 访问授权码。为空(默认)表示不启用授权; // 非空(Docker 部署时通过环境变量 AGENT_AUTH_CODE 注入)表示启用: // 访问者必须输入正确授权码才能使用本实例。 AuthCode string MaxContextTokens int KeepRecentMessages int MaxToolResultChars int MaxIterations int ToolTimeout time.Duration RequestTimeout time.Duration StreamOutputTokens int CompactionTokens int Temperature float64 } func LoadConfig() Config { loadDotEnv(".env") workspace := getenv("AGENT_WORKSPACE", "") if workspace == "" { workspace, _ = os.Getwd() } absWorkspace, err := filepath.Abs(workspace) if err != nil { absWorkspace = workspace } dataDir := getenv("AGENT_DATA_DIR", filepath.Join(absWorkspace, "data")) if !filepath.IsAbs(dataDir) { dataDir = filepath.Join(absWorkspace, dataDir) } cfg := Config{ APIKey: os.Getenv("SILICONFLOW_API_KEY"), BaseURL: getenv("SILICONFLOW_BASE_URL", "https://api.siliconflow.cn/v1/chat/completions"), Model: getenv("AGENT_MODEL", "Qwen/Qwen3-32B"), Port: getenv("AGENT_PORT", "8080"), Workspace: absWorkspace, DataDir: dataDir, // 全面放开限制以适配 DeepSeek(128K 上下文、大输出)跑复杂任务: // - MaxContextTokens 给到 1M,确保 compactionInputBudget 公式(window - Compaction - Stream - window/8)仍有充足余量 // - StreamOutputTokens 提升到 65536:直接作为 max_tokens 传给 LLM(见 llm.go),是放开主 Agent 输出能力的关键 // - CompactionTokens 提升到 16384:压缩摘要允许足够长度,避免历史信息丢失 // - MaxToolResultChars 提升到 100000:复杂任务的脚本/日志能完整传回 LLM,不被截断 // - KeepRecentMessages 提升到 50:压缩后保留更多历史,复杂多步任务上下文不丢 // - ToolTimeout/RequestTimeout 提升到 600s:编译/长命令/深度推理有充足时间 MaxContextTokens: getenvInt("AGENT_MAX_CONTEXT_TOKENS", 1000000), KeepRecentMessages: getenvInt("AGENT_KEEP_RECENT_MESSAGES", 50), MaxToolResultChars: getenvInt("AGENT_MAX_TOOL_RESULT_CHARS", 100000), MaxIterations: getenvInt("AGENT_MAX_ITERATIONS", 50), ToolTimeout: time.Duration(getenvInt("AGENT_TOOL_TIMEOUT_SECONDS", 600)) * time.Second, RequestTimeout: time.Duration(getenvInt("AGENT_REQUEST_TIMEOUT_SECONDS", 600)) * time.Second, StreamOutputTokens: getenvInt("AGENT_STREAM_OUTPUT_TOKENS", 65536), CompactionTokens: getenvInt("AGENT_COMPACTION_TOKENS", 16384), Temperature: getenvFloat("AGENT_TEMPERATURE", 0.3), // 授权码默认关闭:仅当 Docker 部署时显式注入 AGENT_AUTH_CODE 才启用访问授权。 AuthCode: getenv("AGENT_AUTH_CODE", ""), } return cfg } func loadDotEnv(path string) { file, err := os.Open(path) if err != nil { return } defer file.Close() scanner := bufio.NewScanner(file) for scanner.Scan() { line := strings.TrimSpace(scanner.Text()) if line == "" || strings.HasPrefix(line, "#") { continue } key, value, ok := strings.Cut(line, "=") if !ok { continue } key = strings.TrimSpace(key) value = strings.TrimSpace(value) value = strings.Trim(value, `"'`) if key == "" { continue } if _, exists := os.LookupEnv(key); !exists { _ = os.Setenv(key, value) } } } func getenv(key, fallback string) string { if value := os.Getenv(key); value != "" { return value } return fallback } func getenvInt(key string, fallback int) int { value := os.Getenv(key) if value == "" { return fallback } parsed, err := strconv.Atoi(value) if err != nil { return fallback } return parsed } func getenvFloat(key string, fallback float64) float64 { value := os.Getenv(key) if value == "" { return fallback } parsed, err := strconv.ParseFloat(value, 64) if err != nil { return fallback } return parsed }