diff --git a/agent/protocol/agent.py b/agent/protocol/agent.py index 85e1535..6818331 100644 --- a/agent/protocol/agent.py +++ b/agent/protocol/agent.py @@ -166,7 +166,8 @@ class Agent: # Find and replace the runtime section import re pattern = r'\n## 运行时信息\s*\n.*?(?=\n##|\Z)' - updated_prompt = re.sub(pattern, new_runtime_section.rstrip('\n'), prompt, flags=re.DOTALL) + _repl = new_runtime_section.rstrip('\n') + updated_prompt = re.sub(pattern, lambda m: _repl, prompt, flags=re.DOTALL) return updated_prompt except Exception as e: @@ -195,7 +196,9 @@ class Agent: if has_old_block: replacement = new_block or "\n" - prompt = re.sub(old_block_pattern, replacement, prompt, flags=re.DOTALL) + # Use lambda to prevent re.sub from interpreting backslashes in replacement + # (e.g. Windows paths like \LinkAI would be treated as bad escape sequences) + prompt = re.sub(old_block_pattern, lambda m: replacement, prompt, flags=re.DOTALL) elif new_block: skills_header = "以下是可用技能:" idx = prompt.find(skills_header) @@ -224,7 +227,7 @@ class Agent: # Replace existing tooling section pattern = r'## 工具系统\s*\n.*?(?=\n## |\Z)' - updated = re.sub(pattern, new_section, prompt, count=1, flags=re.DOTALL) + updated = re.sub(pattern, lambda m: new_section, prompt, count=1, flags=re.DOTALL) return updated except Exception as e: logger.warning(f"Failed to rebuild tool list section: {e}") diff --git a/channel/web/static/js/console.js b/channel/web/static/js/console.js index b52b30e..36af2b4 100644 --- a/channel/web/static/js/console.js +++ b/channel/web/static/js/console.js @@ -908,7 +908,9 @@ function initConfigView(data) { const providerOpts = Object.entries(configProviders).map(([pid, p]) => ({ value: pid, label: p.label })); // if use_linkai is enabled, always select linkai as the provider - const detected = data.use_linkai ? 'linkai' : detectProvider(configCurrentModel); + // Otherwise prefer bot_type from config, fall back to model-based detection + const detected = data.use_linkai ? 'linkai' + : (data.bot_type && configProviders[data.bot_type] ? data.bot_type : detectProvider(configCurrentModel)); cfgProviderValue = detected || (providerOpts[0] ? providerOpts[0].value : ''); initDropdown(providerEl, providerOpts, cfgProviderValue, onProviderChange); @@ -1062,6 +1064,14 @@ function saveModelConfig() { const updates = { model: model }; const p = configProviders[cfgProviderValue]; updates.use_linkai = (cfgProviderValue === 'linkai'); + // Save bot_type for bot_factory routing. + // Most providers use their key directly as bot_type. + // linkai uses use_linkai flag instead of bot_type. + if (cfgProviderValue === 'linkai') { + updates.bot_type = ''; + } else { + updates.bot_type = cfgProviderValue; + } if (p && p.api_base_key) { const base = document.getElementById('cfg-api-base').value.trim(); if (base) updates[p.api_base_key] = base; diff --git a/channel/web/web_channel.py b/channel/web/web_channel.py index 56ac6ba..424aa3e 100644 --- a/channel/web/web_channel.py +++ b/channel/web/web_channel.py @@ -406,7 +406,7 @@ class ConfigHandler: "api_base_default": None, "models": [const.MINIMAX_M2_5, const.MINIMAX_M2_1, const.MINIMAX_M2_1_LIGHTNING], }), - ("glm-4", { + ("zhipu", { "label": "智谱AI", "api_key_field": "zhipu_ai_api_key", "api_base_key": "zhipu_ai_api_base", @@ -448,7 +448,7 @@ class ConfigHandler: "api_base_default": "https://generativelanguage.googleapis.com", "models": [const.GEMINI_31_PRO_PRE, const.GEMINI_3_FLASH_PRE], }), - ("openAI", { + ("chatGPT", { "label": "OpenAI", "api_key_field": "open_ai_api_key", "api_base_key": "open_ai_api_base", @@ -472,7 +472,7 @@ class ConfigHandler: ]) EDITABLE_KEYS = { - "model", "use_linkai", + "model", "bot_type", "use_linkai", "open_ai_api_base", "claude_api_base", "gemini_api_base", "zhipu_ai_api_base", "moonshot_base_url", "ark_base_url", "open_ai_api_key", "claude_api_key", "gemini_api_key", @@ -522,6 +522,7 @@ class ConfigHandler: "use_agent": use_agent, "title": title, "model": local_config.get("model", ""), + "bot_type": local_config.get("bot_type", ""), "use_linkai": bool(local_config.get("use_linkai", False)), "channel_type": local_config.get("channel_type", ""), "agent_max_context_tokens": local_config.get("agent_max_context_tokens", 50000), diff --git a/common/const.py b/common/const.py index 5bc127b..366ea8a 100644 --- a/common/const.py +++ b/common/const.py @@ -9,9 +9,10 @@ CLAUDEAPI= "claudeAPI" QWEN = "qwen" # 旧版千问接入 QWEN_DASHSCOPE = "dashscope" # 新版千问接入(百炼) GEMINI = "gemini" -ZHIPU_AI = "glm-4" +ZHIPU_AI = "zhipu" MOONSHOT = "moonshot" MiniMax = "minimax" +DEEPSEEK = "deepseek" MODELSCOPE = "modelscope" # 模型列表 diff --git a/models/bot_factory.py b/models/bot_factory.py index 2f83da9..e6e6f92 100644 --- a/models/bot_factory.py +++ b/models/bot_factory.py @@ -17,8 +17,7 @@ def create_bot(bot_type): from models.baidu.baidu_wenxin import BaiduWenxinBot return BaiduWenxinBot() - elif bot_type == const.CHATGPT: - # ChatGPT 网页端web接口 + elif bot_type in (const.CHATGPT, const.DEEPSEEK): # DeepSeek uses OpenAI-compatible API from models.chatgpt.chat_gpt_bot import ChatGPTBot return ChatGPTBot() @@ -53,7 +52,7 @@ def create_bot(bot_type): from models.gemini.google_gemini_bot import GoogleGeminiBot return GoogleGeminiBot() - elif bot_type == const.ZHIPU_AI: + elif bot_type == const.ZHIPU_AI or bot_type == "glm-4": # "glm-4" kept for backward compatibility from models.zhipuai.zhipuai_bot import ZHIPUAIBot return ZHIPUAIBot() diff --git a/models/minimax/minimax_bot.py b/models/minimax/minimax_bot.py index b1e0d32..9e47705 100644 --- a/models/minimax/minimax_bot.py +++ b/models/minimax/minimax_bot.py @@ -2,7 +2,6 @@ import time import json -from pydantic.types import T import requests from models.bot import Bot