xiaoli-cli 7.0.0: 重构底层架构 + 移除工具截断
- 重构 core/ 底层 (7文件): app/runner/engine/parser/history/safety/display - FC原生调用为主,prompt-JSON保底 - 移除所有工具返回截断 (ai_search/git_tools/cmd_executor/browser_auto/network_tools/sub_agent/tool_search) - 删除无用文件 (旧服务器/WebUI/彩蛋/启动器等21个文件) - 清理 constants.py 死代码 - 版本号更新为 7.0.0
This commit is contained in:
commit
78fea7ccdd
57 files changed
+18358
No files matched your search
+274
@@ -0,0 +1,274 @@
|
||||
"""xiaoli-cli 7.0.0 主类"""
|
||||
import os, sys, json, importlib
|
||||
from datetime import datetime
|
||||
|
||||
from .types import ToolCall, ToolResult
|
||||
from .history import History
|
||||
from .safety import Safety
|
||||
from .display import Display
|
||||
from .engine import EngineAdapter
|
||||
from .runner import Runner
|
||||
|
||||
|
||||
class XiaoliCLI:
|
||||
def __init__(self):
|
||||
self.shared_conversation_history = []
|
||||
self.max_history = 999999
|
||||
self.current_engine = None
|
||||
self.engines = {}
|
||||
self.engine_name = "openai"
|
||||
self.liugin_manager = None
|
||||
self.tools = []
|
||||
self.liugin_commands = {}
|
||||
self.chat_dir = "chat_history"
|
||||
self.memory_manager = None
|
||||
|
||||
self._load_config()
|
||||
self._load_engines()
|
||||
self._load_plugins()
|
||||
self._init_memory()
|
||||
self._init_core()
|
||||
self._register_commands()
|
||||
print("xiaoli-cli 7.0.0 初始化完成")
|
||||
|
||||
def _load_config(self):
|
||||
try:
|
||||
from xcli_core.config import get_system_config
|
||||
self.engine_name = get_system_config("default_engine", "openai")
|
||||
except Exception:
|
||||
self.engine_name = "openai"
|
||||
|
||||
def _load_engines(self):
|
||||
print("正在加载AI引擎...")
|
||||
d = os.path.join(os.path.dirname(os.path.dirname(__file__)), "ai_engines")
|
||||
if not os.path.isdir(d):
|
||||
return
|
||||
for fn in os.listdir(d):
|
||||
if fn.endswith("_engine.py") and not fn.startswith("__"):
|
||||
mn = fn[:-3]
|
||||
try:
|
||||
mod = importlib.import_module(f"ai_engines.{mn}")
|
||||
for an in dir(mod):
|
||||
obj = getattr(mod, an)
|
||||
if isinstance(obj, type) and an.endswith("AI") and hasattr(obj, "generate_response"):
|
||||
eng = obj()
|
||||
eng.cli = self
|
||||
eng.shared_conversation_history = self.shared_conversation_history
|
||||
self.engines[eng.name] = eng
|
||||
print(f" 已加载: {eng.name} ({an})")
|
||||
except Exception as e:
|
||||
print(f" [ERROR] {mn}: {e}")
|
||||
if self.engine_name not in self.engines and self.engines:
|
||||
self.engine_name = list(self.engines.keys())[0]
|
||||
self.current_engine = self.engines.get(self.engine_name)
|
||||
print(f" 共 {len(self.engines)} 个引擎,当前: {self.engine_name}")
|
||||
|
||||
def _load_plugins(self):
|
||||
print("正在加载插件...")
|
||||
try:
|
||||
from unified_tool_manager import UnifiedToolManager
|
||||
self.liugin_manager = UnifiedToolManager(self)
|
||||
pd = os.path.join(os.path.dirname(os.path.dirname(__file__)), "plugins")
|
||||
sd = os.path.join(os.path.dirname(os.path.dirname(__file__)), "skills")
|
||||
self.liugin_manager.initialize(pd, sd)
|
||||
self.tools = self.liugin_manager.tools if hasattr(self.liugin_manager, "tools") else []
|
||||
print(f" 已加载 {len(self.tools)} 个插件")
|
||||
except Exception as e:
|
||||
print(f" [ERROR] 插件加载失败: {e}")
|
||||
import traceback; traceback.print_exc()
|
||||
|
||||
def _init_memory(self):
|
||||
try:
|
||||
from xcli_core.memory import MemoryManager
|
||||
self.memory_manager = MemoryManager(self)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
def _init_core(self):
|
||||
self.history = History(self.max_history)
|
||||
self.safety = Safety(self, lambda: self.current_engine)
|
||||
self.display = Display()
|
||||
self.engine_adapter = EngineAdapter(self.current_engine)
|
||||
self.runner = Runner(self.engine_adapter, self.liugin_manager,
|
||||
self.history, self.safety, self.display)
|
||||
self.runner.set_prompt_builder(self._build_prompt)
|
||||
|
||||
def _build_prompt(self):
|
||||
p = '你叫小狸,是一个强大的智能编程助手。\n\n'
|
||||
p += '【工具调用】\n当你需要执行操作时,直接调用工具。\n工具执行后,根据结果继续回复或调用下一个工具。\n\n'
|
||||
p += '【补充回复】\n如果你需要补充之前的回复,输出:\n'
|
||||
p += '{"action": "continue", "content": "要补充的内容"}\n\n'
|
||||
p += '【核心工具】\n'
|
||||
p += '1. code_editor - 代码编辑\n2. code_search - 代码搜索\n3. git_tools - Git\n'
|
||||
p += '4. cmd_executor - Shell命令\n5. file_manager - 文件管理\n6. browser_auto - 浏览器\n'
|
||||
p += '7. sub_agent - 子Agent\n8. auto_engineer - 工程化\n9. network_tools - 网络\n'
|
||||
p += '10. ai_search - 网页内容 (url/search/web)\n\n'
|
||||
p += '说话时可适当加nyan表现可爱性格。'
|
||||
return p
|
||||
|
||||
def register_liugin_command(self, name, handler):
|
||||
self.liugin_commands[name] = handler
|
||||
|
||||
def process_conversation(self, user_input):
|
||||
return self.runner.run(user_input)
|
||||
|
||||
def switch_engine(self, name):
|
||||
if name in self.engines:
|
||||
self.engine_name = name
|
||||
self.current_engine = self.engines[name]
|
||||
self.current_engine.shared_conversation_history = self.shared_conversation_history
|
||||
self.engine_adapter = EngineAdapter(self.current_engine)
|
||||
self.runner.set_engine(self.engine_adapter)
|
||||
self.safety._engine = lambda: self.current_engine
|
||||
try:
|
||||
from xcli_core.config import set_system_config
|
||||
set_system_config("default_engine", name)
|
||||
except Exception:
|
||||
pass
|
||||
return f"已切换到: {name}"
|
||||
return f"引擎 {name} 不存在"
|
||||
|
||||
def _register_commands(self):
|
||||
self._commands = {
|
||||
"/help": self._cmd_help,
|
||||
"/engine": self._cmd_engine,
|
||||
"/mode": self._cmd_mode,
|
||||
"/clear": self._cmd_clear,
|
||||
"/history": self._cmd_history,
|
||||
"/tools": self._cmd_tools,
|
||||
"/exit": self._cmd_exit,
|
||||
"/quit": self._cmd_exit,
|
||||
"/save": self._cmd_save,
|
||||
"/config": self._cmd_config,
|
||||
"/new": self._cmd_new,
|
||||
}
|
||||
|
||||
def handle_command(self, user_input):
|
||||
parts = user_input.strip().split(None, 1)
|
||||
cmd = parts[0].lower().lstrip("/")
|
||||
args = parts[1] if len(parts) > 1 else ""
|
||||
h = self._commands.get("/" + cmd)
|
||||
if h:
|
||||
return h(args)
|
||||
if cmd in self.liugin_commands:
|
||||
try:
|
||||
r = self.liugin_commands[cmd](args)
|
||||
if r: print(r)
|
||||
except Exception as e:
|
||||
print(f"命令失败: {e}")
|
||||
return ""
|
||||
return None
|
||||
|
||||
def _cmd_help(self, a):
|
||||
return "\n".join(["/help - 帮助", "/engine [list|<name>] - 引擎",
|
||||
"/mode [0-3] - 安全模式", "/clear - 清空历史",
|
||||
"/history - 历史", "/tools - 工具", "/save - 保存",
|
||||
"/new - 新对话", "/config - 配置", "/exit - 退出"])
|
||||
|
||||
def _cmd_engine(self, a):
|
||||
if not a or a == "list":
|
||||
lines = [f"当前: {self.engine_name}", "可用:"]
|
||||
for n in self.engines:
|
||||
lines.append(f" {n}{' <==' if n == self.engine_name else ''}")
|
||||
return "\n".join(lines)
|
||||
return self.switch_engine(a)
|
||||
|
||||
def _cmd_mode(self, a):
|
||||
if not a: return f"当前模式: {self.safety.get_mode()}"
|
||||
try:
|
||||
m = int(a)
|
||||
self.safety.set_mode(m)
|
||||
names = {0: "无限制", 1: "普通", 2: "人工", 3: "计划"}
|
||||
return f"已切换: {names.get(m, '未知')}"
|
||||
except ValueError:
|
||||
return "用法: /mode [0-3]"
|
||||
|
||||
def _cmd_clear(self, a):
|
||||
self.history.clear()
|
||||
self.shared_conversation_history.clear()
|
||||
return "已清空"
|
||||
|
||||
def _cmd_history(self, a):
|
||||
msgs = self.history.snapshot()
|
||||
if not msgs: return "无历史"
|
||||
lines = [f"共 {len(msgs)} 条:"]
|
||||
for m in msgs[-10:]:
|
||||
c = m.content[:50] + "..." if len(m.content) > 50 else m.content
|
||||
lines.append(f" [{m.role}] {c}")
|
||||
return "\n".join(lines)
|
||||
|
||||
def _cmd_tools(self, a):
|
||||
if not self.tools: return "无工具"
|
||||
lines = [f"共 {len(self.tools)} 个:"]
|
||||
for t in self.tools:
|
||||
lines.append(f" {t.get('name','')}: {t.get('description','')[:60]}")
|
||||
return "\n".join(lines)
|
||||
|
||||
def _cmd_save(self, a):
|
||||
try:
|
||||
os.makedirs(self.chat_dir, exist_ok=True)
|
||||
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
fp = os.path.join(self.chat_dir, f"{ts}_chat.json")
|
||||
msgs = self.history.snapshot()
|
||||
data = [{"role": m.role, "content": m.content} for m in msgs]
|
||||
with open(fp, "w", encoding="utf-8") as f:
|
||||
json.dump(data, f, ensure_ascii=False, indent=2)
|
||||
return f"已保存: {fp}"
|
||||
except Exception as e:
|
||||
return f"失败: {e}"
|
||||
|
||||
def _cmd_new(self, a):
|
||||
self._cmd_save("")
|
||||
self.history.clear()
|
||||
self.shared_conversation_history.clear()
|
||||
return "新对话"
|
||||
|
||||
def _cmd_config(self, a):
|
||||
try:
|
||||
with open("config.json", "r", encoding="utf-8") as f:
|
||||
return json.dumps(json.load(f), ensure_ascii=False, indent=2)[:1000]
|
||||
except Exception as e:
|
||||
return f"失败: {e}"
|
||||
|
||||
def _cmd_exit(self, a):
|
||||
self._cmd_save("")
|
||||
return "__EXIT__"
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
from colorama import init, Fore, Style
|
||||
init()
|
||||
except ImportError:
|
||||
class _D:
|
||||
CYAN = GREEN = YELLOW = RESET_ALL = ''
|
||||
Fore = Style = _D()
|
||||
print()
|
||||
print(f" {Fore.CYAN}+========================================+{Style.RESET_ALL}")
|
||||
print(f" {Fore.CYAN}| xiaoli-cli 7.0.0 (重构版) |{Style.RESET_ALL}")
|
||||
print(f" {Fore.CYAN}| 小狸 AI 编程助手 |{Style.RESET_ALL}")
|
||||
print(f" {Fore.CYAN}+========================================+{Style.RESET_ALL}")
|
||||
print()
|
||||
print(f" 引擎: {Fore.GREEN}{self.engine_name}{Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''}")
|
||||
print(f" 工具: {Fore.GREEN}{len(self.tools)}{Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''} 个插件")
|
||||
print(f" FC: {'支持' if self.engine_adapter.supports_fc() else '不支持'}")
|
||||
print(f" 输入 /help 查看命令")
|
||||
print()
|
||||
while True:
|
||||
try:
|
||||
ui = input(f"{Fore.CYAN}[用户ID: xiaoli]{Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''} ").strip()
|
||||
if not ui: continue
|
||||
if ui.startswith("/"):
|
||||
r = self.handle_command(ui)
|
||||
if r == "__EXIT__":
|
||||
print(f" {Fore.YELLOW}再见~{Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''}")
|
||||
break
|
||||
if r: print(r)
|
||||
continue
|
||||
self.process_conversation(ui)
|
||||
print()
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n {Fore.YELLOW}(Ctrl+C, /exit退出){Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''}")
|
||||
except EOFError:
|
||||
break
|
||||
except Exception as e:
|
||||
print(f" {Fore.RED}错误: {e}{Style.RESET_ALL if hasattr(Style,'RESET_ALL') else ''}")
|
||||
Reference in new issue
Block a user