Files
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
8.7 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "acosmi-fushihua/crabclaw", "files": {"backend/internal/agents/models/providers.go": {"f1ed71addaa2352c15c98de18228056cd03e5773": {"t": 1786068297.9697924, "n": 7330, "h": "80935e4e00672a99", "c": "package models\n\nimport (\n\t\"os\"\n\t\"strings\"\n\n\t\"github.com/Acosmi/CrabClawApp/pkg/types\"\n)\n\n// ---------- 供应商配置 ----------\n\n// TS 参考: src/agents/models-config.providers.ts (637 行)\n\n// ProviderDefaults 供应商默认配置。\ntype ProviderDefaults struct {\n\tBaseURL string `json:\"baseUrl,omitempty\"`\n\tAPIURL string `json:\"apiUrl,omitempty\"`\n\tDefaultModel string `json:\"defaultModel,omitempty\"`\n\tContextWindow int `json:\"contextWindow,omitempty\"`\n\tMaxTokens int `json:\"maxTokens,omitempty\"`\n\tCostInput float64 `json:\"costInput,omitempty\"`\n\tCostOutput float64 `json:\"costOutput,omitempty\"`\n\tCostCacheRead float64 `json:\"costCacheRead,omitempty\"`\n\tCostCacheWrite float64 `json:\"costCacheWrite,omitempty\"`\n}\n\n// 供应商默认值\n// TS 参考: models-config.providers.ts 常量定义\nvar providerDefaults = map[string]ProviderDefaults{\n\t\"minimax\": {\n\t\tBaseURL: \"https://api.minimax.io/v1\",\n\t\tDefaultModel: \"MiniMax-Text-01\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 8192,\n\t},\n\t\"minimax-portal\": {\n\t\tBaseURL: \"https://api.minimax.io/anthropic\",\n\t\tDefaultModel: \"MiniMax-M2.7\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 8192,\n\t},\n\t\"moonshot\": {\n\t\tBaseURL: \"https://api.moonshot.ai/v1\",\n\t\tDefaultModel: \"moonshot-v1-kimi-k2\", // K2.5 稳定别名(2026-01-27)\n\t\tContextWindow: 131_072,\n\t\tMaxTokens: 16384,\n\t},\n\t\"qwen-portal\": {\n\t\tBaseURL: \"https://portal.qwen.ai/v1\",\n\t\tDefaultModel: \"qwen3.6-plus\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 81920,\n\t},\n\t\"ollama\": {\n\t\tBaseURL: \"http://127.0.0.1:11434/v1\",\n\t\tAPIURL: \"http://127.0.0.1:11434\",\n\t\tContextWindow: 128_000,\n\t\tMaxTokens: 8192,\n\t},\n\t\"deepseek\": {\n\t\tBaseURL: \"https://api.deepseek.com/v1\",\n\t\tDefaultModel: \"deepseek-chat\",\n\t\tContextWindow: 131_072, // DeepSeek-V3.2 实际 128K\n\t\tMaxTokens: 8192,\n\t},\n\t\"google\": {\n\t\tBaseURL: \"https://generativelanguage.googleapis.com/v1beta\",\n\t\tDefaultModel: \"gemini-2.5-flash\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 8192,\n\t},\n\t\"doubao\": {\n\t\tBaseURL: \"https://ark.cn-beijing.volces.com/api/v3\",\n\t\tDefaultModel: \"doubao-seed-2-0-pro-260215\",\n\t\tContextWindow: 131_072,\n\t\tMaxTokens: 16384,\n\t},\n\t\"qwen\": {\n\t\tBaseURL: \"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n\t\tDefaultModel: \"qwen3.6-plus\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 81920,\n\t},\n\t\"zai\": {\n\t\tBaseURL: \"https://open.bigmodel.cn/api/paas/v4\",\n\t\tDefaultModel: \"glm-5.1\",\n\t\tContextWindow: 204_800,\n\t\tMaxTokens: 65536,\n\t},\n\t\"openai\": {\n\t\tBaseURL: \"https://api.openai.com/v1\",\n\t\tDefaultModel: \"gpt-5.4\",\n\t\tContextWindow: 1_000_000,\n\t\tMaxTokens: 32768,\n\t},\n\t\"anthropic\": {\n\t\tBaseURL: \"https://api.anthropic.com/v1\",\n\t\tDefaultModel: \"claude-sonnet-4-20250514\",\n\t\tContextWindow: 200_000,\n\t\tMaxTokens: 8192,\n\t},\n\t\"xai\": {\n\t\tBaseURL: \"https://api.x.ai/v1\",\n\t\tDefaultModel: \"grok-3\",\n\t\tContextWindow: 131_072,\n\t\tMaxTokens: 8192,\n\t},\n}\n\n// EnvApiKeyVarNames 供应商 API Key 环境变量名映射。\n// P4-DRIFT4: 对齐 TS model-auth.ts L287-307 完整映射。\nvar EnvApiKeyVarNames = map[string]string{\n\t\"anthropic\": \"ANTHROPIC_API_KEY\",\n\t\"openai\": \"OPENAI_API_KEY\",\n\t\"google\": \"GEMINI_API_KEY\",\n\t\"deepseek\": \"DEEPSEEK_API_KEY\",\n\t\"qwen\": \"DASHSCOPE_API_KEY\",\n\t\"qwen-portal\": \"DASHSCOPE_API_KEY\",\n\t\"moonshot\": \"MOONSHOT_API_KEY\",\n\t\"minimax\": \"MINIMAX_API_KEY\",\n\t\"minimax-portal\": \"MINIMAX_API_KEY\",\n\t\"xai\": \"XAI_API_KEY\",\n\t\"zai\": \"ZAI_API_KEY\",\n\t\"doubao\": \"ARK_API_KEY\",\n\t\"crabclaw\": \"CRABCLAW_API_KEY\",\n\t\"ollama\": \"OLLAMA_API_KEY\",\n}\n\n// EnvApiKeyFallbacks OAuth/令牌回退链。\n// TS 参考: model-auth.ts resolveEnvApiKey 中的 fallback 链。\nvar EnvApiKeyFallbacks = map[string][]string{\n\t\"anthropic\": {\"ANTHROPIC_OAUTH_TOKEN\"},\n\t\"qwen-portal\": {\"QWEN_PORTAL_API_KEY\"},\n\t\"minimax-portal\": {\"MINIMAX_PORTAL_API_KEY\"},\n}\n\n// ResolveEnvApiKeyVarName 解析供应商 API Key 环境变量名。\nfunc ResolveEnvApiKeyVarName(provider string) string {\n\tnormalized := strings.ToLower(strings.TrimSpace(provider))\n\tif varName, ok := EnvApiKeyVarNames[normalized]; ok {\n\t\treturn varName\n\t}\n\treturn \"\"\n}\n\n// ResolveEnvApiKeyWithFallback P4-DRIFT4: 解析 API Key,支持 OAuth 回退链。\n// 对齐 TS model-auth.ts resolveEnvApiKey() 中的 fallback 逻辑。\nfunc ResolveEnvApiKeyWithFallback(provider string) string {\n\tnormalized := strings.ToLower(strings.TrimSpace(provider))\n\n\t// 主环境变量\n\tif varName, ok := EnvApiKeyVarNames[normalized]; ok {\n\t\tif val := os.Getenv(varName); val != \"\" {\n\t\t\treturn val\n\t\t}\n\t}\n\n\t// 回退链\n\tif fallbacks, ok := EnvApiKeyFallbacks[normalized]; ok {\n\t\tfor _, fb := range fallbacks {\n\t\t\tif val := os.Getenv(fb); val != \"\" {\n\t\t\t\treturn val\n\t\t\t}\n\t\t}\n\t}\n\n\treturn \"\"\n}\n\n// NormalizeApiKeyConfig 规范化 API Key 配置字符串。\nfunc NormalizeApiKeyConfig(value string) string {\n\ttrimmed := strings.TrimSpace(value)\n\tif trimmed == \"\" {\n\t\treturn \"\"\n\t}\n\t// 检查是否为环境变量引用 (以 $ 开头)\n\tif strings.HasPrefix(trimmed, \"$\") {\n\t\tenvVar := strings.TrimPrefix(trimmed, \"$\")\n\t\tenvVar = strings.Trim(envVar, \"{}\")\n\t\treturn os.Getenv(envVar)\n\t}\n\treturn trimmed\n}\n\n// NormalizeGoogleModelId 规范化 Google 模型 ID。\n// TS 参考: models-config.providers.ts L191-198\nfunc NormalizeGoogleModelId(id string) string {\n\tif id == \"\" {\n\t\treturn id\n\t}\n\t// gemini-3 系列名称映射\n\tif id == \"gemini-3.1-pro\" {\n\t\treturn \"gemini-3.1-pro-preview\"\n\t}\n\tif id == \"gemini-3-pro\" {\n\t\treturn \"gemini-3-pro-preview\"\n\t}\n\tif id == \"gemini-3-flash\" {\n\t\treturn \"gemini-3-flash-preview\"\n\t}\n\t// 移除 models/ 前缀\n\tif strings.HasPrefix(id, \"models/\") {\n\t\treturn strings.TrimPrefix(id, \"models/\")\n\t}\n\treturn id\n}\n\n// GetProviderDefaults 获取供应商默认配置。\nfunc GetProviderDefaults(provider string) *ProviderDefaults {\n\tnormalized := strings.ToLower(strings.TrimSpace(provider))\n\tif defaults, ok := providerDefaults[normalized]; ok {\n\t\treturn &defaults\n\t}\n\treturn nil\n}\n\n// ResolveProviderBaseURL 解析供应商 base URL。\n// 优先使用配置文件中用户自定义的 baseUrl,回退到硬编码默认值。\nfunc ResolveProviderBaseURL(provider string, cfg *types.CrabClawConfig) string {\n\t// 1. 优先: 配置文件中用户自定义 baseUrl\n\tif cfg != nil && cfg.Models != nil && cfg.Models.Providers != nil {\n\t\tnormalized := strings.ToLower(strings.TrimSpace(provider))\n\t\tif pc := cfg.Models.Providers[normalized]; pc != nil && pc.BaseURL != \"\" {\n\t\t\treturn pc.BaseURL\n\t\t}\n\t\tif pc := cfg.Models.Providers[provider]; pc != nil && pc.BaseURL != \"\" {\n\t\t\treturn pc.BaseURL\n\t\t}\n\t}\n\t// 2. 回退: 硬编码默认值\n\tdefaults := GetProviderDefaults(provider)\n\tif defaults != nil {\n\t\treturn defaults.BaseURL\n\t}\n\treturn \"\"\n}\n\n// ---------- 工具级 API Key 环境变量(非 LLM provider) ----------\n// 对应 TS: tools/web-search.ts 和 tools/web-fetch.ts 中的 env fallback 逻辑。\n\n// ToolEnvApiKeyVarNames 工具名称到环境变量名的映射。\n// configPath 对应 schema_hints_data.go 中的 \"fallback: XXX_API_KEY env var\" 描述。\nvar ToolEnvApiKeyVarNames = map[string]string{\n\t\"brave_search\": \"BRAVE_API_KEY\",\n\t\"firecrawl\": \"FIRECRAWL_API_KEY\",\n\t\"perplexity\": \"PERPLEXITY_API_KEY\",\n\t\"elevenlabs\": \"ELEVENLABS_API_KEY\",\n\t\"elevenlabs_xi\": \"XI_API_KEY\",\n}\n\n// ResolveToolApiKey 解析工具级 API Key。\n// configValue 为配置文件中的显式值(优先);tool 为工具名(用于 env fallback)。\n// TS 参考: web-search.ts resolveSearchApiKey(), web-fetch.ts resolveFirecrawlApiKey()\nfunc ResolveToolApiKey(tool, configValue string) string {\n\tif v := NormalizeApiKeyConfig(configValue); v != \"\" {\n\t\treturn v\n\t}\n\tif envVar, ok := ToolEnvApiKeyVarNames[strings.ToLower(tool)]; ok {\n\t\treturn os.Getenv(envVar)\n\t}\n\treturn \"\"\n}\n"}}}}