myagent-ai 1.15.91 → 1.15.93

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Dockerfile ADDED
@@ -0,0 +1,30 @@
1
+ # MyAgent - 本地桌面端执行型 AI 助手
2
+ # Docker 构建文件 (主要用于服务器部署)
3
+ FROM python:3.11-slim
4
+
5
+ WORKDIR /app
6
+
7
+ # 安装系统依赖
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ python3-pip \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ # 安装 Python 依赖
13
+ COPY requirements.txt .
14
+ RUN pip install --no-cache-dir -r requirements.txt
15
+
16
+ # 复制代码
17
+ COPY . .
18
+
19
+ # 创建数据目录
20
+ RUN mkdir -p data logs
21
+
22
+ # 环境变量
23
+ ENV MYAGENT_APP_DATA_DIR=data
24
+ ENV MYAGENT_APP_LOG_FILE=logs/myagent.log
25
+
26
+ # HTTP API 模式
27
+ EXPOSE 8080
28
+
29
+ # 启动
30
+ CMD ["python", "main.py", "--server", "--host", "0.0.0.0", "--port", "8080"]
@@ -638,7 +638,10 @@ class UpdateManager:
638
638
  self._save_record(record)
639
639
  logger.info(f"全量更新完成 v{record.from_version} → v{new_version},准备优雅重启...")
640
640
 
641
- # Step 4: 优雅重启
641
+ # Step 4: 清除旧的 .pyc 缓存(防止更新后仍加载旧字节码)
642
+ self._clear_pycache()
643
+
644
+ # Step 5: 优雅重启
642
645
  self._status = UpdateStatus.RESTARTING
643
646
  await asyncio.sleep(0.5) # 给日志一点时间写入
644
647
 
@@ -911,6 +914,34 @@ class UpdateManager:
911
914
  importlib.reload(sys.modules["config"])
912
915
  logger.info("config 模块已重载")
913
916
 
917
+ def _clear_pycache(self):
918
+ """[v1.15.93] 清除项目目录和 npm 全局目录中的 __pycache__,
919
+ 防止更新后 Python 仍加载旧的 .pyc 字节码文件。"""
920
+ import shutil
921
+ dirs_to_clean = [PROJECT_ROOT]
922
+ # 也清除 npm 全局目录的缓存
923
+ try:
924
+ result = subprocess.run(
925
+ ["npm", "root", "-g"],
926
+ capture_output=True, text=True, timeout=5,
927
+ )
928
+ npm_root = result.stdout.strip()
929
+ if npm_root:
930
+ npm_pkg_dir = Path(npm_root) / "myagent-ai"
931
+ if npm_pkg_dir.exists() and npm_pkg_dir not in dirs_to_clean:
932
+ dirs_to_clean.append(npm_pkg_dir)
933
+ except Exception:
934
+ pass
935
+
936
+ for base_dir in dirs_to_clean:
937
+ for pycache_dir in base_dir.rglob("__pycache__"):
938
+ try:
939
+ shutil.rmtree(pycache_dir, ignore_errors=True)
940
+ logger.debug(f"已清除缓存: {pycache_dir}")
941
+ except Exception:
942
+ pass
943
+ logger.info(f"__pycache__ 清理完成 (检查了 {len(dirs_to_clean)} 个目录)")
944
+
914
945
  # ── 模块热重载 ──
915
946
 
916
947
  async def _reload_modules(self):
