1 line
16 KiB
JSON
1 line
16 KiB
JSON
{"repo": "artmeng/litecode", "files": {"agent/providers/registry.py": {"3e988e02ecfcbc878828ccd6f0241c6125fe3792": {"t": 1785674685.5435565, "n": 14114, "h": "b23a4de884f85106", "c": "\"\"\"\nProvider Registry — single source of truth for LLM provider metadata.\n\n设计原则(参考 nanobot):\n - ProviderSpec 只描述 *访问方式*,不内嵌 model 列表。\n - Model id 由用户在配置 / WebUI 自由填写。\n - 添加新 provider:在 PROVIDERS 元组里加一条,并在 webui ProviderOption 自动暴露。\n\n字段使用:\n - keywords: 用于 `provider=\"auto\"` 时按 model 名匹配。\n - default_api_base: 当用户未填 apiBase 时的兜底;OAuth/local/direct provider 也用。\n - is_gateway / is_local / is_oauth / is_direct: 决定是否要求 apiKey、UI 是否折叠 API Base 字段等。\n - thinking_style: 把\"启用思考\"开关注入 extra_body 的方式(不同厂家不同协议)。\n - model_overrides: 强制为某些 model 注入的固定参数(例如 Kimi K2 要求 temperature ≥ 1)。\n\"\"\"\n\nfrom __future__ import annotations\n\nfrom dataclasses import dataclass, field\nfrom typing import Any\n\n\n@dataclass(frozen=True)\nclass ProviderSpec:\n \"\"\"一种 provider 的访问元数据。Model id 由用户填,spec 不存。\"\"\"\n\n # 身份\n name: str # registry id, 与 config providers.{name} 对齐\n display_name: str # UI 展示\n backend: str # openai_compat | anthropic | azure_openai | bedrock | openai_codex | github_copilot\n keywords: tuple[str, ...] = () # provider=\"auto\" 时用 model 名匹配\n\n # 网络\n default_api_base: str | None = None\n env_key: str = \"\" # 可选,从环境变量取 key\n env_extras: tuple[tuple[str, str], ...] = () # 额外注入的 env,e.g. ((\"ZHIPUAI_API_KEY\", \"{api_key}\"),)\n\n # 分类(仅 UI 分组与门禁逻辑用)\n region: str = \"other\" # foreign | aggregator | cloud | cn | local | other\n is_gateway: bool = False # OpenRouter / AiHubMix 等可路由任意模型\n is_local: bool = False # 本地部署(vLLM / Ollama / LM Studio)\n is_oauth: bool = False # OAuth-based,用户不填 apiKey\n is_direct: bool = False # 用户必须自己填完整 endpoint(custom / azure / bedrock / ovms)\n detect_by_key_prefix: str = \"\" # auto 路由:按 apiKey 前缀认人\n detect_by_base_keyword: str = \"\" # auto 路由:按 apiBase 关键字认人\n\n # OpenAI-compat 行为差异\n strip_model_prefix: bool = False # 发请求前去掉 \"vendor/\" 前缀(aihubmix 等)\n supports_max_completion_tokens: bool = False # OpenAI 系:用 max_completion_tokens 而非 max_tokens\n supports_prompt_caching: bool = False # Anthropic / OpenRouter 等\n\n # 思考开关 / 推理\n thinking_style: str = \"\" # thinking_type | enable_thinking | reasoning_split\n reasoning_as_content: bool = False # StepFun:把 reasoning 字段当正文\n\n # 强制覆写(按 model id 注入 extra_body / sampling)\n model_overrides: tuple[tuple[str, dict[str, Any]], ...] = field(default_factory=tuple)\n\n\nPROVIDERS: tuple[ProviderSpec, ...] = (\n # ─── 海外大厂 ─────────────────────────────────────────────\n ProviderSpec(\n name=\"openai\",\n display_name=\"OpenAI\",\n backend=\"openai_compat\",\n keywords=(\"openai\", \"gpt\", \"o1\", \"o3\", \"o4\"),\n default_api_base=\"https://api.openai.com/v1\",\n env_key=\"OPENAI_API_KEY\",\n region=\"foreign\",\n supports_max_completion_tokens=True,\n ),\n ProviderSpec(\n name=\"anthropic\",\n display_name=\"Anthropic\",\n backend=\"anthropic\",\n keywords=(\"anthropic\", \"claude\"),\n env_key=\"ANTHROPIC_API_KEY\",\n region=\"foreign\",\n supports_prompt_caching=True,\n ),\n ProviderSpec(\n name=\"gemini\",\n display_name=\"Google Gemini\",\n backend=\"openai_compat\",\n keywords=(\"gemini\", \"gemma\", \"google\"),\n default_api_base=\"https://generativelanguage.googleapis.com/v1beta/openai/\",\n env_key=\"GEMINI_API_KEY\",\n region=\"foreign\",\n ),\n ProviderSpec(\n name=\"xai\",\n display_name=\"xAI Grok\",\n backend=\"openai_compat\",\n keywords=(\"xai\", \"grok\"),\n default_api_base=\"https://api.x.ai/v1\",\n env_key=\"XAI_API_KEY\",\n region=\"foreign\",\n ),\n ProviderSpec(\n name=\"mistral\",\n display_name=\"Mistral AI\",\n backend=\"openai_compat\",\n keywords=(\"mistral\", \"codestral\"),\n default_api_base=\"https://api.mistral.ai/v1\",\n env_key=\"MISTRAL_API_KEY\",\n region=\"foreign\",\n ),\n ProviderSpec(\n name=\"groq\",\n display_name=\"Groq\",\n backend=\"openai_compat\",\n keywords=(\"groq\",),\n default_api_base=\"https://api.groq.com/openai/v1\",\n env_key=\"GROQ_API_KEY\",\n region=\"foreign\",\n ),\n\n # ─── 聚合 / 网关 ───────────────────────────────────────────\n ProviderSpec(\n name=\"openrouter\",\n display_name=\"OpenRouter\",\n backend=\"openai_compat\",\n keywords=(\"openrouter\",),\n default_api_base=\"https://openrouter.ai/api/v1\",\n env_key=\"OPENROUTER_API_KEY\",\n region=\"aggregator\",\n is_gateway=True,\n detect_by_key_prefix=\"sk-or-\",\n detect_by_base_keyword=\"openrouter\",\n supports_prompt_caching=True,\n ),\n ProviderSpec(\n name=\"huggingface\",\n display_name=\"Hugging Face\",\n backend=\"openai_compat\",\n keywords=(\"huggingface\", \"hugging-face\"),\n default_api_base=\"https://router.huggingface.co/v1\",\n env_key=\"HF_TOKEN\",\n region=\"aggregator\",\n is_gateway=True,\n detect_by_key_prefix=\"hf_\",\n detect_by_base_keyword=\"huggingface\",\n ),\n ProviderSpec(\n name=\"aihubmix\",\n display_name=\"AiHubMix\",\n backend=\"openai_compat\",\n keywords=(\"aihubmix\",),\n default_api_base=\"https://aihubmix.com/v1\",\n env_key=\"AIHUBMIX_API_KEY\",\n region=\"aggregator\",\n is_gateway=True,\n detect_by_base_keyword=\"aihubmix\",\n strip_model_prefix=True,\n ),\n ProviderSpec(\n name=\"siliconflow\",\n display_name=\"SiliconFlow (硅基流动)\",\n backend=\"openai_compat\",\n keywords=(\"siliconflow\",),\n default_api_base=\"https://api.siliconflow.cn/v1\",\n env_key=\"SILICONFLOW_API_KEY\",\n region=\"aggregator\",\n is_gateway=True,\n detect_by_base_keyword=\"siliconflow\",\n ),\n\n # ─── 云厂 ─────────────────────────────────────────────────\n ProviderSpec(\n name=\"azure_openai\",\n display_name=\"Azure OpenAI\",\n backend=\"azure_openai\",\n keywords=(\"azure\", \"azure-openai\"),\n region=\"cloud\",\n is_direct=True,\n ),\n ProviderSpec(\n name=\"bedrock\",\n display_name=\"AWS Bedrock\",\n backend=\"bedrock\",\n keywords=(\n \"bedrock\", \"anthropic.claude\", \"amazon.nova\", \"meta.\",\n \"mistral.\", \"cohere.\", \"deepseek.\", \"moonshot.\",\n ),\n env_key=\"AWS_BEARER_TOKEN_BEDROCK\",\n region=\"cloud\",\n is_direct=True,\n ),\n\n # ─── 国内 ─────────────────────────────────────────────────\n ProviderSpec(\n name=\"deepseek\",\n display_name=\"DeepSeek\",\n backend=\"openai_compat\",\n keywords=(\"deepseek\",),\n default_api_base=\"https://api.deepseek.com\",\n env_key=\"DEEPSEEK_API_KEY\",\n region=\"cn\",\n thinking_style=\"thinking_type\",\n ),\n ProviderSpec(\n name=\"dashscope\",\n display_name=\"Alibaba DashScope (Qwen)\",\n backend=\"openai_compat\",\n keywords=(\"dashscope\", \"qwen\"),\n default_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n env_key=\"DASHSCOPE_API_KEY\",\n region=\"cn\",\n thinking_style=\"enable_thinking\",\n ),\n ProviderSpec(\n name=\"moonshot\",\n display_name=\"Moonshot Kimi\",\n backend=\"openai_compat\",\n keywords=(\"moonshot\", \"kimi\"),\n default_api_base=\"https://api.moonshot.cn/v1\",\n env_key=\"MOONSHOT_API_KEY\",\n region=\"cn\",\n model_overrides=(\n (\"kimi-k2\", {\"temperature\": 1.0}),\n (\"kimi-k2.5\", {\"temperature\": 1.0}),\n (\"kimi-k2.6\", {\"temperature\": 1.0}),\n ),\n ),\n ProviderSpec(\n name=\"zhipu\",\n display_name=\"Zhipu GLM (智谱)\",\n backend=\"openai_compat\",\n keywords=(\"zhipu\", \"glm\", \"zai\"),\n default_api_base=\"https://open.bigmodel.cn/api/paas/v4/\",\n env_key=\"ZAI_API_KEY\",\n env_extras=((\"ZHIPUAI_API_KEY\", \"{api_key}\"),),\n region=\"cn\",\n ),\n ProviderSpec(\n name=\"volcengine\",\n display_name=\"VolcEngine 火山方舟 (含豆包)\",\n backend=\"openai_compat\",\n keywords=(\"volcengine\", \"volces\", \"ark\", \"doubao\"),\n default_api_base=\"https://ark.cn-beijing.volces.com/api/v3\",\n env_key=\"ARK_API_KEY\",\n region=\"cn\",\n is_gateway=True,\n detect_by_base_keyword=\"volces\",\n thinking_style=\"thinking_type\",\n ),\n ProviderSpec(\n name=\"volcengine_coding_plan\",\n display_name=\"VolcEngine Coding Plan\",\n backend=\"openai_compat\",\n keywords=(\"volcengine-plan\",),\n default_api_base=\"https://ark.cn-beijing.volces.com/api/coding/v3\",\n env_key=\"ARK_API_KEY\",\n region=\"cn\",\n is_gateway=True,\n strip_model_prefix=True,\n thinking_style=\"thinking_type\",\n ),\n ProviderSpec(\n name=\"byteplus\",\n display_name=\"BytePlus (海外火山)\",\n backend=\"openai_compat\",\n keywords=(\"byteplus\",),\n default_api_base=\"https://ark.ap-southeast.bytepluses.com/api/v3\",\n env_key=\"BYTEPLUS_API_KEY\",\n region=\"cn\",\n is_gateway=True,\n detect_by_base_keyword=\"bytepluses\",\n strip_model_prefix=True,\n thinking_style=\"thinking_type\",\n ),\n ProviderSpec(\n name=\"minimax\",\n display_name=\"MiniMax\",\n backend=\"openai_compat\",\n keywords=(\"minimax\",),\n default_api_base=\"https://api.minimax.io/v1\",\n env_key=\"MINIMAX_API_KEY\",\n region=\"cn\",\n thinking_style=\"reasoning_split\",\n ),\n ProviderSpec(\n name=\"stepfun\",\n display_name=\"Step Fun (阶跃星辰)\",\n backend=\"openai_compat\",\n keywords=(\"stepfun\", \"step\"),\n default_api_base=\"https://api.stepfun.com/v1\",\n env_key=\"STEPFUN_API_KEY\",\n region=\"cn\",\n reasoning_as_content=True,\n ),\n ProviderSpec(\n name=\"xiaomi_mimo\",\n display_name=\"Xiaomi MIMO (小米)\",\n backend=\"openai_compat\",\n keywords=(\"xiaomi\", \"mimo\"),\n default_api_base=\"https://api.xiaomimimo.com/v1\",\n env_key=\"XIAOMIMIMO_API_KEY\",\n region=\"cn\",\n ),\n ProviderSpec(\n name=\"longcat\",\n display_name=\"LongCat (美团)\",\n backend=\"openai_compat\",\n keywords=(\"longcat\",),\n default_api_base=\"https://api.longcat.chat/openai/v1\",\n env_key=\"LONGCAT_API_KEY\",\n region=\"cn\",\n ),\n ProviderSpec(\n name=\"qianfan\",\n display_name=\"Qianfan 千帆 (文心 ERNIE)\",\n backend=\"openai_compat\",\n keywords=(\"qianfan\", \"ernie\", \"wenxin\"),\n default_api_base=\"https://qianfan.baidubce.com/v2\",\n env_key=\"QIANFAN_API_KEY\",\n region=\"cn\",\n ),\n\n # ─── 本地部署 ──────────────────────────────────────────────\n ProviderSpec(\n name=\"ollama\",\n display_name=\"Ollama\",\n backend=\"openai_compat\",\n keywords=(\"ollama\", \"llama\", \"nemotron\"),\n default_api_base=\"http://localhost:11434/v1\",\n env_key=\"OLLAMA_API_KEY\",\n region=\"local\",\n is_local=True,\n detect_by_base_keyword=\"11434\",\n ),\n ProviderSpec(\n name=\"lm_studio\",\n display_name=\"LM Studio\",\n backend=\"openai_compat\",\n keywords=(\"lm-studio\", \"lmstudio\", \"lm_studio\"),\n default_api_base=\"http://localhost:1234/v1\",\n env_key=\"LM_STUDIO_API_KEY\",\n region=\"local\",\n is_local=True,\n detect_by_base_keyword=\"1234\",\n ),\n ProviderSpec(\n name=\"vllm\",\n display_name=\"vLLM\",\n backend=\"openai_compat\",\n keywords=(\"vllm\",),\n env_key=\"HOSTED_VLLM_API_KEY\",\n region=\"local\",\n is_local=True,\n ),\n ProviderSpec(\n name=\"ovms\",\n display_name=\"OpenVINO Model Server\",\n backend=\"openai_compat\",\n keywords=(\"openvino\", \"ovms\"),\n default_api_base=\"http://localhost:8000/v3\",\n region=\"local\",\n is_local=True,\n is_direct=True,\n ),\n\n # ─── OAuth-based ───────────────────────────────────────────\n ProviderSpec(\n name=\"openai_codex\",\n display_name=\"OpenAI Codex\",\n backend=\"openai_codex\",\n keywords=(\"openai-codex\", \"codex\"),\n default_api_base=\"https://chatgpt.com/backend-api\",\n region=\"other\",\n is_oauth=True,\n detect_by_base_keyword=\"codex\",\n strip_model_prefix=True,\n ),\n ProviderSpec(\n name=\"github_copilot\",\n display_name=\"GitHub Copilot\",\n backend=\"github_copilot\",\n keywords=(\"github_copilot\", \"copilot\"),\n default_api_base=\"https://api.githubcopilot.com\",\n region=\"other\",\n is_oauth=True,\n strip_model_prefix=True,\n supports_max_completion_tokens=True,\n ),\n\n # ─── 兜底 ─────────────────────────────────────────────────\n ProviderSpec(\n name=\"custom\",\n display_name=\"Custom\",\n backend=\"openai_compat\",\n keywords=(),\n region=\"other\",\n is_direct=True,\n ),\n)\n\n\ndef find_by_name(name: str | None) -> ProviderSpec | None:\n \"\"\"按 registry name 精确查找。容忍 - / _ 互换。\"\"\"\n if not name:\n return None\n normalized = name.replace(\"-\", \"_\").lower()\n for spec in PROVIDERS:\n if spec.name == normalized:\n return spec\n return None\n\n\ndef provider_options() -> list[dict[str, Any]]:\n \"\"\"供 WebUI ProviderOption 下拉用的元数据列表。\"\"\"\n return [\n {\n \"name\": spec.name,\n \"displayName\": spec.display_name,\n \"backend\": spec.backend,\n \"defaultApiBase\": spec.default_api_base or \"\",\n \"region\": spec.region,\n \"isGateway\": spec.is_gateway,\n \"isLocal\": spec.is_local,\n \"isOauth\": spec.is_oauth,\n \"isDirect\": spec.is_direct,\n \"thinkingStyle\": spec.thinking_style or None,\n }\n for spec in PROVIDERS\n ]\n"}}}} |