fix(configure_mykey): 备份命名标准化 + 保留既有 LLM 配置

This commit is contained in:
WindCat committed 2026-05-19 22:59:57 +08:00
1 parent cf129162d5
commit 964f51dacb
2 files changed
+98 -19

No files matched your search

+91 -19
View File
@@ -7,6 +7,7 @@ GenericAgent — 交互式初始化向导 (configure.py)
python configure.py
"""
import ast
import os
import sys
import re
@@ -1068,7 +1069,7 @@ def generate_mykey(llm_cfgs, platform_configs):
def _write_config_fields(lines, cfg):
"""写入配置字典的键值对(缩进的 'key': value, 格式)"""
for key in ['name', 'apikey', 'apibase', 'model', 'api_mode',
for key in ['name', 'type', 'apikey', 'apibase', 'model', 'api_mode',
'fake_cc_system_prompt', 'thinking_type', 'thinking_budget_tokens',
'reasoning_effort', 'max_tokens', 'max_retries', 'connect_timeout',
'read_timeout', 'temperature', 'context_win',
@@ -1101,7 +1102,7 @@ def _write_platform_value(lines, key, val):
def _parse_existing_mykey():
"""解析已有 mykey.py,返回 (model_names, platform_infos)
llm_cfgs: [{'name': str, 'type': str, ...}] — 模型配置字典列表
model_names: [str] — 模型名列表
platform_infos: [{'id': str, 'vars': [{'key': str, 'val': ...}]}] — 平台信息
解析失败时返回 ([], [])
"""
@@ -1117,21 +1118,81 @@ def _parse_existing_mykey():
if m:
model_names = re.findall(r"'([^']+)'", m.group(1))
# 解析平台变量 → 平台 ID
platform_id_map = {
'tg_bot_token': 'telegram', 'qq_app_id': 'qq',
'fs_app_id': 'feishu', 'wecom_bot_id': 'wecom',
'dingtalk_client_id': 'dingtalk', 'dc_bot_token': 'discord',
}
# 先收集所有已知平台 env var key → 判断值类型
all_env_var_keys = {}
platform_env_keys = {} # pid -> [var_key]
for p in PLATFORMS:
pid = p['id']
platform_env_keys.setdefault(pid, [])
for var in p.get('env_vars', []):
vkey = var['key']
all_env_var_keys[vkey] = var
platform_env_keys[pid].append(vkey)
# 逐平台解析所有已知变量
platform_infos = []
for var_key, pid in platform_id_map.items():
m_var = re.search(rf"^{var_key}\s*=\s*'([^']*)'", content, re.MULTILINE)
if m_var:
platform_infos.append({'id': pid, 'vars': [{'key': var_key, 'val': m_var.group(1)}]})
for pid, env_keys in platform_env_keys.items():
vars_found = []
for vkey in env_keys:
var_def = all_env_var_keys[vkey]
val = None
if var_def.get('is_list'):
# 匹配 `xxx = [...]`
m_var = re.search(rf"^{vkey}\s*=\s*(\[[^\]]*\])", content, re.MULTILINE)
if m_var:
try:
val = ast.literal_eval(m_var.group(1))
except (ValueError, SyntaxError):
pass
else:
# 匹配 `xxx = '...'`
m_var = re.search(rf"^{vkey}\s*=\s*'([^']*)'", content, re.MULTILINE)
if m_var:
val = m_var.group(1)
if val is not None:
vars_found.append({'key': vkey, 'val': val})
if vars_found:
platform_infos.append({'id': pid, 'vars': vars_found})
return model_names, platform_infos
def _parse_existing_llm_cfgs():
"""解析已有 mykey.py,返回完整 LLM 配置字典列表 [{name, apikey, ...}]
解析失败时返回 []
"""
if not os.path.exists(MYKPY_PATH):
return []
with open(MYKPY_PATH, 'r', encoding='utf-8') as f:
content = f.read()
cfgs = []
# 匹配所有 `xxx = { ... }` 顶层字典赋值
# 用简单状态机: 找 `\w+ = {` 然后匹配花括号
pattern = re.compile(r'^(\w+)\s*=\s*\{', re.MULTILINE)
for m in pattern.finditer(content):
brace_start = m.end() - 1 # '{' 的位置
depth = 1
i = brace_start + 1
while i < len(content) and depth > 0:
if content[i] == '{':
depth += 1
elif content[i] == '}':
depth -= 1
i += 1
if depth == 0:
dict_text = content[m.end():i - 1]
try:
d = ast.literal_eval('{' + dict_text + '}')
if isinstance(d, dict) and 'name' in d:
cfgs.append(d)
except (ValueError, SyntaxError):
continue
return cfgs
def _backup_with_name(model_names, platform_ids):
"""按 mykey+模型名+机器人名 格式备份旧 mykey.py"""
parts = ['mykey']
@@ -1142,6 +1203,8 @@ def _backup_with_name(model_names, platform_ids):
if pid_clean not in parts:
parts.append(pid_clean)
safe_name = '_'.join(parts)
if safe_name == 'mykey':
safe_name = 'mykey_backup' # 避免和源文件同名
if len(safe_name) > 100:
safe_name = safe_name[:100]
backup_path = os.path.join(PROJECT_ROOT, f'{safe_name}.py')
@@ -1189,7 +1252,7 @@ def main():
if mode == 'new':
backup_path = _backup_with_name(model_names, [p['id'] for p in platform_infos])
print(f" {C['green']}✓ 旧配置已备份至:{C['reset']} {C['dim']}{backup}{C['reset']}")
print(f" {C['green']}✓ 旧配置已备份至:{C['reset']} {C['dim']}{backup_path}{C['reset']}")
is_new = True
else:
is_modify = True
@@ -1212,8 +1275,12 @@ def main():
config_dict = {v['key']: v['val'] for v in pi['vars']}
platform_configs.append({'platform': p, 'config': config_dict})
elif scope == 'platform' and model_names:
print(f"\n {C['yellow']}⚠ 只修改平台时若未提供 LLM 配置将无法使用。{C['reset']}")
cprint(f" 建议两项都重新配置。", 'dim')
old_cfgs = _parse_existing_llm_cfgs()
if old_cfgs:
llm_cfgs = old_cfgs
print(f"\n {C['green']}✓ 已保留现有 LLM 配置: {', '.join(c['name'] for c in old_cfgs)}{C['reset']}")
else:
print(f"\n {C['yellow']}⚠ 保留 LLM 配置失败,将生成空配置。建议两项都重新配置。{C['reset']}")
if not is_modify:
if is_new:
@@ -1245,6 +1312,12 @@ def main():
platform_configs, platform_deps = configure_platforms()
if ask_yesno("是否继续配置 LLM 模型?", default=True):
llm_cfgs = _do_llm()
elif os.path.exists(MYKPY_PATH):
# 新建+仅平台:从备份保留旧 LLM 配置
old_cfgs = _parse_existing_llm_cfgs()
if old_cfgs:
llm_cfgs = old_cfgs
print(f"\n {C['green']}✓ 已保留备份中的 LLM 配置: {', '.join(c['name'] for c in old_cfgs)}{C['reset']}")
# ── 生成 mykey.py ──
if not llm_cfgs and not platform_configs:
@@ -1253,10 +1326,9 @@ def main():
content = generate_mykey(llm_cfgs, platform_configs)
# 备份旧文件
if os.path.exists(MYKPY_PATH):
backup = os.path.join(PROJECT_ROOT, f'mykey.py.bak.{datetime.now().strftime("%Y%m%d_%H%M%S")}')
shutil.copy2(MYKPY_PATH, backup)
# 备份旧文件(修改模式不备份,直接在原文件修改)
if os.path.exists(MYKPY_PATH) and not is_modify and not is_new:
backup = _backup_with_name(model_names, [p['id'] for p in platform_infos])
print(f"\n {C['green']}✓ 旧配置已备份至:{C['reset']} {C['dim']}{backup}{C['reset']}")
# 写入
+7
View File
@@ -65,6 +65,11 @@ COMMANDS = {
"desc": "启动终端图形界面(Textual),适合纯终端环境或 SSH",
"cmd": ["python", "{FRONTENDS}/tuiapp.py"],
},
"tui2": {
"help": "启动终端 TUI v2 (tuiapp_v2)",
"desc": "启动增强版终端图形界面(Textual v2),更多功能更好的体验",
"cmd": ["python", "{FRONTENDS}/tuiapp_v2.py"],
},
"cli": {
"help": "启动 CLI 对话 (agentmain)",
"desc": "启动命令行交互对话模式,最轻量的使用方式",
@@ -151,6 +156,8 @@ def main():
ga gui 启动桌面 GUI
ga web 启动 Web 增强版
ga web --native 启动 Web 基础版(桌面壳)
ga tui 启动终端 TUI (v1)
ga tui2 启动终端 TUI (v2 增强版)
ga pet 启动桌面宠物 v2
ga launch 启动 webview 桌面壳
ga list 列出所有命令