package/install.ps1 ADDED
@@ -0,0 +1,69 @@
1
+ # MyAgent 一键部署脚本 (Windows)
2
+ # ==========================================
3
+
4
+ $VENV_DIR = ".venv"
5
+
6
+ # 设置 UTF-8 输出
7
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
8
+
9
+ Write-Host "`n--- MyAgent 一键部署 ---" -ForegroundColor Cyan
10
+
11
+ # 1. 检查 Python
12
+ # 尝试使用 python 或 python3
13
+ $PYTHON_EXE = "python"
14
+ if (-not (Get-Command $PYTHON_EXE -ErrorAction SilentlyContinue)) {
15
+ $PYTHON_EXE = "python3"
16
+ if (-not (Get-Command $PYTHON_EXE -ErrorAction SilentlyContinue)) {
17
+ Write-Host "[!] 未找到 Python 环境。请从 python.org 安装 Python 3.10+。" -ForegroundColor Red
18
+ exit 1
19
+ }
20
+ }
21
+
22
+ try {
23
+ # 更加稳健的版本获取方式
24
+ $py_ver_str = & $PYTHON_EXE -c "import sys; print('%d.%d' % sys.version_info[:2])"
25
+ Write-Host "[i] 找到 Python: $py_ver_str"
26
+
27
+ if ([string]::IsNullOrWhiteSpace($py_ver_str)) {
28
+ Write-Host "[!] 无法获取 Python 版本号。" -ForegroundColor Red
29
+ exit 1
30
+ }
31
+
32
+ $py_ver = [double]$py_ver_str
33
+ if ($py_ver -lt 3.10) {
34
+ Write-Host "[!] 需要 Python 3.10 或更高版本,当前版本为 $py_ver_str,请升级。" -ForegroundColor Red
35
+ exit 1
36
+ }
37
+ } catch {
38
+ Write-Host "[!] 检查 Python 版本时出错: $_" -ForegroundColor Red
39
+ exit 1
40
+ }
41
+
42
+ # 2. 创建虚拟环境
43
+ if (-not (Test-Path $VENV_DIR)) {
44
+ Write-Host "[*] 正在创建虚拟环境 ($VENV_DIR)..." -ForegroundColor Cyan
45
+ & $PYTHON_EXE -m venv $VENV_DIR
46
+ if ($LASTEXITCODE -ne 0) {
47
+ Write-Host "[✗] 创建虚拟环境失败。" -ForegroundColor Red
48
+ exit 1
49
+ }
50
+ Write-Host "[✓] 虚拟环境已创建。" -ForegroundColor Green
51
+ }
52
+
53
+ # 3. 安装依赖
54
+ Write-Host "[*] 正在安装/升级依赖..." -ForegroundColor Cyan
55
+ & "$VENV_DIR\Scripts\python.exe" -m pip install --upgrade pip --quiet
56
+ & "$VENV_DIR\Scripts\python.exe" -m pip install -r requirements.txt
57
+
58
+ if ($LASTEXITCODE -eq 0) {
59
+ Write-Host "`n[✓] 部署成功!" -ForegroundColor Green
60
+ Write-Host "提示: 现在可以运行 ./start.ps1 启动 MyAgent。" -ForegroundColor Yellow
61
+ } else {
62
+ Write-Host "`n[✗] 依赖安装过程中出现错误。" -ForegroundColor Red
63
+ }
64
+
65
+ Write-Host "`n按回车退出..."
66
+ # 仅在非交互模式下禁用 Read-Host
67
+ if ($Host.Name -ne "ServerRemoteHost") {
68
+ Read-Host
69
+ }
@@ -0,0 +1,26 @@
1
+ # MyAgent 一键启动脚本 (Windows)
2
+ # ==========================================
3
+
4
+ $VENV_DIR = ".venv"
5
+ $PYTHON = "$VENV_DIR\Scripts\python.exe"
6
+
7
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
8
+
9
+ Write-Host "`n--- MyAgent 启动器 ---" -ForegroundColor Cyan
10
+
11
+ if (-not (Test-Path $PYTHON)) {
12
+ Write-Host "[!] 未找到本地虚拟环境,尝试使用系统环境..." -ForegroundColor Yellow
13
+ if (Get-Command python -ErrorAction SilentlyContinue) {
14
+ $PYTHON = "python"
15
+ } else {
16
+ Write-Host "[✗] 未找到 Python 环境。" -ForegroundColor Red
17
+ exit 1
18
+ }
19
+ }
20
+
21
+ Write-Host "[*] 启动服务 (Web + Tray)..." -ForegroundColor Cyan
22
+ & $PYTHON main.py --tray --web 8767
23
+
24
+ if ($LASTEXITCODE -ne 0) {
25
+ Write-Host "`n[!] 程序退出 (代码: $LASTEXITCODE)。" -ForegroundColor Yellow
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "myagent-ai",
3
- "version": "1.15.91",
3
+ "version": "1.15.93",
4
4
  "description": "本地桌面端执行型AI助手 - Open Interpreter 风格 | Local Desktop Execution-Oriented AI Assistant",
5
5
  "main": "main.py",
6
6
  "bin": {
@@ -42,27 +42,5 @@
42
42
  "engines": {
43
43
  "python": ">=3.10",
44
44
  "node": ">=18"
45
- },
46
- "files": [
47
- "main.py",
48
- "config.py",
49
- "setup.py",
50
- "requirements.txt",
51
- "start.js",
52
- "start.sh",
53
- "install/",
54
- "docs/",
55
- "core/",
56
- "memory/",
57
- "executor/",
58
- "agents/",
59
- "chatbot/",
60
- "skills/",
61
- "knowledge/",
62
- "communication/",
63
- "organization/",
64
- "groups/",
65
- "departments/",
66
- "web/"
67
- ]
45
+ }
68
46
  }
