feat: OpenAI 多模型注册表 + /model 命令,告别手改配置文件
痛点:很多模型都是 OpenAI 格式,但换模型只能手改 config.json 的单槽位,
且只能存一个。新增模型注册表与 /model 命令族:
- 新增 xcli_core/model_registry.py:在 api.engines.openai 下维护
models 列表(name + base_url + api_key + model)与 current 指针,全部落盘。
向后兼容:无 models 时把扁平 api_key/base_url/model 当作单条隐式模型。
- OpenaiAI 接入:__init__ 应用注册表 current 模型;新增
set_registry_model / list_registry_models / add_model / remove_model /
current_model_name。注意保留引擎原有的轻量 set_model(只改 model 名)
与 list_models(查 API /models 端点),新方法与它们不重名、互不干扰。
- 新增 /model 命令族(仅 openai 引擎):
/model 列出已配置模型(* 标记当前)
/model <名称> 切换当前模型并持久化
/model add 交互式录入(名称/base_url/api_key/model),回车即存并切换
/model rm <名称> 删除(删当前则回退到列表第一个)
- 启动横幅引擎名后显示当前模型;紧凑提示与 /help 速查表均补 /model 入口。
- 测试:新增 tests/test_model_registry.py(13 项,覆盖兼容/增删/切换/落盘/
引擎接入/CLI 路由,全程临时配置不污染真实 config.json)。
全量 230 passed(原 217 passed)。
交互实测:/model add → 已添加并切换到 gpt4o;/model gpt4o → 已切换;
/model rm gpt4o → 回退到 xophunyuan7bmt,配置结构与内容完好。
This commit is contained in:
1 parent
3a86da7444
commit
1383d32f8b
7 files changed
+493
-2
No files matched your search
@@ -19,6 +19,11 @@ except Exception:
|
||||
def get_system_config(key, default=None):
|
||||
return default
|
||||
|
||||
try:
|
||||
from xcli_core import model_registry
|
||||
except Exception:
|
||||
model_registry = None
|
||||
|
||||
try:
|
||||
from xcli_core.verbose import vprint
|
||||
except Exception:
|
||||
@@ -140,6 +145,9 @@ OpenAI 兼容格式引擎帮助信息
|
||||
self.conversation_history = []
|
||||
self.shared_conversation_history = None
|
||||
|
||||
# 应用注册表中的当前模型(覆盖扁平默认配置,向后兼容)
|
||||
self._apply_registry_model()
|
||||
|
||||
# 最近一次请求的 token 用量(供 token 感知压缩使用)
|
||||
self.last_prompt_tokens = None
|
||||
|
||||
@@ -155,6 +163,63 @@ OpenAI 兼容格式引擎帮助信息
|
||||
else:
|
||||
vprint(f"{Fore.GREEN}OpenAI 兼容引擎已启用 (base_url: {self.base_url}){Style.RESET_ALL}")
|
||||
|
||||
# ── 模型注册表(多模型在线切换)──
|
||||
|
||||
def _apply_registry_model(self):
|
||||
"""若注册表存在 current 模型,用它覆盖 __init__ 读到的扁平默认配置。"""
|
||||
if not model_registry:
|
||||
return
|
||||
try:
|
||||
m = model_registry.get_model()
|
||||
if m:
|
||||
self.api_key = m.get("api_key", self.api_key)
|
||||
self.base_url = (m.get("base_url") or self.base_url).rstrip('/')
|
||||
self.model = m.get("model", self.model)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def list_registry_models(self):
|
||||
"""返回 (models, current_name),供 CLI 列出已配置模型。"""
|
||||
if not model_registry:
|
||||
return [], None
|
||||
return model_registry.list_models()
|
||||
|
||||
def current_model_name(self):
|
||||
"""当前激活模型在注册表中的名称(兼容单槽位时返回 model 值)。"""
|
||||
if not model_registry:
|
||||
return self.model
|
||||
try:
|
||||
models, current = model_registry.list_models()
|
||||
return current or self.model
|
||||
except Exception:
|
||||
return self.model
|
||||
|
||||
def set_registry_model(self, name):
|
||||
"""切换到注册表中指定模型(含 base_url/api_key/model)并持久化 current。
|
||||
成功返回 True。"""
|
||||
if not model_registry:
|
||||
return False
|
||||
m = model_registry.get_model(name)
|
||||
if not m:
|
||||
return False
|
||||
self.api_key = m.get("api_key", "")
|
||||
self.base_url = (m.get("base_url") or "").rstrip('/')
|
||||
self.model = m.get("model", "")
|
||||
model_registry.set_current(name)
|
||||
return True
|
||||
|
||||
def add_model(self, entry):
|
||||
"""新增/更新模型并持久化。entry: {name, base_url, api_key, model}。"""
|
||||
if not model_registry:
|
||||
return None
|
||||
return model_registry.add_model(entry)
|
||||
|
||||
def remove_model(self, name):
|
||||
"""删除模型并持久化。成功返回 True。"""
|
||||
if not model_registry:
|
||||
return False
|
||||
return model_registry.remove_model(name)
|
||||
|
||||
def _get_headers(self):
|
||||
"""构建请求头"""
|
||||
headers = {
|
||||
|
||||
Reference in new issue
Block a user