@@ -0,0 +1,33 @@
1
+
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ # Add project root to sys.path
6
+ root = Path(__file__).resolve().parent.parent
7
+ sys.path.append(str(root))
8
+
9
+ from web.api_server import ApiServer
10
+ from config import get_config
11
+
12
+ class MockCore:
13
+ def __init__(self):
14
+ self.config_mgr = get_config()
15
+ self.llm = None
16
+ self.executor = None
17
+
18
+ def main():
19
+ print("[*] 正在手动创建/更新系统配置助手...")
20
+ core = MockCore()
21
+ # ApiServer needs core, and it calls _setup_routes which we don't really need but it's fine
22
+ server = ApiServer(core)
23
+
24
+ # Manually call the ensure methods
25
+ server._ensure_default_agent()
26
+ server._ensure_config_helper()
27
+
28
+ print("[+] 配置助手创建/更新完成!")
29
+ print(f"[i] 数据目录: {core.config_mgr.data_dir}")
30
+ print(f"[i] Agent 目录: {core.config_mgr.data_dir / 'agents'}")
31
+
32
+ if __name__ == "__main__":
33
+ main()
@@ -331,18 +331,18 @@ class WebReadSkill(Skill):
331
331
  tag.decompose()
332
332
  # 移除所有 class 含特定关键词的元素
333
333
  # 注意: decompose() 会连带销毁子元素,子元素的 attrs 变为 None,
334
- # 因此必须检查 tag.parent 是否为 None 来跳过已被销毁的标签
335
- for tag in soup.find_all(True, class_=True):
336
- if tag.parent is None:
337
- continue
338
- try:
334
+ # 必须同时检查 attrs parent 来跳过已被销毁的标签
335
+ try:
336
+ for tag in list(soup.find_all(True, class_=True)):
337
+ if not getattr(tag, 'attrs', None):
338
+ continue
339
339
  cls_str = " ".join(tag.get("class", []))
340
- except (AttributeError, TypeError):
341
- continue
342
- if any(kw in cls_str.lower() for kw in
343
- ["sidebar", "footer", "nav", "header", "advertisement",
344
- "cookie", "popup", "modal", "banner", "social", "share"]):
345
- tag.decompose()
340
+ if any(kw in cls_str.lower() for kw in
341
+ ["sidebar", "footer", "nav", "header", "advertisement",
342
+ "cookie", "popup", "modal", "banner", "social", "share"]):
343
+ tag.decompose()
344
+ except Exception:
345
+ pass # 解析异常时跳过清理,不影响主要内容提取
346
346
 
347
347
  text = soup.get_text(separator="\n", strip=True)
348
348
  text = "\n".join(line for line in text.split("\n") if line.strip())
package/start.js CHANGED
@@ -414,6 +414,9 @@ function cmdUpdate(pkgDir) {
414
414
  let newVer = "";
415
415
  try { newVer = JSON.parse(fs.readFileSync(path.join(newPkgDir, "package.json"), "utf8")).version || ""; } catch (_) {}
416
416
 
417
+ // 2.5 清除 __pycache__(防止旧的 .pyc 字节码覆盖新的 .py 源码)
418
+ cleanPycache(newPkgDir);
419
+
417
420
  // 3. 如果版本变了,用新的 start.js 重新执行自身,确保运行最新代码
418
421
  if (curVer && newVer && curVer !== newVer) {
419
422
  const newStartJs = path.join(newPkgDir, "start.js");
@@ -446,6 +449,33 @@ function cmdUpdate(pkgDir) {
446
449
 
447
450
 
448
451
 
452
+ // ── 清除 __pycache__ ──────────────────────────────────────
453
+
454
+ function cleanPycache(pkgDir) {
455
+ /**
456
+ * 递归清除 pkgDir 下所有 __pycache__ 目录。
457
+ * npm 更新后旧的 .pyc 可能残留,Python 优先加载 .pyc 导致新代码不生效。
458
+ */
459
+ try {
460
+ function walk(dir) {
461
+ if (!fs.existsSync(dir)) return;
462
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
463
+ for (const entry of entries) {
464
+ const full = path.join(dir, entry.name);
465
+ if (entry.isDirectory()) {
466
+ if (entry.name === "__pycache__") {
467
+ fs.rmSync(full, { recursive: true, force: true });
468
+ } else {
469
+ walk(full);
470
+ }
471
+ }
472
+ }
473
+ }
474
+ walk(pkgDir);
475
+ console.log(" ✓ 已清除 Python 字节码缓存");
476
+ } catch (_) {}
477
+ }
478
+
449
479
  function cmdUninstall() {
450
480
  const venvDir = getVenvDir();
451
481
  const dataDir = getDataDir();
package/worklog.md ADDED
@@ -0,0 +1,306 @@
1
+ ---
2
+ Task ID: 1
3
+ Agent: Main Agent
4
+ Task: 移动端多项UI修复
5
+
6
+ Work Log:
7
+ - 分析了 chat_main.js, chat.css, right_agents.html, left_sessions.html, index.html, groupchat.js 等文件
8
+ - 定位并修复了 newChat() 不关闭移动端侧边栏的问题
9
+ - 定位并修复了 quickChatAgent() 和 selectGroup() 不关闭移动端右侧栏的问题
10
+ - 定位了右侧agent面板在collapsed状态下,mobile CSS的 display:flex!important 缺少 flex-direction:column 导致内容横向排列的bug
11
+ - 修复了移动端collapsed状态下版本号/更新信息被 display:none 隐藏的问题
12
+ - 对admin后台(index.html)的sidebar-footer-text在移动端collapsed+mobile-open状态下也做了显示修复
13
+ - 版本号bump: CSS v3→v4, JS v2→v3
14
+
15
+ Stage Summary:
16
+ - 修改文件: web/ui/chat/chat.css, web/ui/chat/chat_main.js, web/ui/chat/groupchat.js, web/ui/index.html, web/ui/chat/chat_container.html
17
+ - 已 commit & push (4ec4726)
18
+
19
+ ---
20
+ Task ID: 2
21
+ Agent: Main Agent
22
+ Task: 修复聊天消息排版混乱和脚本注入漏洞
23
+
24
+ Work Log:
25
+ - 分析了 renderMarkdown() 函数,发现所有 markdown 转换(行内代码、粗体、斜体、列表、引用块)均未对内容进行 HTML 转义
26
+ - 发现漏洞:agent 回复中的 HTML 标签可以执行 JavaScript(XSS),也可以破坏页面布局(如注入未闭合的 div)
27
+ - 实现了 3 层防护:
28
+ 1. renderMarkdown() 重写:先提取代码块为占位符 → escapeHtml() 转义所有 HTML → 应用 markdown 转换 → 还原代码块
29
+ 2. CSS 容器隔离:message-bubble / group-msg-bubble / thought-content / msg-timeline 添加 overflow:hidden 防溢出
30
+ 3. 代码块 pre 添加 max-width:100% + white-space:pre-wrap 防止代码块撑破容器
31
+ - 确认了 flow_engine.js 中的 renderInlineExecEvent()、showExecResultModal()、showToolResultModal() 均已正确使用 escapeHtml()
32
+ - 版本号 bump: 1.8.5 → 1.8.6, CSS v4→v5, JS v3→v4
33
+
34
+ Stage Summary:
35
+ - 修改文件: web/ui/chat/chat_main.js, web/ui/chat/chat.css, package.json, web/ui/chat/chat_container.html, web/ui/chat/chat.js
36
+ - 修复了 XSS 漏洞和排版破坏问题
37
+
38
+ ---
39
+ Task ID: 1
40
+ Agent: main
41
+ Task: 部门Agent管理 + 工具调用保存 + 会话分页加载 (v1.9.0)
42
+
43
+ Work Log:
44
+ - 拉取最新代码 (git pull --rebase)
45
+ - 修改 web/ui/index.html: 部门详情页 showDeptDetail() 新增Agent成员管理面板(添加/移除)
46
+ - 修改 web/ui/index.html: renderDeptTree() 显示成员数量标签
47
+ - 修改 web/ui/index.html: openCreateAgentModal() 新增部门选择下拉框
48
+ - 修改 web/ui/index.html: openEditAgentModal() 部门选择支持子部门路径
49
+ - 修改 web/ui/index.html: 新增 _flattenDepts() 辅助函数
50
+ - 修改 web/ui/index.html: viewSession() 改为分页加载 + 工具调用折叠显示
51
+ - 修改 web/api_server.py: handle_create_agent 支持 department 字段
52
+ - 修改 web/api_server.py: handle_update_agent allowed_fields 添加 department
53
+ - 修改 web/api_server.py: handle_get_messages/handle_get_messages_query 支持 limit/offset 分页
54
+ - 修改 agents/main_agent.py: 处理完成后保存执行事件为 role=tool 短期记忆
55
+ - 修改 memory/manager.py: get_conversation 默认 limit 从50提升到500
56
+ - 修改 web/ui/chat/chat_main.js: selectSession 不再过滤 tool 角色
57
+ - 修改 web/ui/chat/chat_main.js: _renderMessagesInner 新增 tool 角色折叠显示
58
+ - 版本号升级到 1.9.0
59
+ - git commit + git push 成功
60
+ - npm publish 失败(登录凭证过期)
61
+
62
+ Stage Summary:
63
+ - 部门管理现在可以添加/移除Agent成员
64
+ - 创建和编辑Agent时可以指定所属部门(支持子部门)
65
+ - 工具调用过程现在会保存为role=tool的短期记忆
66
+ - 会话消息API支持分页(limit/offset参数)
67
+ - 聊天页面和管理后台都能查看工具调用过程
68
+
69
+ ---
70
+ Task ID: 1
71
+ Agent: Main Agent
72
+ Task: 修复 V2 finish回调逻辑 + 轻量测试服务验证
73
+
74
+ Work Log:
75
+ - 分析 _process_v2_inner 中的 V2 循环逻辑,发现 finish 检查位置错误
76
+ - 原逻辑: Step 10 先检查 finish=true 直接 break(工具不执行),Step 11 工具执行后只看 need_callback
77
+ - 修复后: Step 10 先执行工具 → Step 12 工具执行完检查 finish(优先级最高)→ 再检查 need_callback
78
+ - 提交 58be408 并推送到远程仓库
79
+ - 搭建轻量 HTTP 测试服务器 (server.py),使用 ModelScope API 直接验证 V2 全链路
80
+ - 运行 3 个测试场景全部通过:
81
+ 1. 搜索场景: finish=false, callback=false → no_callback(正确)
82
+ 2. 问候场景: finish=true, 有工具 → finish_after_tools(修复验证)
83
+ 3. 机票场景: finish=true, askuser非空 → ask_user(正确)
84
+
85
+ Stage Summary:
86
+ - 关键修复: finish 标志是最终决策者,优先级高于工具级 callback
87
+ - finish=true → 即使工具 callback=true 也不回调 LLM
88
+ - finish=false → 根据工具 callback 标志决定是否回调
89
+ - 测试服务器文件: /home/z/my-project/download/v2-test-server/server.py
90
+ - 所有更改已推送至 ctz168/myagent main 分支
91
+
92
+ ---
93
+ Task ID: stream-test
94
+ Agent: main
95
+ Task: 使用轻量测试环境对前后端流式输出进行全面测试
96
+
97
+ Work Log:
98
+ - 分析项目架构:LLM客户端(chat_stream)、前端(flow_engine.js SSE)、API服务(handle_chat_stream)
99
+ - 发现 test/server.py 仅有非流式 /api/chat 端点,前端使用标准 fetch JSON 响应
100
+ - 升级 test/server.py:新增 /api/chat/stream SSE 流式端点,支持 7 种事件类型
101
+ - 升级 test/index.html:新增流式 Agent 循环标签页,实时渲染 text_delta/v2_tool/v2_parse 等事件
102
+ - 发现并修复 core/llm.py _stream_openai 的 AsyncOpenAI 流式迭代 bug (coroutine is not iterable)
103
+ - 验证单轮迭代:1+1 简短回答,25 chunks,TTFT=13.5s,parse_success=true
104
+ - 验证多轮迭代:天气查询→工具执行→回调→二次处理,2 轮迭代,123 SSE 事件,finish 正确
105
+ - 运行单元测试:output_parser(get_knowledge)、context_builder(knowledge) 全部通过
106
+
107
+ Stage Summary:
108
+ - SSE 流式端点 /api/chat/stream 完整实现,支持 7 种事件类型
109
+ - 前端流式渲染面板,含 TTFT 统计、自动滚动、停止按钮
110
+ - 修复 core/llm.py AsyncOpenAI 流式调用关键 bug
111
+ - 代码已推送到 origin/main (commit ce63c16)
112
+
113
+ ---
114
+ Task ID: 1
115
+ Agent: main
116
+ Task: 测试前端输入"你好"后无回复的问题,验证前后端流式通信
117
+
118
+ Work Log:
119
+ - 启动 test/server.py 测试服务器,验证 /api/health 正常
120
+ - 用 curl 直接测试 /api/chat/stream SSE 端点,确认后端流式输出正常
121
+ - 用 Python 直接调用 event_generator 确认 SSE 事件完整(session/iteration_start/text_delta/v2_parse/v2_task_plan/v2_ask/iteration_end/done)
122
+ - 发现 uvicorn 后台进程容易被 shell 退出时杀死,影响测试稳定性
123
+ - 编写 test_e2e_runner.py 自包含 E2E 测试脚本(自动启停服务器+Playwright)
124
+ - 运行 Playwright 流式测试:PASS(7个事件渲染,0错误,43个SSE事件,8.6s完成)
125
+ - 运行 Playwright 非流式测试:PASS(1次迭代成功)
126
+ - 用 VLM 视觉分析截图确认前端 UI 渲染正确
127
+ - 更新 test_automated.py 新增流式SSE浏览器测试用例
128
+ - 更新测试说明.md 增加流式API和E2E测试文档
129
+ - 推送代码到 GitHub: 2ce96cc
130
+
131
+ Stage Summary:
132
+ - 前后端流式通信完全正常,用户遇到的"无回复"很可能是服务器未启动或提前崩溃
133
+ - SSE 流式输出验证通过:43个chunk,完整的 8 种事件类型
134
+ - E2E 测试工具链已就绪:test_e2e_runner.py 一键运行
135
+ - 截图保存在 /home/z/my-project/download/stream_test_result.png
136
+
137
+ ---
138
+ Task ID: 1
139
+ Agent: Main Agent
140
+ Task: 修复前端V2模式下"无回复"和刷新后排版断裂问题
141
+
142
+ Work Log:
143
+ - 分析 flow_engine.js sendMessage() 的 SSE 事件处理流程
144
+ - 发现根因:V2模式下 text_delta 事件包含原始XML(<output><usersays_correct>...),被当作用户可见内容
145
+ - 发现根因:最终 content 仅从 msgParts.filter(p.type==='text') 组装,但 V2 的用户文本来自 v2_reasoning/v2_ask_user 事件
146
+ - 发现根因:flushCurrentText() 在 V2 模式下将原始 XML 推入 msgParts,导致 content 是原始标签而非中文文本
147
+ - 新增 _isV2Mode 标志位(通过 v2_context 事件激活)
148
+ - 新增 _v2RawXml 分离存储(V2模式下 text_delta 不再混入 msgParts)
149
+ - 新增 _assembleV2Content() 函数,按优先级组装最终内容:v2_reasoning > _askUser > V1 text parts > server content > '(无回复)'
150
+ - 修复 flushCurrentText() 在 V2 模式下不将 raw XML 推入 msgParts
151
+ - 修复 text_delta handler:V2模式下显示 v2_reasoning 文本而非原始XML
152
+ - 修复 v2_reasoning handler:多事件间添加 \n\n 分隔符,同时更新 content 和 _streamingText
153
+ - 修复 done/finalization handler:使用 _assembleV2Content() 替代旧的 filter+join 逻辑
154
+ - 修复 queue_start/clear_text handler:同样使用 _assembleV2Content()
155
+ - 所有旧式 "msgParts.filter(p=>p.type==='text').join('\\n\\n') || '(无回复)'" 已替换为 _assembleV2Content()
156
+
157
+ Stage Summary:
158
+ - 修改文件: web/ui/chat/flow_engine.js
159
+ - 核心修复:V2模式用户可见内容现在来自 v2_reasoning/v2_ask_user 事件,不再显示原始XML
160
+ - 后向兼容:V1模式行为不变(text_delta 仍然是用户可见内容)
161
+
162
+ ---
163
+ Task ID: 3
164
+ Agent: Main Agent
165
+ Task: 修复聊天页面三个渲染Bug + web_search结果传递给LLM的问题
166
+
167
+ Work Log:
168
+ - **web_search结果传递问题**: 定位到 _extract_tool_output() 函数优先返回 message 摘要("找到16条结果")而忽略 data 字段中的URL。修复: 新增 _format_data_for_llm() 智能格式化函数,优先处理 data 字段;增大搜索类工具输出截断限制到6000字符
169
+ - **推理框闪烁**: 推理块(thought-block)每次 throttledStreamUpdate(~12fps)都用 outerHTML 完全重建,包括 renderMarkdown() 重渲染全部内容。修复: 改为增量更新——只更新字数统计/badge,用 insertAdjacentHTML 追加新增文本
170
+ - **消息位置错乱**: updateStreamingMessage() 通过计算 .assistant 行找目标消息,但 msgIdx 是全局索引(含user/tool行),导致匹配错位。修复: 改为计算所有 .message-row 行来匹配 msgIdx
171
+ - **聊天历史显示XML**: 后端存储了 LLM 原始 XML 输出(key=llm_output)到数据库,刷新后前端加载显示裸XML。修复:
172
+ - 后端 api_server.py: handle_get_messages/query 过滤掉 _HIDDEN_KEYS = {llm_output, tool_call, tool_result}
173
+ - 前端 chat_main.js: selectSession/loadMoreMessages 加载时对 XML 内容执行 _stripXmlTags 清理
174
+
175
+ Stage Summary:
176
+ - 修改文件: agents/main_agent.py, web/ui/chat/flow_engine.js, web/ui/chat/chat_main.js, web/api_server.py
177
+ - agents/main_agent.py: _extract_tool_output() 重写 + _format_data_for_llm() + 截断限制增大
178
+ - flow_engine.js: 推理框增量更新、消息索引修正
179
+ - chat_main.js: 消息加载时XML清理
180
+ - api_server.py: 聊天历史API过滤内部键
181
+
182
+ ---
183
+ Task ID: 2
184
+ Agent: Main Agent
185
+ Task: v1.15.3 - 修复 LLM 调用 400 错误 (缺少 user role 消息)
186
+
187
+ Work Log:
188
+ - 定位根因: main_agent.py 的 _process_v2_inner() 在构建 LLM 消息时,首次迭代(无工具输出)只发送了 system 消息,缺少 role=user 的消息
189
+ - OpenAI 兼容 API 要求消息列表中至少包含一条 role=user 的消息,否则返回 400 错误
190
+ - 修复: 在 else 分支中,当 all_tool_outputs 为空时,追加一条 role=user 的消息,内容为 context.user_message 或默认文本 "请处理上述上下文。"
191
+ - 额外改进: LLM 调用失败时将错误信息保存到会话记忆,刷新后仍可见
192
+
193
+ Stage Summary:
194
+ - 修改文件: agents/main_agent.py, package.json
195
+ - version: 1.15.2 → 1.15.3
196
+ - 核心修复: 确保每次 LLM 调用的 messages 数组始终包含 role=user 消息
197
+
198
+ ---
199
+ Task ID: 3
200
+ Agent: Main Agent
201
+ Task: v1.15.4 - 四项前端修复 (流式MD渲染/工具详情/推理持久化/滚动持久化)
202
+
203
+ Work Log:
204
+ - 修复流式输出时未闭合代码块显示裸MD: 改写 renderMarkdown() 的 Step 1.5,检测最后一个未闭合的 ``` 开头,将其内容渲染为带 streaming-code-block 样式的代码块(左边框脉动动画)
205
+ - 修复工具执行详情按钮点击无效: 所有 showToolResultModal/showExecResultModal 的 onclick 中 eventId 未加引号,字符串ID无法作为JS标识符传递。统一添加引号,匹配逻辑改为 String(e.id) === String(eventId)
206
+ - 修复刷新后推理过程丢失:
207
+ - LLMResponse 新增 reasoning 字段,_call_llm_stream 返回 full_reasoning
208
+ - main_agent.py 将推理文本以 key=reasoning 保存到会话记忆
209
+ - 前端 groupHistoryMessages 识别 key=reasoning 消息,合并到分组消息的 reasoning 字段
210
+ - 修复滚动位置不持久化:
211
+ - 新增 saveScrollPosition()/restoreScrollPosition() 函数
212
+ - 滚动事件触发防抖保存
213
+ - saveUIState() 中立即保存(beforeunload 时)
214
+ - selectSession() 渲染后恢复滚动位置
215
+
216
+ Stage Summary:
217
+ - 修改文件: package.json, core/llm.py, agents/base.py, agents/main_agent.py, web/ui/chat/chat_main.js, web/ui/chat/flow_engine.js, web/ui/chat/chat.css
218
+ - version: 1.15.3 → 1.15.4
219
+ - 核心修复: 流式Markdown渲染、工具详情弹窗、推理过程持久化、滚动位置持久化
220
+
221
+ ---
222
+ Task ID: 4
223
+ Agent: Main Agent
224
+ Task: v1.15.5 - 推理框宽度/finish_reason显示/TTS播报/STT自动安装
225
+
226
+ Work Log:
227
+ - 修复推理过程框文本宽度: thought-content 添加 box-sizing:border-box,子元素 p/pre 添加 width:100%;max-width:100%;box-sizing:border-box,message-content 内联样式补全 width:100%
228
+ - 实现 finish_reason 展示: v2_output_parsed 事件中 finish=true 时,将 finish_reason 存到 msg._v2FinishReason;渲染时在 taskPlan 之后显示绿色左边框标签;流式更新时动态插入 DOM
229
+ - 实现 finish_reason TTS/通知逻辑:
230
+ - TTS 未在播报且已开启 → 调用 ttsManager.speakText() 直接播报
231
+ - TTS 正在播报 → 弹出带双音提示音的通知窗口(5秒自动关闭)
232
+ - TTS 未开启 → 仅在消息中显示文字
233
+ - 新增 ttsManager.speakText() 方法: 支持直接传入文本进行 TTS 播报(不依赖消息索引)
234
+ - 新增 _showFinishNotification() 函数: 双音提示 + 弹窗通知
235
+ - 修复 STT 安装问题:
236
+ - deps_checker.py 添加 faster-whisper 依赖项(category=stt)
237
+ - deps_checker.py category_map 添加 stt 映射
238
+ - start.js CORE_PACKAGES 添加 faster-whisper
239
+ - api_server.py handle_voice_stt 的 ImportError 处理中添加自动安装逻辑(ensure_skill_deps)
240
+ - 前端错误提示改为友好信息
241
+
242
+ Stage Summary:
243
+ - 修改文件: package.json, core/deps_checker.py, web/api_server.py, web/ui/chat/chat_main.js, web/ui/chat/flow_engine.js, web/ui/chat/chat.css, start.js
244
+ - version: 1.15.4 → 1.15.5
245
+ - 核心修复: 推理框宽度、finish_reason展示+TTS播报、STT自动安装
246
+
247
+ ---
248
+ Task ID: 5
249
+ Agent: Main Agent
250
+ Task: v1.15.5 后续修复 — 弹出窗口链接、部门侧栏、成员数、后台部门详情
251
+
252
+ Work Log:
253
+ - 修复弹出窗口(popout)链接错误: new URL('.', ...).href + 'chat/...' 导致双路径问题,改为 window.location.origin + '/ui/chat/chat_container.html'
254
+ - 修复右侧边栏部门点击不展开: renderRpDeptNode 的 .rp-dept-item div 添加 onclick="toggleRpDept()",点击部门名称即可展开/折叠显示 agent 列表
255
+ - 部门名称后始终显示成员数: 之前仅在 agentCount > 0 时显示,改为始终显示 "(N成员)" 标签(chat_main.js 右侧面板、renderDeptItem、admin renderDeptTree)
256
+ - 修复后台部门成员数不准: departments/manager.py get_dept() 方法返回结果补充 agent_count 字段(动态计算 len(meta.agents))
257
+ - 重构后台部门详情弹窗(index.html showDeptDetail):
258
+ - 保存/关闭按钮移至页面最底部(justify-content:flex-end)
259
+ - 成员列表改为行列表样式(每行带背景、emoji、名称、部长标签、删除按钮)
260
+ - 删除按钮从 × 改为明显的"删除"文字按钮(btn-danger 样式)
261
+ - 暂无成员时显示带虚线边框的空状态提示
262
+
263
+ Stage Summary:
264
+ - 修改文件: web/ui/chat/chat_main.js, web/ui/index.html, departments/manager.py
265
+ - version: 1.15.5 (unchanged, cumulative fixes)
266
+ - 核心修复: popout链接、部门点击展开、成员数显示、后台部门详情弹窗布局
267
+
268
+ ---
269
+ Task ID: 6
270
+ Agent: Main Agent
271
+ Task: context_window 从配置动态读取,不再硬编码 128000
272
+
273
+ Work Log:
274
+ - 发现 context_builder.py:738 硬编码 window=128000,完全忽略了模型配置的 context_window
275
+ - LLMClient.__init__ 新增 context_window 参数(默认 128000)
276
+ - main.py 创建 LLMClient 时传入 context_window=llm_cfg.context_window
277
+ - ContextBuilder.__init__ 新增 context_window 参数,_enforce_token_budget() 改用 self.context_window
278
+ - init_context_builder() 自动从 self.llm.context_window 读取并传给 ContextBuilder
279
+ - _hot_reload_llm() 新增 context_window 同步到所有 agent 的 context_builder
280
+ - _build_model_chain() 在模型链字典中加入 context_window 字段
281
+ - _try_model_chain_inner/_stream_inner 切换模型时同步 context_window 到 context_builder
282
+ - _try_model_chain_inner/_stream_inner 的 finally 恢复原始 context_window
283
+ - get_llm_client() 工厂函数传入 context_window
284
+
285
+ Stage Summary:
286
+ - 修改文件: core/llm.py, core/context_builder.py, main.py, agents/main_agent.py, web/api_server.py
287
+ - version: 1.15.5 → 1.15.6
288
+ - 核心修复: context 截断现在根据模型配置中的 context_window 动态调整,不再硬编码 128000
289
+ - 影响范围: 启动初始化、热重载、模型链切换(含 fallback)都会正确同步 context_window
290
+
291
+ ---
292
+ Task ID: 7
293
+ Agent: Main Agent
294
+ Task: knowledge写入隔离 + 注释聊天历史注入
295
+
296
+ Work Log:
297
+ - 发现 _save_knowledge_to_base() 总是写入 organization/knowledge/auto_knowledge/,导致所有 agent 知识混在一起
298
+ - 修改 _save_knowledge_to_base() 优先写入 agent_knowledge_dir(agent 专属目录),无 agent KB 时才回退 knowledge_base_dir(组织 KB)
299
+ - 注释掉 build_context() 中的 _build_recent_dialog() 调用,不再注入 <resentdialog> 聊天历史
300
+ - 现在上下文仅包含:datetime + whoami + automemory + recall_memory + knowledge + user_input + task_plan + tools
301
+ - 用户最新消息通过 messages[role=user] 直接传入 LLM,工具执行结果通过 all_tool_outputs 传入
302
+
303
+ Stage Summary:
304
+ - 修改文件: agents/main_agent.py, core/context_builder.py
305
+ - version: 1.15.6 (cumulative)
306
+ - 核心修复: knowledge 写入隔离到 agent 目录;取消聊天历史注入,依赖系统记忆