diff --git a/.github/workflows/ai-cross-platform.yml b/.github/workflows/ai-cross-platform.yml
index 53a5a534..3f0ca0e6 100644
--- a/.github/workflows/ai-cross-platform.yml
+++ b/.github/workflows/ai-cross-platform.yml
@@ -21,6 +21,13 @@ on:
- 'tools/build_ai_smoke.cjs'
- 'frontend/components/**'
- 'frontend/composables/useAiApi.js'
+ - 'frontend/composables/useApi.js'
+ - 'frontend/composables/chat/useChatSearch.js'
+ - 'frontend/tests/chat-calendar.test.js'
+ - 'src/wechat_decrypt_tool/chat_realtime_reader.py'
+ - 'src/wechat_decrypt_tool/routers/chat.py'
+ - 'tests/test_chat_calendar_queries.py'
+ - 'tests/test_chat_message_calendar_heatmap.py'
- 'tests/test_ai*.py'
- 'tests/test_local_search*.py'
- 'pyproject.toml'
@@ -36,7 +43,8 @@ jobs:
matrix:
os: [windows-2022, macos-14]
runs-on: ${{ matrix.os }}
- timeout-minutes: 30
+ # Windows 的真实 SQLite 持久化测试耗时波动较大,为后续构建预留时间。
+ timeout-minutes: 60
env:
# macOS setup-python builds may lack SQLite loadable-extension support.
# Use uv-managed CPython for both source checks and the frozen runtime.
@@ -50,14 +58,25 @@ jobs:
with:
node-version: 22
- run: python -m pip install uv
+ # macOS 的部分 Python 构建不支持 SQLite 扩展;统一使用 uv 托管解释器。
- name: Install Python with SQLite extension support
run: uv python install 3.11
- - run: uv sync --locked --extra build
+ - run: uv sync --locked --extra build --python 3.11 --managed-python
- name: AI runtime and media (synthetic, no API calls)
run: uv run python tools/verify_ai_runtime.py
- name: AI and local search regression
shell: bash
- run: uv run pytest -q tests/test_ai*.py tests/test_local_search*.py
+ # 首次失败立即输出具体断言,避免超时取消后只留下进度标记。
+ run: uv run pytest -x -vv --tb=short --durations=15 tests/test_ai*.py tests/test_local_search*.py
+ - name: Chat calendar and date navigation regression
+ run: >-
+ uv run pytest -q
+ tests/test_chat_calendar_queries.py
+ tests/test_chat_message_calendar_heatmap.py
+ tests/test_native_core_realtime.py
+ tests/test_chat_export_targets.py
+ tests/test_chat_source_auto.py
+ tests/test_chat_request_perf.py
- run: npm ci
working-directory: frontend
- run: npx vitest run
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 7efd42c4..8c8b524f 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -561,6 +561,8 @@ jobs:
- name: Run focused desktop release tests
working-directory: desktop
shell: pwsh
+ env:
+ WDA_REQUIRE_NSIS_TEST: "1"
run: |
node --test `
tests/desktop-settings.test.cjs `
diff --git a/.gitignore b/.gitignore
index 8b42e75a..13098690 100644
--- a/.gitignore
+++ b/.gitignore
@@ -118,3 +118,6 @@ pnpm-lock.yaml
# 高级版演示走片的默认输出目录(website/dev/shot.mjs),只是本地调试产物
pro-shots/
+
+# 隔离验收数据库、真实聊天资料和本地状态快照不得进入版本库。
+/tmp/deepagents-migration/
diff --git a/design-qa.md b/design-qa.md
index 961518ef..ff280245 100644
--- a/design-qa.md
+++ b/design-qa.md
@@ -226,6 +226,248 @@ final result: passed
新增菜单组件 6 项测试,聊天组件 20 项回归测试通过。检查范围为菜单交互,不包含真实模型执行;前述实机模型验收仍待完成。修改本地保存,未经用户确认不推送。
+## 全账号助手本轮界面验收(2026-09-10)
+
+以用户提供的 D01~D04 图片为参考,完成 AI Elements Vue 与 Tailwind 4 接入后的组件和生产页面验证。最终记录为 `tmp/ai-assistant-implementation-20260910/browser-final/result.json`,11 个场景通过,无页面错误;截图位于同目录。旧日期记录不能代表本轮通过。
+
+侧栏实测 320px、横向溢出 0px,静态圆环 10px、主按钮 28px,控件文字 12px。D01 深浅主题及模型菜单、D02 展开、D03 实际发送者来源预览、D04 深浅主题和缺图均已检查。D04 按参考图采用浅色页头、灰色图片区和浅色底部控件,深色使用对应变量。查看器仅浏览当前回答引用图片,支持缩放、旋转、移动、复位和定位。
+
+修复了 Conversation 实际滚动容器识别、来源悬停后点击被自动浮层关闭、Nuxt 自动导入误识别工具函数参数导致生产聊天页异常的问题。生产页面检查了切换聊天后 AI 草稿保持、旧工具入口、朋友圈及 AI 设置。组件测试 239 项、前端 Node 测试 62 项通过,生产构建成功。
+
+用户要求不操作其桌面,检查使用后台内置浏览器及无界面浏览器,数据和图片为独立样例。以上不是原生 Electron、真实中文输入法或真实模型验收;Mac 当前离线。完整边界见 `docs/ai-assistant-implementation-2026-09-10.md`。
+
+## Mac 本轮真实界面复验(2026-09-11)
+
+Mac 上线后,在 `/Users/sheng/WeChatDataAnalysis-ai-check-20260910-01` 核对 1,133 个交付文件 SHA-256,运行同版本源码。macOS 26.3.1 / arm64 上本轮 569 项自动化与生产构建全部通过;这与 2026-09-08 记录分开计。
+
+真实 Electron 40.0.0 图形会话检查了聊天加载、切换聊天后 AI 草稿保持、窗口实际隐藏后返回、多行输入、旧工具入口和朋友圈,6 个场景通过,无页面错误。图形启动由 `tools/launch_ai_macos_acceptance.py` 和 `tools/verify_ai_electron.cjs` 重现;`electron-final/result/result.json` 为最终记录。第一次 SSH 直接启动因原生 broker 不可用失败,保留 `electron-01`,未绕过安全检查。
+
+Mac Chrome 的 `browser-final/result.json` 另有 11 个通过场景,覆盖 D01 深浅主题和模型菜单、D02 展开、D03 来源预览、D04 深浅主题和缺图及主要页面。侧栏 320px、横向溢出 0px、圆环 10px、主按钮 28px。数据与媒体均为样例;真实中文输入法、真实模型交互和 Windows 原生桌面仍未验收,不能据此宣称整项完成。
+
## PR #142 提交前检查(2026-09-09)
用户已明确授权将以上本地修改提交到 PR #142。提交目录已快进同步该 PR 最新的安装器与收藏修复(989818b),未覆盖这些改动。最终目录的前端 Vitest 233 项、Node 基础测试 62 项及后端 Agent/上下文/消息分页 67 项全部通过,git diff --check 通过。沿用上一轮实际组件浏览器的视觉检查结果;真实模型桌面输入测试仍未完成,不以模拟测试替代该项结论。
+
+
+## 启动失败专项复验(2026-09-11)
+
+临时开发页面 3040 的导航没有真正受 60 秒期限约束,导致旧窗口长时间挂起。修复实际导航期限与静态页面入口:静态模式跟随已就绪后端地址,忽略遗留开发 URL。Windows 和 Mac 针对性桌面测试各 11 项通过。Mac 真实 Electron 静态启动及窗口/页面回归共 7 个场景通过;真实 HTTP 连接不响应测试在 1 秒期限后 1,013ms 中止,并成功恢复页面。首次新增验收脚本求值错误及修正后结果均保留。
+
+最终专项证据:`tmp/ai-assistant-implementation-20260910/startup-fix-20260911/`,Mac 结果为 `mac/electron-startup-fixed-02/result/result.json`。Windows 生产页面在内置浏览器可用;未操作 Windows 桌面,不宣称原生 Windows、真实输入法或真实对话模型验收完成。
+# 2026-09-11 当前助手修改复核
+
+本轮新截图与问题记录见 [AI 助手 UI 复核](docs/ai-assistant-ui-audit-2026-09-11.md)。Windows 原生操作权限已恢复,新增实际输入法、切换聊天、窗口返回及深浅主题检查;修复静态重建缓存、Tailwind 深色覆盖、预算浮层裁切,并将正式本地索引设置调整为全账号渐进整理。复核仍在进行,Mac 新修改和真实远程模型未验证。
+
+## 2026-09-13 圆环悬停浮层(用户选定第 1 张设计图)
+
+本节仅验收 AgentContextRing 的本次修改,保留以上历史验收记录。
+
+- source visual truth: `C:/Users/123/.codex/generated_images/01a09662-f919-73d0-8510-842ed6cb32de/exec-5673307b-faf2-4dbc-aabd-60bd0feed07a.png`(1774 × 887)。
+- implementation screenshots: `tmp/context-ring-20260913/desktop.png`(1200 × 800)、`detail.png`(330 × 190)、`hover-light.png`、`hover-dark.png`、`unknown.png`(后三张均为 496 × 697)。
+- viewport: 桌面 1200 × 800 CSS px,DPR 约 1;默认内置浏览器 511 × 718 CSS px,DPR 1.25,浏览器截图输出为 496 × 697。侧栏实测 320 CSS px。
+- state: 0.6% 用量的鼠标悬停、移入浮层、键盘焦点、Esc 关闭、明暗主题,以及新对话容量未知。
+- density normalization: 参考是放大的组件概念图,并非原生 CSS 像素截图。按浮层边界和正文行高比较组件比例,不按整张画布像素等比还原;实现浮层实测 224 × 98.2 CSS px。默认浏览器截图另有显示缩放,不用于精确尺寸判断,尺寸以 DOM 实测记录 `metrics.json` 为准。
+- full-view comparison evidence: 在同一比较输入中查看选定设计图与 hover-light.png,核对浮层相对输入框、圆环及模型栏的位置。
+- focused comparison evidence: 在同一比较输入中查看选定设计图与 detail.png,核对三行文案、居中层级、圆角、描边、箭头和阴影。
+
+### Findings
+
+无尚待修复的 P0/P1/P2 问题。
+
+1. 字体:沿用应用现有中文无衬线字体,正文 14px / 21px,估算值 11px,常规字重。标题浅灰、比例次级灰、用量深色,三行均居中且无换行。
+2. 布局:浮层 224px 宽、16px 圆角、12px/14px 内边距、4px 行间距;定位以圆环为锚点,输入区边缘预留 8px。实测横向范围在输入框内,箭头对准圆环。参考图是放大稿;现有 10px 圆环和输入栏尺寸按用户要求保留。
+3. 颜色:复用应用明暗主题变量、浅描边和极轻阴影;深色模式已截图检查。
+4. 图形:复用原有 ContextIcon,不新增位图或改变圆环。浮层尖角属于提示容器边框。
+5. 文案:保留选定图的“上下文窗口 / 估算值”“约 0.6% 已用”“已用约 5.4k / 可用 917k”;真实界面使用响应式预算数据,样例值只在预览参数 budget=reference 中使用。未知容量显示提示,不伪造零用量。
+
+### 验证与比较历史
+
+- 首次实际组件截图的视觉比较无 P0/P1/P2 漂移,无额外视觉迭代。
+- 修正旧浮层相对整个输入区定位和原生 title 重复弹框的问题。
+- 浏览器验证:鼠标移入浮层以及跨过间隙时保持显示;Tab 焦点显示;Esc 关闭浮层且不关闭助手;焦点在输入框、鼠标悬停圆环时,Esc 同样生效;新对话显示未知用量;窄侧栏与明暗主题正常。
+- DOM 实测 boundsOkay=true、titleAbsent=true,桌面浮层中心与圆环中心一致。
+- 浏览器控制台 error/warn 为空。
+- 本机默认 Node 18 不符合现有 Vite 运行要求;改用已安装的 Codex 新版 Node 后,3 个相关测试文件、30 项测试通过。最终 Esc 修正后重新运行同组测试,仍全部通过。
+- git diff --check 针对本次前端文件通过,仅提示仓库 CRLF 换行策略。
+- 验收使用实际 Vue 组件与示例数据,未重新打包 Electron,未调用真实模型。
+
+### Implementation Checklist
+
+- [x] 三行浮层和小箭头
+- [x] 圆环定位与边缘避让
+- [x] 移除原生重复提示
+- [x] 鼠标、键盘、未知用量和明暗主题检查
+- [x] 相关组件测试
+
+final result: passed
+
+### 2026-09-13 用户追加:整体更小、更轻巧
+
+用户在实际预览后要求缩小整个浮层。最终规格替换本节上一版尺寸:196 × 78.4 CSS px(原 224 × 98.2),正文 12px/18px,估算标注 10px,内边距 9px/12px,行间距 2px,圆角 12px。三行层级、轻描边、轻阴影和交互不变。
+
+最新证据:`tmp/context-ring-20260913/compact-desktop.png`、`compact-detail.png`、`compact-narrow.png`。实际浏览器重新检查:三行无折行,宽 196px、高 78.4px,320px 侧栏内无越界。特写确认缩小字体和留白后仍完整可读。此为用户明确要求的比例调整,不属于参考图偏离。已恢复浏览器临时视口设置。
+
+final result: passed
+
+## 2026-09-13 句尾引用胶囊(第 3 张布局+第 2 张细描边)
+
+- source visual truth: `C:/Users/123/.codex/generated_images/01a09662-f919-73d0-8510-842ed6cb32de/exec-4f139ab8-62a1-4021-8ff5-40974c958630.png`(1620 × 972 左右的放大概念稿)。用户确认后实现。
+- implementation screenshot: `tmp/citation-pills-20260913/light.png`、`detail.png`、`dark-narrow.png`。
+- viewport: 1200 × 800 CSS px;侧栏分别 440px、320px。完成后恢复内置浏览器默认视口。
+- state: 句尾引用、无头像引用、点击打开来源、定位成功、键盘焦点、Esc 关闭、明暗主题。
+- full-view comparison: 在同一比较输入中查看合成稿与实际组件截图;仅改引用胶囊,现有正文排版、动态来源位置和编号继续来自实际回答。
+- focused comparison: 同一输入查看合成稿与 detail.png,核对胶囊圆角、描边、内部间距及句尾对齐。参考图是放大展示,按胶囊相对正文的比例校准,实际 CSS 高度20px,字号11px,头像14px;不按整张概念画布等比放大应用。
+
+### Findings 与保留的产品约束
+
+无胶囊相关 P0/P1/P2 问题。
+
+- 字体:编号为11px常规字重、16px行高、等宽数字特性,辅助于正文。
+- 布局:999px圆角、20px高,头像14px,间距3px;单数字含头像实测33.06px宽、无头像22px宽。胶囊整体换行,头像和编号不拆散。320px侧栏无横向溢出。
+- 颜色:浅色近白绿底 #f8fcfa、边框 #ccebdd,绿色编号;深色改用深绿底和可辨识描边。悬停、选中和键盘焦点均有独立视觉状态。
+- 资产:生产组件继续显示实际来源头像;预览明确使用仓库logo图片验证14px图片加载和圆形裁切,不复制真实联系人头像。真实编号按引用顺序生成,预览1/2/3对应设计稿19/20/21的动态内容差异,非样式偏差。
+- 文案:保留示例摘要两句;另增无头像验收段落。代码未改写原始回答、来源对应关系或引用顺序。
+
+### 验证
+
+- 浏览器点击引用打开消息来源预览;点击定位按钮后出现“已定位原消息”(示例导航,不读取真实聊天)。
+- Esc关闭预览;Tab能移到下一引用并显示solid焦点轮廓。
+- 图片完成加载,头像实测14px;纯编号正常。
+- 440px浅色和320px深色场景已截图,后者正文横向溢出为false。
+- error/warn控制台记录为空。
+- 原文预览、Markdown和引用相关3个测试文件共19项通过。
+- git diff --check通过;只提示原有CRLF换行策略。
+- 独立预览新增深色切换后发现定位结果演示卡文字继承浅色的问题,已为该示例卡设置固定深色文字;不涉及生产胶囊。
+- 首次组件对比无需要迭代的胶囊视觉问题。保留了原有组件交互与生产头像路径,未重新打包Electron。
+
+### Implementation Checklist
+
+- [x] 细描边全圆角胶囊与小头像
+- [x] 句尾内联和完整胶囊换行
+- [x] 无头像、深浅主题、选中及键盘焦点
+- [x] 点击原文和示例定位
+- [x] 相关测试与截图复核
+
+final result: passed
+
+## 2026-09-14 上下文压缩分隔与摘要保留
+
+source visual truth: `C:/Users/123/.codex/generated_images/01a09e9d-579d-7630-88e1-ff8a8fe1f4e5/exec-e5f847f0-257e-4fba-8f39-41f3e3b0e28b.png`。
+
+implementation: 现有 `AgentRun.vue` 与新增 `AgentContextCompaction.vue`;浏览器验收入口 `http://127.0.0.1:3050/tests/fixtures/agent-compaction.html`,明确使用示例数据,不调用模型。
+
+### 比较目标与证据
+
+- 源图 1422×1106,是两个生命周期状态的放大概念板;主要实现全屏截图 1100×900 CSS/像素,画面内包含 440px 与 320px 两种实际侧栏。重启后的过程折叠复核 `process-collapsed-fixed.png` 使用恢复后的 500×697 默认视口,细节图为 375×84;折叠顺序按 DOM 与可见界面判断,不据不同视口推断像素间距。验收结束已恢复浏览器默认尺寸。
+- 按源图单个内容区域约 515px 与实际内容区域 375px 的比例比较字级和留白,不按整个双栏画布一比一缩放;保留应用现有字体与工具行,不复刻概念图窗口边框或聊天内容。
+- Full-view:在同一次工具比较输入中查看源图与 `tmp/compaction-ui-20260914/running.png`;复核修订后 `running-fixed.png` 和 `completed.png`。
+- Focused:在同一次工具比较输入中查看源图与 `completed-detail.png`。分隔线、文档图标、标签字级和默认隐藏摘要均可读。
+- 其他证据:`expanded.png`、`dark.png`、`failed.png`、`process-collapsed.png`、`process-collapsed-fixed.png`,均在上述 tmp 目录。
+
+### Findings 与修复迭代
+
+1. [P2,已修复] 初稿字号偏小,左侧阅读轴穿过分隔区域。证据 `running.png`。标签从 12px 调整为 14px,辅助说明从 11px 调整为 12px;提示跨出步骤缩进,局部遮住阅读轴。后续 `running-fixed.png`、`completed.png` 与细节图确认修复。
+2. [P2,已修复] 手动收起过程时,当前继续分析状态先于历史压缩分隔显示。证据 `process-collapsed.png`。折叠态压缩节点移到当前状态前,并保持完成任务中的可见性。后续 `process-collapsed-fixed.png` 与 DOM 顺序确认修复。
+
+### 五项视觉核对
+
+- 字体:沿用应用字体,标签 14px 常规字重,说明/摘要 12px,行高 1.7;标题字级与正文相近,摘要默认无可见占位。
+- 间距:细线两端对齐内容阅读区,标签与图标间距 8px,分隔上下各 24px;运行中两行辅助说明及轻微省略号呼吸动画。320px 侧栏下未出现组件横向溢出。
+- 颜色:现有 app text/border/surface tokens;深色模式实测文字 rgb(199,199,199)、背景 rgb(34,38,41),无白色遮罩穿帮。
+- 资产:使用现有 FontAwesome 文档与省略号图标。未新增位图、替换用户头像或绘制自定义图标;概念图图标粗细与现有图标库差异为复用既有设计系统的选择。
+- 文案:运行中「正在压缩上下文」,当前已用百分比来自保存的 before/window;完成态只有「上下文已压缩」。失败及中断保留真实状态。概念图里的实际聊天记录在验收页使用明确标注的样例替代,不改动生产数据。
+
+### 行为与技术验收
+
+- 同一条记录从运行中更新为已完成,完成后默认折叠;点击展开摘要及 83.3% → 27.4%,Enter 收起。
+- 收起执行过程后记录仍可见,顺序在继续分析状态之前;多次压缩和后端/前端 200 步裁剪的保留行为通过测试。
+- 浅色/深色、440px/320px、失败态截图已复核;浏览器控制台 error/warn 为空。
+- 摘要加载失败可重试,账号/任务切换后晚到响应不会串入新页面;旧记录没有窗口时显示 Token。
+- 后端相关 87 项、前端相关 89 项测试通过(共 176 项,不重复计数);git diff --check 通过,仅有现有换行策略提醒。
+- 应用已重启,前后端健康检查通过;新接口成功读取真实历史压缩摘要。未自动运行用户聊天或调用真实模型触发压缩;真实新压缩的自然触发留待日常使用,确定性完整生命周期已覆盖。
+
+### Implementation Checklist
+
+- [x] 压缩中分隔提示与高水位更新
+- [x] 默认折叠的持久完成记录
+- [x] 每次摘要独立保存、按需读取及访问隔离
+- [x] 失败/中断、旧记录兼容和 200 步以外保留
+- [x] 视觉修订、深浅主题、窄栏与键盘交互
+- [x] 自动回归、真实历史接口检查、项目重启
+
+无尚未处理的 P0/P1/P2 界面问题。
+
+final result: passed
+
+## 2026-09-14 用户反馈修正:压缩记录跟随执行过程收起
+
+用户指出:收起「执行过程」后不应在外部继续展示「上下文已压缩」。此前「折叠后保留可见」的设计解释作废;保留指保存记录和摘要,重新展开可读。
+
+- 删除折叠态另行渲染压缩节点的分支;完成任务收起过程后不再为压缩记录撑开过程容器。
+- 展开后仍按原始时间顺序显示各次压缩,摘要和用户展开状态保留。
+- 正在运行时沿用现有简洁实时状态,完整压缩提示仍归入展开的执行过程。
+- 更新既有回归测试:覆盖运行中收起、完成后隐藏、再次展开两条历史压缩及读取摘要;相关 34 项前端测试通过。
+
+此项为折叠行为修复,不改动已确认的分隔样式或后端持久化。
+
+
+## 2026-09-14 模型与思考强度单入口落地
+
+### 视觉依据与实测环境
+
+- 批准的原稿:`C:/Users/123/.codex/generated_images/01a09e9d-579d-7630-88e1-ff8a8fe1f4e5/exec-7b087f6d-19fa-4be3-a842-16777debedcf.png`(1643×957)。这是放大展示的两个交互状态,不把演示画布的标题和说明塞进正式产品。
+- 真实组件预览:`http://127.0.0.1:3050/tests/fixtures/agent-model-picker.html`。
+- 实现截图:`D:/workProject/WeChatDataAnalysis/tmp/model-picker-light.png`、`model-picker-list.png`、`model-picker-dark.png`、`model-picker-narrow.png`(后三者同目录)。
+- 桌面 viewport 1100×900 CSS px,440/320px 两种侧栏;截图工具保存约 1085×888 的显示版本,比例约 0.986,不按差出的像素误判 CSS 尺寸。360×800 窄窗口另外检查。浏览器读取 DPR≈1、根元素 zoom=1。
+- 对照按原稿卡片约 625px 的展示宽度归一到实际 320px,原稿强度卡片高度约 234px,实际 DOM 为 320×117.6 CSS px。原稿、整体截图及控件局部截图曾放在同批图像输入中比较;最终布局判断使用完整截图和 DOM 尺寸,局部截图工具存在缩放偏移,未作为像素精度证据。
+- 重点复核整体图中的浮层区域:中间两行入口、重置按钮、五档刻度、绿色填充和白色滑块;列表区域:返回、居中标题、选中行与绿色勾。文字在完整截图中可读,无需依赖失真的裁剪判断。
+
+### Findings 与修订记录
+
+1. [P2,已修复] 初稿中间灰色按钮被网格拉伸到整列,宽于已批准原稿。改为居中、随内容宽度,最小 100px;重新截图后中间入口比例符合原稿。
+2. [P2,已修复] 初稿列表标题靠左且返回只有图标。增加「返回」,标题独立居中;最终 `model-picker-list.png` 已复核。
+3. [P2,已修复] 窄窗口预览继承了正式侧栏的 fixed 布局,使两个演示侧栏叠在一起。预览容器改为相对定位;最终窄图复核上下排列,DOM scrollWidth 345≤viewport 360,正式组件浮层位于窗口内。这是验收页面修复,不改变正式侧栏定位行为。
+4. 已保留的产品约束:正式模型列表保留服务分组、获取上游模型和手动输入,因此比只列四个名称的演示原稿更高;列表最高 380px/55vh 可滚动。输入框沿用现有两行排布;浮层沿用无尖角的产品菜单外形。这些为接入现有功能所需的差异。
+
+### 五项视觉核对
+
+- 字体:沿用当前应用的 system-ui 和中文回退;强度 16px、模型副标题 12px,模型长名称截断;层级与原稿一致。
+- 布局:单入口,弹层最大 320px;中心按钮、左右图标与滑杆对齐;窄窗口不挤掉发送入口。
+- 配色:浅色采用 #079b57,深色 #3eb575;表面、边线、正文均使用现有 app 主题变量。没有蓝色选中态。
+- 资产:使用已有 FontAwesome 闪电、箭头、复位、勾选图标;无需生成位图。滑杆使用原生 range,白色滑块和离散刻度是功能控件。
+- 文案:正式界面仅保留模型、档位、默认恢复、加载/错误与能力说明;设计演示说明仅在 fixtures 中。
+
+### 交互与工程验证
+
+- 浏览器实测:点击中间区域→同一浮层模型列表→选择模型后返回滑杆;新模型使用默认状态;键盘 End 切到末档;恢复默认清除覆盖。外部点击/Esc、加载迟到、列表刷新补齐能力另有自动回归覆盖。
+- 浅色、深色、440/320px 侧栏、360px 窗口已检查。浏览器 error/warn 日志为空,临时 viewport 已恢复。
+- 前端 326 项 Vitest 回归、后端相关 92 项通过,测试数不重复累计重跑。两个旧断言已按前面完成的全局模型文案和实际输出预留更新。
+- 项目已重启,前后端健康检查 200,启动错误日志为空。真实能力接口已核对 DeepSeek low/high/max + 开关、MiMo 开关;未执行用户聊天或付费推理。
+- 参数适配与验证细节:`docs/ai-model-reasoning-picker-2026-09-14.md`。
+
+### Implementation Checklist
+
+- [x] 绿色单入口与同浮层模型列表
+- [x] models.dev 档位、开关、预算及未知状态
+- [x] 后端能力校验、服务参数适配和模型隔离
+- [x] 全局保存、恢复默认、运行中快照与下轮生效
+- [x] 回归测试、视觉复核、项目重启和真实能力检查
+
+没有尚未处理的 P0/P1/P2 界面问题。未进行付费供应商逐一实发验收,已检查各适配器的真实 SDK 请求体。
+
+final result: passed
+
+
+## 2026-09-14 修订:紧凑浮层覆盖输入框
+
+用户反馈覆盖此前卡片尺寸和定位:缩小浮层、删除左上角闪电、浮层叠在输入框上。
+
+- 依据截图:`C:/Users/123/AppData/Local/Temp/codex-clipboard-c2b734da-7c46-4fa5-889c-765daa2c7239.png`(539×348,局部展示)。
+- 修订截图:`D:/workProject/WeChatDataAnalysis/tmp/model-picker-compact-overlay.png`;原反馈图与新图在同批图像输入中比较,重点观察浮层和输入框相交区域。截图来自当前用户预览标签页,viewport 515×718 CSS px,DPR 1.25;尺寸以 DOM 测量为准,不混同比例不同的截图像素。
+- [P2,已修复] 卡片过大:宽 320→240px,高约 118→89px,内边距和滑杆同步缩小,滑块 34→26px。
+- [P2,已修复] 位置偏高:定位基准从整个 composer 改成模型入口;距入口 6px,实测覆盖输入框 42.8px,不再以输入框上边缘定位。
+- [P2,已修复] 删除左上角闪电节点;保留居中的模型/强度入口及右侧恢复默认。
+- 保留绿色与已有字体,强度 14px、模型名 11px。模型列表随同缩到 240px,返回、服务分组和模型名称无裁切;原生滑杆交互保留,填充边界和刻度同步到新滑块尺寸。没有新增图片资产或改变产品文案。
+- 浏览器已检查强度和列表两态,回到强度态保留预览。10 项既有组件回归通过,git diff --check 通过。前端热更新已生效,无后端改动。
+
+final result: passed
diff --git a/desktop/package.json b/desktop/package.json
index 23bf9534..97b0870d 100644
--- a/desktop/package.json
+++ b/desktop/package.json
@@ -5,7 +5,7 @@
"main": "src/main.cjs",
"scripts": {
"dev": "node scripts/dev.cjs",
- "dev:static": "npm --prefix ../frontend run generate && cross-env ELECTRON_START_URL=http://127.0.0.1:10392 electron .",
+ "dev:static": "npm --prefix ../frontend run generate && cross-env WECHAT_TOOL_STATIC_UI=1 electron .",
"build:ui": "npm --prefix ../frontend run generate && node scripts/copy-ui.cjs",
"build:backend": "uv sync --no-editable --extra build --extra voice-transcription && node scripts/build-backend.cjs",
"build:icon": "node scripts/build-icon.cjs",
diff --git a/desktop/scripts/ai-packaging.cjs b/desktop/scripts/ai-packaging.cjs
index b0715e6c..6d57a708 100644
--- a/desktop/scripts/ai-packaging.cjs
+++ b/desktop/scripts/ai-packaging.cjs
@@ -5,7 +5,7 @@ const { spawnSync } = require('node:child_process');
// AI 的动态导入和清单统一收集,源码与冻结程序使用同一组资源。
function aiPackagingArgs(root, platform = process.platform) {
- const packages = ['langchain_core', 'langchain_openai', 'langchain_anthropic', 'langgraph', 'langsmith',
+ const packages = ['deepagents', 'langchain', 'langchain_core', 'langchain_openai', 'langchain_anthropic', 'langchain_google_genai', 'langgraph', 'langsmith', 'wcmatch', 'bracex',
'pypdf', 'pypdfium2', 'pypdfium2_raw', 'tiktoken', 'docx', 'pptx', 'openpyxl',
'onnxruntime', 'tokenizers', 'sqlite_vec', 'huggingface_hub'];
const args = packages.flatMap(name => ['--collect-all', name]);
diff --git a/desktop/src/main.cjs b/desktop/src/main.cjs
index a3a74384..b4493407 100644
--- a/desktop/src/main.cjs
+++ b/desktop/src/main.cjs
@@ -45,7 +45,7 @@ const {
shouldRetryBackendOnDifferentPort,
} = require("./backend-startup.cjs");
const { applyNativeCoreRuntimePolicy } = require("./native-core-runtime.cjs");
-const { loadWithRedirect } = require("./renderer-startup.cjs");
+const { loadWithRedirect, resolveDesktopUiUrl } = require("./renderer-startup.cjs");
const {
ENV_INTEGRITY_NATIVE_PATH,
ENV_MACOS_DB_KEY_BUNDLE,
@@ -307,9 +307,12 @@ function getBackendUiUrl() {
}
function getDesktopUiUrl() {
- const explicit = String(process.env.ELECTRON_START_URL || "").trim();
- if (explicit) return explicit;
- return app.isPackaged ? getBackendUiUrl() : "http://localhost:3000";
+ return resolveDesktopUiUrl({
+ startUrl: process.env.ELECTRON_START_URL,
+ backendUrl: getBackendUiUrl(),
+ isPackaged: app.isPackaged,
+ staticUi: process.env.WECHAT_TOOL_STATIC_UI === "1",
+ });
}
function isPortAvailable(port, host) {
@@ -863,9 +866,12 @@ function getDesktopSettingsPath() {
}
function getPackagedUiDir() {
- if (!app.isPackaged) return null;
+ // 静态开发入口也加载生成文件,重建后必须失效旧页面缓存。
+ if (!app.isPackaged && process.env.WECHAT_TOOL_STATIC_UI !== "1") return null;
try {
- return path.join(process.resourcesPath, "ui");
+ return process.env.WECHAT_TOOL_UI_DIR?.trim() || (app.isPackaged
+ ? path.join(process.resourcesPath, "ui")
+ : path.join(__dirname, "..", "..", "frontend", ".output", "public"));
} catch {
return null;
}
@@ -1303,7 +1309,7 @@ async function applyPendingOutputDirOnStartup() {
}
async function refreshRendererCacheForPackagedUi() {
- if (!app.isPackaged) return;
+ if (!app.isPackaged && process.env.WECHAT_TOOL_STATIC_UI !== "1") return;
const nextBuildId = readPackagedUiBuildId();
if (!nextBuildId) return;
@@ -1322,6 +1328,7 @@ async function refreshRendererCacheForPackagedUi() {
logMain(`[main] cleared renderer cache for UI build change: ${prevBuildId || "(none)"} -> ${nextBuildId}`);
} catch (err) {
logMain(`[main] failed to clear renderer cache for UI build change: ${err?.message || err}`);
+ return;
}
loadDesktopSettings();
@@ -2460,6 +2467,8 @@ function setupRendererLifecycleLogging(win) {
const logRendererLifecycle = (message) => {
logMain(`[renderer] ${message}`);
};
+ win.on('show', () => logRendererLifecycle('window-show'));
+ win.on('hide', () => logRendererLifecycle('window-hide'));
logRendererLifecycle(`window-created id=${win.id}`);
@@ -2568,14 +2577,15 @@ async function loadWithRetry(win, url) {
attempt += 1;
logMain(`[main] loadWithRetry attempt=${attempt} url=${url}`);
try {
- await loadWithRedirect(win, url);
+ const remaining = Math.max(1, 60_000 - (Date.now() - startedAt));
+ await loadWithRedirect(win, url, Math.min(5000, remaining), remaining);
logMain(`[main] loadWithRetry success attempt=${attempt} elapsedMs=${Date.now() - startedAt} url=${url}`);
return;
} catch (err) {
logMain(
`[main] loadWithRetry failure attempt=${attempt} elapsedMs=${Date.now() - startedAt} url=${url} error=${err?.message || err}`
);
- if (Date.now() - startedAt > 60_000) throw new Error(`Failed to load URL in time: ${url}`);
+ if (Date.now() - startedAt >= 60_000) throw new Error(`Failed to load URL in time: ${url}`);
await new Promise((r) => setTimeout(r, 500));
}
}
@@ -3469,9 +3479,14 @@ async function ensureMainWindowReady() {
logMain(`[main] debugEnabled=${debugEnabled()} startUrl=${startUrl}`);
await loadWithRetry(win, startUrl);
- if (debugEnabled()) {
+ // 首次创建不能只依赖构造器的显示行为;隐藏启动标志可能留下不可见主窗口。
+ if (mainWindow === win && !win.isDestroyed()) showMainWindow();
+
+ // 常规开发版启动也先显示应用;仅显式调试启动自动打开工具窗口。
+ if (debugEnabled() && (process.env.WECHAT_DESKTOP_DEBUG === "1" || process.argv.includes("--debug") || process.argv.includes("--devtools"))) {
try {
- win.webContents.openDevTools({ mode: "detach" });
+ // 调试窗口不抢走主窗口焦点,启动后用户能直接看到应用。
+ win.webContents.openDevTools({ mode: "detach", activate: false });
} catch {}
}
diff --git a/desktop/src/renderer-startup.cjs b/desktop/src/renderer-startup.cjs
index 181f036c..cd4df9fa 100644
--- a/desktop/src/renderer-startup.cjs
+++ b/desktop/src/renderer-startup.cjs
@@ -13,11 +13,13 @@ function isInternalRedirect(start, destination) {
}
// 首次使用页会中止初始导航;仅在同源目标实际完成加载后接受该跳转。
-async function loadWithRedirect(win, url, timeoutMs = 5000) {
+async function loadWithRedirect(win, url, timeoutMs = 5000, navigationTimeoutMs = 60000) {
const contents = win.webContents;
let finished = false;
+ let disposed = false;
let resolveFinished;
let timer;
+ let deadlineTimer;
const completion = new Promise(resolve => { resolveFinished = resolve; });
const onFinish = () => {
if (isInternalRedirect(url, contents.getURL())) {
@@ -26,17 +28,41 @@ async function loadWithRedirect(win, url, timeoutMs = 5000) {
}
};
contents.on('did-finish-load', onFinish);
+ const navigate = async () => {
+ try {
+ await win.loadURL(url);
+ } catch (error) {
+ if (disposed) throw error;
+ if (error?.code !== 'ERR_ABORTED' && error?.errno !== -3) throw error;
+ if (finished) return;
+ timer = setTimeout(() => resolveFinished(false), timeoutMs);
+ if (!await completion) throw error;
+ }
+ };
+ const deadline = new Promise((_, reject) => {
+ deadlineTimer = setTimeout(() => {
+ // loadURL 自身可能一直不返回;重试循环外的计时不能中断这种挂起。
+ const error = Object.assign(new Error(`页面加载超时:${url}`), { code: 'ERR_NAVIGATION_TIMEOUT' });
+ reject(error);
+ try { if (!contents.isDestroyed?.()) contents.stop?.(); } catch {}
+ }, Math.max(1, navigationTimeoutMs));
+ });
try {
- await win.loadURL(url);
- } catch (error) {
- if (error?.code !== 'ERR_ABORTED' && error?.errno !== -3) throw error;
- if (finished) return;
- timer = setTimeout(() => resolveFinished(false), timeoutMs);
- if (!await completion) throw error;
+ await Promise.race([navigate(), deadline]);
} finally {
+ disposed = true;
+ clearTimeout(deadlineTimer);
clearTimeout(timer);
+ resolveFinished(false);
contents.removeListener('did-finish-load', onFinish);
}
}
-module.exports = { loadWithRedirect, isInternalRedirect };
+function resolveDesktopUiUrl({ startUrl, backendUrl, isPackaged, staticUi }) {
+ // 静态模式跟随已经就绪的后端端口,不继承失效的开发服务器地址。
+ if (staticUi) return backendUrl;
+ const explicit = String(startUrl || '').trim();
+ return explicit || (isPackaged ? backendUrl : 'http://localhost:3000');
+}
+
+module.exports = { loadWithRedirect, isInternalRedirect, resolveDesktopUiUrl };
diff --git a/desktop/tests/acceptance-stream-proxy.test.cjs b/desktop/tests/acceptance-stream-proxy.test.cjs
new file mode 100644
index 00000000..b7a8d872
--- /dev/null
+++ b/desktop/tests/acceptance-stream-proxy.test.cjs
@@ -0,0 +1,80 @@
+const { test } = require('node:test')
+const assert = require('node:assert/strict')
+const http = require('node:http')
+const { createStreamProxy } = require('../../tools/ai_acceptance_stream_proxy.cjs')
+
+test('图片故障仅影响指定 MD5 的图片接口,恢复后继续读取原内容', async () => {
+ let upstream = 0
+ const backend = http.createServer((req, res) => { upstream++; res.end('原内容') })
+ await new Promise(resolve => backend.listen(0, '127.0.0.1', resolve))
+ const proxy = await createStreamProxy(`http://127.0.0.1:${backend.address().port}`, { passthrough: true })
+ const md5 = 'a'.repeat(32)
+ const path = '/api/chat/media/image?md5=' + md5
+ try {
+ assert.throws(() => proxy.setMissingImage('*', true))
+ proxy.setMissingImage(md5, true)
+ const missing = await fetch(proxy.url + path)
+ assert.equal(missing.status, 404)
+ assert.equal(missing.headers.get('cache-control'), 'no-store')
+ assert.equal(upstream, 0)
+ for (const url of ['/api/other?md5=' + md5, '/api/chat/media/image?md5=' + 'b'.repeat(32)]) {
+ assert.equal(await (await fetch(proxy.url + url)).text(), '原内容')
+ }
+ proxy.setMissingImage(md5, false)
+ assert.equal(await (await fetch(proxy.url + path)).text(), '原内容')
+ assert.equal(upstream, 3)
+ assert.deepEqual(proxy.images.map(x => x.missing), [true, false, false])
+ } finally {
+ await proxy.close()
+ backend.closeAllConnections()
+ await new Promise(resolve => backend.close(resolve))
+ }
+})
+
+test('验收代理切断真实流连接,重连保留 Last-Event-ID,后端保持可用', async () => {
+ const received = []
+ const backend = http.createServer((req, res) => {
+ received.push(req.headers['last-event-id'] || '')
+ res.writeHead(200, { 'content-type': 'text/event-stream' })
+ res.write('id: 7\ndata: {"version":1}\n\n')
+ })
+ await new Promise(resolve => backend.listen(0, '127.0.0.1', resolve))
+ const proxy = await createStreamProxy(`http://127.0.0.1:${backend.address().port}`)
+ try {
+ const response = await fetch(proxy.url + '/api/ai/agent/events?account=test')
+ const reader = response.body.getReader()
+ assert.match(new TextDecoder().decode((await reader.read()).value), /id: 7/)
+ proxy.drop()
+ await assert.rejects(reader.read())
+ proxy.resume()
+ const again = await fetch(proxy.url + '/api/ai/agent/events?account=test', { headers: { 'Last-Event-ID': '7' } })
+ await again.body.cancel()
+ assert.deepEqual(received, ['', '7'])
+ assert.equal(proxy.requests[1].last_event_id, '7')
+ } finally {
+ await proxy.close()
+ backend.closeAllConnections()
+ await new Promise(resolve => backend.close(resolve))
+ }
+})
+
+test('同源转发保留普通请求方法和正文,断流不影响其他 API', async () => {
+ const backend = http.createServer(async (req, res) => {
+ let body = ''
+ for await (const chunk of req) body += chunk
+ res.writeHead(200, { 'content-type':'application/json' })
+ res.end(JSON.stringify({ method:req.method, body, host:req.headers.host }))
+ })
+ await new Promise(resolve=>backend.listen(0,'127.0.0.1',resolve))
+ const proxy = await createStreamProxy(`http://127.0.0.1:${backend.address().port}`, { passthrough:true })
+ try {
+ proxy.drop()
+ const response=await fetch(proxy.url+'/api/test', { method:'POST',body:'消息正文' })
+ assert.deepEqual(await response.json(), { method:'POST',body:'消息正文',host:new URL(proxy.url).host })
+ assert.equal(proxy.requests.length,0)
+ } finally {
+ await proxy.close()
+ backend.closeAllConnections()
+ await new Promise(resolve=>backend.close(resolve))
+ }
+})
diff --git a/desktop/tests/renderer-cache.test.cjs b/desktop/tests/renderer-cache.test.cjs
new file mode 100644
index 00000000..a842fa2c
--- /dev/null
+++ b/desktop/tests/renderer-cache.test.cjs
@@ -0,0 +1,32 @@
+const test = require('node:test');
+const assert = require('node:assert/strict');
+const fs = require('node:fs');
+const path = require('node:path');
+const vm = require('node:vm');
+
+const source = fs.readFileSync(path.join(__dirname, '../src/main.cjs'), 'utf8');
+const cacheCode = source.slice(source.indexOf('async function refreshRendererCacheForPackagedUi()'), source.indexOf('function parseEnvBool('));
+function setup({ staticUi = '1', fail = false, previous = 'old' } = {}) {
+ const calls = [], settings = { lastSeenUiBuildId: previous };
+ const context = { app: { isPackaged: false }, process: { env: { WECHAT_TOOL_STATIC_UI: staticUi } },
+ readPackagedUiBuildId: () => 'new', loadDesktopSettings: () => settings, desktopSettings: settings,
+ persistDesktopSettings: () => calls.push('persist'), logMain: () => {},
+ session: { defaultSession: { clearCache: async () => { calls.push('cache'); if (fail) throw new Error('locked'); },
+ clearStorageData: async options => calls.push(options.storages) } } };
+ vm.createContext(context); vm.runInContext(cacheCode, context);
+ return { calls, settings, run: () => context.refreshRendererCacheForPackagedUi() };
+}
+test('静态开发重建后清理 HTTP 缓存,保留草稿和账号存储', async () => {
+ const state = setup(); await state.run();
+ assert.deepEqual(JSON.parse(JSON.stringify(state.calls)), ['cache', ['serviceworkers'], 'persist']);
+ assert.equal(state.settings.lastSeenUiBuildId, 'new');
+});
+test('缓存清理失败时保留旧版本标记,下次启动仍可重试', async () => {
+ const state = setup({ fail: true }); await state.run();
+ assert.deepEqual(state.calls, ['cache']); assert.equal(state.settings.lastSeenUiBuildId, 'old');
+});
+test('相同构建和普通开发服务器不触发缓存清理', async () => {
+ for (const options of [{ previous: 'new' }, { staticUi: '' }]) {
+ const state = setup(options); await state.run(); assert.deepEqual(state.calls, []);
+ }
+});
diff --git a/desktop/tests/renderer-startup.test.cjs b/desktop/tests/renderer-startup.test.cjs
index 8d152a62..c8c407d9 100644
--- a/desktop/tests/renderer-startup.test.cjs
+++ b/desktop/tests/renderer-startup.test.cjs
@@ -3,7 +3,7 @@ const assert = require('node:assert/strict');
const { EventEmitter } = require('node:events');
const path = require('node:path');
const { pathToFileURL } = require('node:url');
-const { loadWithRedirect, isInternalRedirect } = require('../src/renderer-startup.cjs');
+const { loadWithRedirect, isInternalRedirect, resolveDesktopUiUrl } = require('../src/renderer-startup.cjs');
test('首次使用页跳转完成后不重新加载首页', async () => {
const contents = new EventEmitter();
@@ -50,3 +50,37 @@ test('打包页面只接受同一目录内的跳转', () => {
assert.equal(isInternalRedirect(url('ui/index.html'), url('secret.html')), false);
assert.equal(isInternalRedirect(url('ui/index.html'), 'about:blank'), false);
});
+
+test('开发页面一直不响应时,在期限内中止加载并释放监听器', async () => {
+ const contents = new EventEmitter();
+ contents.getURL = () => 'http://127.0.0.1:3040/';
+ let stopped = 0;
+ let abort;
+ contents.stop = () => {
+ stopped++; contents.emit('did-finish-load');
+ setImmediate(() => abort(Object.assign(new Error('late abort'), { code: 'ERR_ABORTED' })));
+ };
+ await assert.rejects(loadWithRedirect({ webContents: contents,
+ loadURL: () => new Promise((_, reject) => { abort = reject; }) }, 'http://127.0.0.1:3040/', 5000, 20),
+ error => error.code === 'ERR_NAVIGATION_TIMEOUT');
+ assert.equal(stopped, 1);
+ assert.equal(contents.listenerCount('did-finish-load'), 0);
+});
+
+test('总期限包含未完成的首次使用页跳转,停止事件不能伪装为成功', async () => {
+ const contents = new EventEmitter();
+ contents.getURL = () => 'http://localhost:3000/agreement';
+ contents.stop = () => contents.emit('did-finish-load');
+ await assert.rejects(loadWithRedirect({ webContents: contents, loadURL: async () => {
+ throw Object.assign(new Error('aborted'), { code: 'ERR_ABORTED' });
+ } }, 'http://localhost:3000/', 10000, 20), error => error.code === 'ERR_NAVIGATION_TIMEOUT');
+ assert.equal(contents.listenerCount('did-finish-load'), 0);
+});
+
+test('静态入口使用实际后端端口,忽略遗留开发地址', () => {
+ const options = { startUrl: 'http://127.0.0.1:3040', backendUrl: 'http://127.0.0.1:10494/', isPackaged: false };
+ assert.equal(resolveDesktopUiUrl({ ...options, staticUi: true }), options.backendUrl);
+ assert.equal(resolveDesktopUiUrl(options), options.startUrl);
+ assert.equal(resolveDesktopUiUrl({ ...options, startUrl: '' }), 'http://localhost:3000');
+ assert.equal(resolveDesktopUiUrl({ ...options, startUrl: '', isPackaged: true }), options.backendUrl);
+});
diff --git a/docs/agent-progress-real-2026-09-13.md b/docs/agent-progress-real-2026-09-13.md
new file mode 100644
index 00000000..f2216eb3
--- /dev/null
+++ b/docs/agent-progress-real-2026-09-13.md
@@ -0,0 +1,51 @@
+# 阶段回复真实模型验证
+
+用户实际运行中,工具步骤可见,但没有自然语言阶段回复。只读检查该任务的模型检查点,连续五轮 `AIMessage.content` 均为空,只含工具调用;原有界面没有收到可以显示的公开正文。截图中的模型调用数为零,是运行快照用量未汇总导致的显示滞后。
+
+早期版本在工具定义中加入 `progress_message`,首次或发生显著进展时要求非空,之后先改成可选。用户进一步要求使用官方消息流,当前已彻底移除该工具参数,改用 `astream_events(version="v3")` 和模型正常回复正文。以下两段阶段回复的历史记录来自旧实现,不能作为当前模型一定会主动汇报的证明。界面使用实时调用计数,尚未汇总的 Token 用量显示为待汇总。
+
+早期实现使用本机配置的 `deepseek-flash`、真实 DeepAgents 图、隔离任务库及一条虚构聊天进行验证,没有调用真实聊天数据库,也没有为阶段回复额外请求模型。当时的实测结果:
+
+- 8.7 秒完成,3 次模型调用,正常进入 `completed`。
+- 两段公开回复按 `progress → 确定范围 → progress → 读取消息` 保存。
+- 回复原文:“先锁定当前聊天 test-friend 最近 7 天的范围,然后读取消息内容归纳重点。”以及“读取该范围内的消息原文。”
+- 最终回答保留聊天引用,完成时此前的两段进展仍在时间线中。
+
+本地实测记录:`tmp/progress-live-1789288886630019700/result.json`。测试密钥只在内存中使用,结果文件不保存密钥。本次实测验证该模型可以通过结构化工具参数返回公开进展,不保证模型每一轮都产生新的阶段文字,也不会为正在使用旧后端的历史任务补造进展。
+
+回归结果:DeepAgents、执行契约、MiMo 回归及可靠性测试共 115 项通过;阶段时间线与聊天面板测试共 54 项通过。新增字段计入上下文压缩预算,并缩小压缩后保留的历史尾部,为工具定义及摘要留出空间。
+
+## 官方消息流版本
+
+当前使用官方 `astream_events(version="v3")`,直接接收模型正文的 `text-delta`,工具参数不再包含 `progress_message`。提示词仅建议在有实质成果时汇报;没有阶段回复不会重试或增加模型调用。
+
+新版实测记录为 `tmp/progress-live-1789291054034153300/result.json`:同一模型在约 8.7 秒内以 3 次调用正常完成。本次没有主动产生阶段回复;界面没有补造文字。最终回答时间线的 revision 为 5,确认正文增量已通过新版流式通道保存。
+
+确定性模型配合真实执行图覆盖有阶段正文、无阶段正文、连续多个工具后汇报及 JSON 兼容模式。子任务与内部摘要的文字不会混入主任务最终回答。
+
+新版回归:DeepAgents、可靠性和执行契约共 96 项通过(合并运行 95 项通过;分页测试适配压缩后的当前状态后,单独复跑通过)。
+
+## 加强长任务沟通要求
+
+用户反馈长任务仍然全程静默后,将“建议、可以不汇报”调整为明确的长任务沟通要求,集中放在系统提示词末尾。首次取得有用资料且仍需继续分析时分享收获,后续在关键发现、判断变化或阻碍出现时再次汇报;无需开场预告,不逐次播报工具。简单任务和即将完成的回答仍可直接结束,运行时不检查阶段回复数量,不补造内容、不因此重试。
+
+参考官方 Codex 指导中的 [Mid-Rollout User Updates](https://developers.openai.com/api/docs/guides/latest-model?model=gpt-5.3-codex) 以及 OpenAI [Agentic steerability & user updates](https://developers.openai.com/api/docs/guides/latest-model?model=gpt-5.2):通过提示词引导中间回复,内容集中于重要阶段变化和具体成果。这里沿用 DeepAgents 正常消息流,没有添加 OpenAI 专用参数或切换模型。
+
+最终提示词实测使用 `deepseek-flash`、隔离数据库、3 页共 6 条虚构聊天,问题只要求完整梳理事项及变化,没有额外要求模型汇报。记录:`tmp/progress-milestone-1789292608102823100/result.json`。
+
+- 24.3 秒、8 次模型调用,正常完成;没有开场预告。
+- 约第 10 秒出现首次阶段正文,描述已读到的旅行预算及分工。
+- 约第 15 秒再次汇报,指出会议时间、预算发生变更,路线仍未定。
+- 两段汇报通过标准正文保存,最终答案独立显示。相同虚构任务在第一版较弱措辞下也是 8 次调用,但没有阶段正文。
+
+这是当前模型的一次成功实测,不代表每次运行都能保证相同频率。
+
+## 2026-09-14:新版规划过滤了主任务沟通要求
+
+用户反馈阶段回复再次消失。只读核对截图对应运行 `3cb4010d181d4ac8b9a3c3c8189f1037`:耗时 362.8 秒、14 项工具操作,`subtask_plan_version=2`,时间线只有工具、压缩通知及答案,没有 `progress` 记录。最近另外两次新版任务同样没有阶段回复,较早任务仍保存着阶段回复。
+
+原因位于 `DeepAgentRuntime.graph()`:新版规划精简 `SYSTEM` 时同时过滤了“阶段汇报是长任务”“首次拿到有用资料”“阶段汇报写在”等行。原常量仍有要求,但真正传入执行图的提示词已失去这些要求。前端阶段文字渲染和后端保存逻辑仍在。
+
+修复保留主任务的完整沟通要求,子任务继续使用独立的 `CHILD_SYSTEM`。没有添加额外模型调用、强制汇报重试或历史补写。已有原生和 JSON 兼容模式图测试新增实际模型请求的提示词检查,修复前两种模式均能复现缺失。验证使用确定性模型,不把脚本产生的阶段文字当作真实模型主动汇报的证明。运行中的旧后端需重启加载代码,已经完成的历史任务不会自动出现新文字。
+
+验证结果:后端图与新版规划共 47 项、前端时间线 26 项通过。后端首次运行 46 项通过,另一个并行测试的模拟流把压缩摘要误当主线响应,提前消耗了汇总工具步骤;该测试补上独立摘要响应后单独复跑通过。实际运行逻辑未为此修改。前端使用随环境提供的新版 Node,系统旧 Node 缺少 `crypto.hash`,无法加载 Vite Vue 插件。
diff --git a/docs/agent-subtask-progress-2026-09-13.md b/docs/agent-subtask-progress-2026-09-13.md
new file mode 100644
index 00000000..a7eec485
--- /dev/null
+++ b/docs/agent-subtask-progress-2026-09-13.md
@@ -0,0 +1,11 @@
+# 子任务进度与重复分析修正
+
+截图所示任务的只读记录表明:子任务已经产生公开阶段回复,但子任务列表接口未返回这些内容。动作和覆盖数据藏在第二层折叠中,主任务还同时显示工具行、子任务行和泛化等待提示。两次发现提交包含当前页以外的来源,触发完整批次重试;随后的模型请求分别约 190 秒、195 秒。读取本身并非主要等待原因。
+
+调整后的子任务在时间线的实际委派位置出现。运行中默认展开,每个子任务直接显示当前动作、动作耗时、最近公开回复、已读和已分析数量;最近八项记录、任务目标和用量按需展开。模型请求仍在进行时明确标注等待本轮结果,并显示距上次公开进展的时间。只返回公开回复和工具动作,不展示内部推理。父任务结束时立即补取最终快照,随后停止轮询。
+
+发现提交错误现在一次列出各个错误位置和无效来源,保留页面待处理状态且不写入部分结果,要求修正后一次性提交整页发现,避免用单条试提交提前完成一页。普通单聊概览的工具指引改为由主任务直接整理,避免重复委派整个已读范围;独立分析能力保留。
+
+验证:96 项后端测试、29 项前端测试通过。浏览器查看大视图与 360px 侧栏的浅色/深色示例,正文无横向溢出,阶段文字无需额外展开即可看到。项目在 16:53 重启后,通过实际接口读取原子任务:返回 8 项公开记录、最近回复及真实的已读 350 条/已分析 350 条。原任务已暂停,本次没有重新运行该完整聊天分析,因此不宣称其总耗时已缩短到某个数值。
+
+示例入口:`http://127.0.0.1:3050/tests/fixtures/agent-progress.html?subtasks`,使用明确标注的虚构数据。
diff --git a/docs/ai-agent-compaction-evidence-2026-09-14.json b/docs/ai-agent-compaction-evidence-2026-09-14.json
new file mode 100644
index 00000000..da206a72
--- /dev/null
+++ b/docs/ai-agent-compaction-evidence-2026-09-14.json
@@ -0,0 +1,188 @@
+{
+ "captured_local": "2026-09-14T11:24:34.320332",
+ "scope": "AI 助手现行执行链与指定失败任务;不含密钥和聊天正文",
+ "runtime_dependencies": {
+ "deepagents": "0.7.13",
+ "langchain": "1.4.0",
+ "langchain-core": "1.6.2",
+ "langgraph": "1.2.11",
+ "langgraph-checkpoint-sqlite": "3.1.1"
+ },
+ "run": {
+ "id": "8fbda9940a8f4587b3380a36262a4c10",
+ "engine_version": 3,
+ "status": "failed",
+ "error": "上下文摘要整理失败:摘要仍过长(13010 字节,上限 8192 字节);已尝试 3 次,原文和原检查点已保留。",
+ "version": 1,
+ "read_count": 2146,
+ "used": {
+ "tools": 20,
+ "models": 28,
+ "media": 0
+ },
+ "cutoff": 1789354431
+ },
+ "context_budget": {
+ "used": 21815,
+ "input_capacity": 615488,
+ "model_window": 1000000,
+ "output_reserve": 384000,
+ "safety_reserve": 512,
+ "percent": 3.5,
+ "measurement": "conservative_estimate",
+ "unit": "budget_units",
+ "conservative_units": 21815
+ },
+ "coverage": [
+ {
+ "read": 2000,
+ "analyzed": 0,
+ "read_complete": false,
+ "complete": false,
+ "warning": ""
+ }
+ ],
+ "scopes": [
+ {
+ "start": 0,
+ "end": 1789354431,
+ "mode": "search",
+ "complete_required": false,
+ "message_count": null,
+ "read_complete": false,
+ "pages": 12,
+ "committed_pages": 12,
+ "pending_page": ""
+ }
+ ],
+ "saved_piece_kinds": {
+ "deep_directory": 1,
+ "deep_file": 1,
+ "deep_live_cursor": 8,
+ "deep_page": 12,
+ "deep_scope": 1,
+ "read_cursor": 12,
+ "timeline": 35
+ },
+ "post_restart_summary_calls": [
+ {
+ "id": "fe4f44b59fd54ec3b7cd55e55bdb8ccc",
+ "purpose": "deepagents_summary",
+ "status": "success",
+ "model": "deepseek-flash",
+ "usage": {
+ "input_tokens": 25075,
+ "output_tokens": 3322,
+ "total_tokens": 28397,
+ "input_token_details": {
+ "cache_read": 0
+ },
+ "output_token_details": {}
+ },
+ "finish_reason": "stop",
+ "duration_ms": 53520,
+ "truncated": null,
+ "started_local": "2026-09-14T11:06:56.995796"
+ },
+ {
+ "id": "fe9c094f2b794a3f9122240fe5be746d",
+ "purpose": "deepagents_summary",
+ "status": "success",
+ "model": "deepseek-flash",
+ "usage": {
+ "input_tokens": 3443,
+ "output_tokens": 2471,
+ "total_tokens": 5914,
+ "input_token_details": {
+ "cache_read": 0
+ },
+ "output_token_details": {}
+ },
+ "finish_reason": "stop",
+ "duration_ms": 40339,
+ "truncated": null,
+ "started_local": "2026-09-14T11:07:50.624364"
+ },
+ {
+ "id": "26b6e3d913744a058352415fd6fe296f",
+ "purpose": "deepagents_summary",
+ "status": "success",
+ "model": "deepseek-flash",
+ "usage": {
+ "input_tokens": 25186,
+ "output_tokens": 5156,
+ "total_tokens": 30342,
+ "input_token_details": {
+ "cache_read": 0
+ },
+ "output_token_details": {}
+ },
+ "finish_reason": "stop",
+ "duration_ms": 78946,
+ "truncated": null,
+ "started_local": "2026-09-14T11:08:31.084826"
+ },
+ {
+ "id": "235bca25e320459bb6df8dd745caf6d5",
+ "purpose": "deepagents_summary",
+ "status": "success",
+ "model": "deepseek-flash",
+ "usage": {
+ "input_tokens": 7748,
+ "output_tokens": 4868,
+ "total_tokens": 12616,
+ "input_token_details": {
+ "cache_read": 0
+ },
+ "output_token_details": {}
+ },
+ "finish_reason": "stop",
+ "duration_ms": 82776,
+ "truncated": null,
+ "started_local": "2026-09-14T11:09:50.124173"
+ },
+ {
+ "id": "9d11f458ccc141edb6962d479b40af05",
+ "purpose": "deepagents_summary",
+ "status": "success",
+ "model": "deepseek-flash",
+ "usage": {
+ "input_tokens": 7459,
+ "output_tokens": 4868,
+ "total_tokens": 12327,
+ "input_token_details": {
+ "cache_read": 0
+ },
+ "output_token_details": {}
+ },
+ "finish_reason": "stop",
+ "duration_ms": 83843,
+ "truncated": null,
+ "started_local": "2026-09-14T11:11:13.006333"
+ }
+ ],
+ "totals": {
+ "calls": 5,
+ "input_tokens": 68911,
+ "output_tokens": 20685,
+ "duration_ms": 339424
+ },
+ "source_sha256": {
+ "src/wechat_decrypt_tool/ai/deep_runtime.py": "d432e4262c15faa7b3cda1a1062ecef77ab9d95aff9988dcb3f4b5666c0383ad",
+ "src/wechat_decrypt_tool/ai/deep_context.py": "68a72967e3a1ba5df2e57a7a213299de609cc308e4a7aea78ef515d0ee36f942",
+ "src/wechat_decrypt_tool/ai/deep_model.py": "9398a18fc5d58694287f085e19dc1669adac37bfbf6b8023303276039e202c5a",
+ "src/wechat_decrypt_tool/ai/deep_tools.py": "251a08c24dc38b8dc78c0f7ff3ebe8f6dec58bf022092bfbbf367c2b633f0607",
+ "src/wechat_decrypt_tool/ai/agent_budget.py": "28dfd7e70181314aa711f3dd1669920e238a583a420f66301637260379b9e91b",
+ "src/wechat_decrypt_tool/ai/context_meter.py": "1c6aef0de99142d740506f3480fb22c1b3a616bd255ca9879d9bc962815e1d69",
+ "src/wechat_decrypt_tool/ai/compaction_policy.py": "40c47947ad51980df246c3d7a1e62b3ead16c95ee1b7f32d0f5be5d54b7262e9",
+ "src/wechat_decrypt_tool/ai/deep_projection.py": "9fe5730554024d550dfd026d5e3da968de4a738263bed0cfcb1be286b4e032b5",
+ "src/wechat_decrypt_tool/ai/agent_service.py": "475efd1b3fd9038ca767f2a7bd8a8a3f836361e575a98d417d0e494a642c1439",
+ "src/wechat_decrypt_tool/ai/agent_workspace.py": "b8b22c19f92353a0d9fbac1a81b07c90962c4f1d802872187be357c5454da383",
+ "src/wechat_decrypt_tool/ai/deep_backend.py": "3c7ee3dcfa1f665a9d3edf20e7a13c9bca0898f564e2e11b654e98b4ae8612e0",
+ "src/wechat_decrypt_tool/ai/deep_checkpoints.py": "c764a9bc3d4797d6162059afbefba202974901f94608e963e5fd1a366dc957f7",
+ "frontend/components/chat/AgentRun.vue": "6654eef4c90eed2a0a8cd683d1e24abb60cd6beb2946d1a596518b8aa9540087",
+ "frontend/components/chat/ChatAgentPanel.vue": "791ebf358a6e040362a3f543791db96e9996d5d1bc428a9fb02cd058c8b0724f"
+ },
+ "current_scope_saved_original_count_verified": 2146,
+ "coverage_snapshot_note": "搜索登记更新总读取数但未刷新 coverage;持久化 read=2000,当前范围原文实际2146。"
+}
diff --git a/docs/ai-agent-current-logic-2026-09-14.md b/docs/ai-agent-current-logic-2026-09-14.md
new file mode 100644
index 00000000..05999663
--- /dev/null
+++ b/docs/ai-agent-current-logic-2026-09-14.md
@@ -0,0 +1,376 @@
+# AI 助手现行逻辑与重做依据
+
+> 这是修复前的历史审计。后续已实施的改动和验证见 [上下文恢复修复记录](ai-context-recovery-2026-09-14.md)。
+
+核查日期:2026-09-14。范围:桌面 AI 助手的提问、查询、模型循环、上下文压缩、状态保存、恢复和结果展示;不展开微信解密、语音识别、向量索引算法本身。
+
+本文描述核查时的工作区源码,以及本次失败的持久化记录。工作区有其他未提交改动,不能把当前源码等同于某个发布版本。此次只整理文档,没有继续修改运行逻辑或重新调用真实模型。
+
+## 1. 结论先行
+
+**问题集中在上下文管理的职责与失败边界,而不只是模型没按字数要求输出。** 当前实现把一次业务分析中积累的用户要求、模型过程、工具参数、聊天原文、工具结果等一起压成一段累计摘要,并把“摘要通过固定字节校验”设为下一次主模型调用的前提。连续失败就终止整个任务。
+
+本次搜索工具已经执行成功。重启后的缩写补丁也确实执行了,但依然撞上同一个业务终止条件。把失败称为“原文和检查点已保留”只说明数据还在,不能说明压缩过程能从失败分段继续,也不能说明用户能拿到已有分析成果。
+
+需要拆开的概念有五个:**原文资料、任务状态、分析发现、模型上下文、最终回答**。现在它们已经分别有一些存储结构,但执行时仍过度依赖一条不断增长的模型消息历史,以及压缩这条历史的单段摘要。
+
+## 2. 本次失败的确切记录
+
+任务 ID:`8fbda9940a8f4587b3380a36262a4c10`。同一个任务重试,版本仍为 `1`。
+
+| 项目 | 已核实的状态 | 含义 |
+|---|---|---|
+| 当前引擎 | DeepAgents,engine_version=3 | 使用当前主执行入口 |
+| 查询方式 | search,complete_required=false | 普通问答,不是强制逐页提交的完整报告 |
+| 时间范围 | 从 0 到原任务创建时的 cutoff | 全历史范围;重试不自动更新截止时间 |
+| 原文库计数 | 2146 条 | 任务已保存的去重来源数 |
+| 当前范围覆盖计数 | read=2000,analyzed=0 | 覆盖快照未随后续搜索刷新;直接查询该范围原文实际也是 2146 条 |
+| 已读分页 | 12 页,committed_pages=12 | 普通读取页会自动推进,不表示提交了分析笔记 |
+| 分析笔记 / findings | stage_note=0,finding=0 | 普通路径没有形成结构化分析发现 |
+| 业务工具调用 | 20 次 | 重启后的这次重试没有新增业务工具调用 |
+| 模型调用 | 23 增至 28 次 | 新增 5 次全部用于摘要 |
+| 最终错误 | 摘要 13010 字节,上限 8192 字节,已尝试 3 次 | 程序主动拒绝摘要并结束任务 |
+
+重启后的摘要调用,来自 `usage` 审计,而非猜测:
+
+| 开始时间(本地) | 输入 Token | 输出 Token | 耗时 | 上游结束原因 |
+|---|---:|---:|---:|---|
+| 11:06:56 | 25075 | 3322 | 53.5 秒 | stop |
+| 11:07:50 | 3443 | 2471 | 40.3 秒 | stop |
+| 11:08:31 | 25186 | 5156 | 78.9 秒 | stop |
+| 11:09:50 | 7748 | 4868 | 82.8 秒 | stop |
+| 11:11:13 | 7459 | 4868 | 83.8 秒 | stop |
+
+合计输入 **68911 Token**、输出 **20685 Token**,模型调用耗时约 **339.4 秒**。五次上游请求都正常结束;`usage.status=success` 不表示摘要通过业务校验。
+
+结合源码调用顺序,记录对应:第一段生成过长 → 缩写通过 → 下一段生成过长 → 缩写两次仍不通过 → 失败。这里的“三次”指最后失败分段的尝试次数,不是整次压缩只请求了三次。
+
+最新上下文圈显示约 **3.5%**,对应最后一个缩写请求的 21815 个保守预算单位,不代表主 Agent 的全部待压缩历史只占 3.5%。
+
+数据库还保存着之前成功提交的压缩事件(cutoff_index=15)和一个约 1.23 MB 的历史归档文件。这证明资料及早先检查点存在,**不能证明本轮分段压缩进度已保存**。
+
+审计没有保存这五次调用的完整摘要正文、每次字节数及显式分段编号,因此不能逐字比较两次 4868 Token 的输出,也不能把 Token 数直接换算成字节数。本文不作这些推断。
+
+结构化证据及源码指纹见 [核查快照](D:/workProject/WeChatDataAnalysis/docs/ai-agent-compaction-evidence-2026-09-14.json)。不包含 API 密钥或聊天正文。
+
+## 3. 现在的主链路
+
+```mermaid
+flowchart TD
+ A[用户提问或补充要求] --> B[AgentService.submit 创建或更新运行版本]
+ B --> C[读取图检查点或组装初始消息]
+ C --> D[准备工具列表与程序状态]
+ D --> E{上下文需要整理吗}
+ E -->|否| F[DeepChatModel 调用模型]
+ E -->|是| G[历史归档与分段累计摘要]
+ G --> H{摘要通过校验吗}
+ H -->|是| F
+ H -->|三次仍失败| X[任务 failed]
+ F --> I{模型返回什么}
+ I -->|工具调用| J[范围 查询 原文 笔记 媒体 子任务]
+ J --> K[保存资料并把工具结果加入图消息]
+ K --> D
+ I -->|回答| L[检查读取要求与范围覆盖]
+ L -->|需要继续| D
+ L -->|可交付| M[保存回答并完成]
+ X --> N[用户点击重试这一步]
+ N --> C
+```
+
+该图表示逻辑关系,不是完整的框架中间件嵌套顺序。还有单独的上游超限回退、文件外置和模型协议重试,见后文。
+
+生产入口是 [AgentService](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/agent_service.py:33),继承 `DeepAgentRuntime + DeepProjection + AgentTimeline`。它没有继承旧的自定义 Agent 主循环。
+
+## 4. 提问、补充、继续与重新运行
+
+| 操作 | 现行行为 | 后续重做要注意 |
+|---|---|---|
+| 新提问 | 保存用户消息、创建 run,快照化模型配置和 cutoff,后台启动图 | 同一 request_id 幂等;不是每次点击都创建独立运行 |
+| 运行中补充要求 | 同一 run 的 version 加一,取消旧 worker;清空当前回答、范围等,合并 input_digest | 新版本使用新图检查点,避免沿用旧筛选条件下的工具消息 |
+| 已结束后追问 | 创建新 run,记录 previous_run_id | 历史回答、少量已验证发现和内部笔记可进入新轮 |
+| 重试这一步 / 继续查找 | `/continue` → resume,同一 run、version、图检查点重新执行 | 不是精确重试最后一个 UI 工具;也不是压缩分段断点续传 |
+| 重新运行历史问题 | restart → submit,创建新 run,继承问题、模型选择和相关查询条件 | 与 resume 不同;旧引擎任务需要走这条路径 |
+| 停止 | 标记取消,取消 worker | 原文和已提交资料保留 |
+| 应用启动恢复 | 把仍为 queued/running 的遗留运行转为可恢复的中断状态 | 启动应用本身不等于自动重跑全部任务 |
+
+`execute()` 通过检查点的待执行节点决定传入新消息还是以 `inputs=None` 恢复。补充要求走新版本;普通重试维持旧版本。因此业务状态、原文和图检查点之间的版本对应关系是重做时必须保留的约束。
+
+入口:[deep_runtime.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_runtime.py:355)、[HTTP 路由](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/routers/ai_agent.py)、[前端按钮](D:/workProject/WeChatDataAnalysis/frontend/components/chat/ChatAgentPanel.vue:309)。
+
+## 5. 范围和业务工具
+
+### 5.1 范围如何决定
+
+模型先调用 `select_chat_scope`。程序校验账号、联系人、时间、发言人、最近消息条数等,保存范围句柄。当前聊天由前端传入;无时间要求时允许全历史。系统提示要求模糊“最近”默认近七天并说明,但这仍有模型理解和工具参数选择参与。
+
+`complete=true` 或正则识别到“完整报告、全面分析、全部提取”等明确要求时,进入强制完整覆盖路径。普通“有哪些事还没确认”没有被自动视为完整报告。本次实际选的是全历史普通搜索范围。
+
+现有范围结构包括:会话列表、start/end、sender、message_count、complete_required、mode、cursor、conversation_index、pending_page、pages、committed_pages、warnings。
+
+### 5.2 工具职责表
+
+| 工具 | 实际职责 | 是否形成已分析覆盖 |
+|---|---|---|
+| select_chat_scope | 解析并保存范围,返回真实 scope_handle;触发后台索引准备 | 否 |
+| search_messages | 每次查一个会话的索引搜索;底层请求 hybrid,每页 50 条;保存命中原文 | 否;命中不等于完整覆盖 |
+| search_live_messages | 根据索引末尾时间确定实时缺口,逐页读取后做关键词匹配 | 否;扫描和命中不同 |
+| read_messages | 按时间和容量读取下一页;每页容量最大 48 KiB,或输入预算的三分之一 | 普通页自动推进;完整分析页必须先提交 |
+| commit_findings | 对当前 pending_page 提交事实和来源;空列表也可提交;落库 stage_note | 是,以来源的完整字符区间覆盖统计 |
+| read_context | 读取已知来源前后文并限制在当前范围;定位失败时可返回已保存原文及缺口 | 否 |
+| count_messages | 程序遍历并统计,不由模型估算数量 | 只完成统计,不代表内容分析完成 |
+| read_results | 分页读取本轮已保存 finding,每页 20 项 | 读取已有结果 |
+| search_material | 回查本轮或同一 AI 对话旧轮的已保存原文 | 否;返回来源重新登记 |
+| read_material | 按字符位置续读长消息,每次最多 4000 字符 | 否 |
+| analyze_media | 根据本轮模型能力解释图片或提取附件文字;独立保存派生结果 | 不等于范围全文分析 |
+| task | 创建隔离的范围分析 / 事实核查子任务,合并其原文和发现 | 范围分析成功后可完成对应范围 |
+| ls / grep / read_file | 查询任务虚拟文件,包括历史、笔记和资料 | 否 |
+| write_file / edit_file | 模型只可写任务内部 notes/plans/drafts | 写普通笔记不自动计为 stage_note 覆盖 |
+| write_todos | 框架内任务计划 | 不是证据或分页提交 |
+
+实时搜索底层每页最多 200 条、批次字节上限 1 MiB;网关单次最多循环 8 页,找到命中或耗时超过约 1 秒即返回。这与普通读取的 48 KiB 容量不是同一个限制。工具输出后还可能被框架外置。
+
+### 5.3 已有防循环机制及其局限
+
+`RuntimeEvents` 会按真实状态动态隐藏工具:没选范围时主要允许选范围;完整分析待完成时限制搜索;有 pending_page 时优先提交;连续三次搜索无新增且无下一页时引导读取。
+
+同一参数、同一结果、同一进度重复两次会加提示,四次会失败。进度增加会重置这项计数。因此**“不断拿到少量新资料、但迟迟不收尾”的搜索扩张不一定被拦住**。主图递归上限为 100000,也没有普通问答的固定总调用额度作为实际收尾机制。
+
+这解释了为什么普通问题仍可能读取数千条历史。源码中的“证据足够即答”主要是提示约束,尚不是明确的、可观察的停止策略。
+
+来源:[工具与范围](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_tools.py)、[底层读取与搜索](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/agent_tools.py)、[运行约束](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_runtime.py:76)。
+
+## 6. 原文已落库,为什么上下文还会变大
+
+`save_messages()` 同时做两件事:把完整原文按来源去重保存,以及生成给模型看的工具 payload。payload 包含文字、时间、发言人、来源编号、内部路径和可选引用 / 续读字段。
+
+**数据库去重不等于模型历史去重。** 新的搜索、前后文回查、分页结果仍会作为 ToolMessage 加入图。已保存原文再次返回时,模型历史里仍可能多一份相同或重叠内容。当前没有一个统一的“只向模型追加尚未见过的最小证据包”的构建器。
+
+模型当前请求可能同时包含:
+
+1. 系统提示、业务规则,以及本轮可用工具 Schema。
+2. 用户要求和上一轮的近期消息。
+3. 程序注入的真实范围、待提交页、来源样例等恢复状态。
+4. 模型的过程文字、工具调用及工具返回。
+5. 先前压缩得到的摘要和归档路径。
+6. 正文续写、覆盖未完成、工具参数错误等自动反馈。
+
+新一轮初始历史按 `B/4` 字节容量从近到远选取;更旧内容完整写入 `/history/previous.json`。上一轮最多取 20 条已验证 finding,及最多 20 份符合约束的内部笔记作为可回查历史。这条历史继承路径与运行中压缩是两套处理。
+
+## 7. 预算不是一套统一口径
+
+设 `W` 为模型配置窗口,`O` 为程序按模型元数据计算的输出预留,`B=input_limit(profile)`。
+
+| 位置 | 现行计算 | 关键差异 |
+|---|---|---|
+| 模型输入容量 B | 配置预算、W−O−512、上游 input 上限中的约束值 | 元数据以 Token 窗口描述 |
+| request_size / context_tokens | UTF-8 字节、消息封装、工具 Schema 等保守估计;图片有独立估值 | 返回值不是供应商实际 Token |
+| 主请求检查 | ContextMeter 可用历史真实 usage 校准相同请求前缀 | 与纯字节估计不同 |
+| 自动压缩触发 | `max(1024, floor(B×0.8))`,使用 context_tokens;框架也可参考匹配供应商的 reported usage | 不调用 ContextMeter 的校准结果来决定触发 |
+| 压缩保留尾部 | `max(256, floor(B×0.1))` | 按 token_counter 切分且维护工具调用配对,不是保留最近固定轮数 |
+| 摘要输入预算 S | `min(65536, max(512, floor(B×0.55)))` | 65536 是本次补丁加入的请求保守上限 |
+| 单段累计摘要目标 T | `min(8192, max(128, floor(S/5)))` | 严格 UTF-8 字节上限,不随资料复杂度增长 |
+| 主模型 / 摘要实际输出参数 | 一般 `max_tokens=min(output_limit,8192)` | 8192 Token 与摘要 8192 字节不是一个东西 |
+| 超大工具结果外置 | 参数 `max(512,min(24000,B/8))`,框架内部另用字符近似等策略 | 不是统一的 UTF-8 请求计量 |
+| 前端上下文圈 | 最近一次 publish_context 的 used / B | 摘要调用也更新它,会把主 Agent 的显示覆盖成摘要请求占用 |
+
+本次配置数值:W=1000000,O=384000,B=615488,压缩触发约 492390,保留尾部约 61548,S=65536,T=8192。这里的 W/O 是**本地配置快照**,本文没有核实供应商真实能力。
+
+另一个不一致是:输入预算预留了 384000 的输出空间,但普通实际请求最多只发 8192 的输出参数。这不证明压缩一定触发过早,但说明容量计算和实际请求参数没有统一。
+
+因此,“界面才 3.5% / 22.8%,为什么在压缩”不能只用圈上的数字回答。它可能显示的是另一个内部请求,且触发计量与显示计量不同。现有审计也没有逐次记录压缩是因估计阈值、框架回退还是上游超限触发,不能事后凭圈值断言。
+
+来源:[预算计算](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/agent_budget.py)、[计量校准](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/context_meter.py)、[图配置](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_runtime.py:477)、[模型请求](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_model.py)。
+
+## 8. 压缩算法逐步拆解
+
+### 8.1 框架外层
+
+使用 DeepAgents 0.7.13 的 SummarizationMiddleware,并由 `DurableSummarization` 覆写关键步骤。同名替换用于避免注册两个摘要调度器。
+
+1. 根据之前已提交的 `_summarization_event` 组装有效历史。
+2. 把系统说明、当前工具定义和消息计入触发估计;框架还可能先处理超大的旧工具参数。
+3. 未达触发条件时先调用主模型;若发生 ContextOverflowError,框架也会回退到摘要。
+4. 找切分点,保留近期尾部。应用额外处理单条超长用户输入和已配对的大工具批次。
+5. 处理媒体外置,然后**并发**进行历史归档和 `_acreate_summary()`。
+6. 摘要成功后,用“累计摘要 + 历史文件路径 + 保留尾部”调用主模型。
+7. 主模型调用返回后,把新的摘要事件随 Command 提交到图状态。
+
+注意:当前异步实现是归档与摘要并发,不是“归档成功后才开始花费模型调用”。应用会验证归档,阻止未归档时继续主模型,但摘要调用可能已经开始。主模型在压缩完成后若又失败,本轮新摘要事件也未必提交。
+
+### 8.2 应用的分段累计摘要
+
+输入并非纯聊天文字,而是 `message_to_dict()` 后序列化的完整消息结构。角色、工具调用参数、结果及消息附加字段都会进入历史字符串。
+
+```text
+previous = 空字符串
+offset = 0
+S = 本次摘要请求预算
+T = 单段累计摘要字节上限
+
+while 还有未处理历史:
+ 扣掉提示词、previous、请求封装,计算本段 available
+ 按 UTF-8 边界取 fragment
+ draft = 空字符串
+
+ 最多尝试 3 次:
+ 有完整超长 draft → 请求缩写 draft,并带 previous
+ 否则 → 请求合并 previous 与 fragment
+
+ 上游上下文超限 → S 减半、缩小 T,重新处理当前位置
+ 合法且字节数 <= T → 更新 previous,推进 offset
+ 完整但过长且修复请求放得下 → 下次缩写 draft
+ 空、占位文本、被截断或 draft 太大 → 缩小原文 fragment 再试
+
+ 三次均不通过 → 抛 ProviderFailure,整轮摘要失败
+
+return previous
+```
+
+合法性检查只涵盖非空、非已知失败占位、未标记输出截断、字节数达标。**没有检查关键待办、来源或分页位置是否在连续压缩中被遗漏。** 提示词要求保留这些信息,不等于程序保证保留。
+
+当前的缩写修复只在提示词里报告实际字节数、给更小的汉字建议;并没有一个能保证收敛的长度控制器。被模型正常结束但仍有 13010 字节的结果会再次被拒绝。直接截断字符串虽能凑够字节数,却可能切掉待办、来源和否定条件,也不应作为默认答案。
+
+### 8.3 有三层不同重试
+
+| 层级 | 行为 | 是否保存该层进度 |
+|---|---|---|
+| DeepChatModel | 最多 3 次网络 / 协议尝试;单次 240 秒,总期限 600 秒;已暴露输出后限制重试 | 保存调用审计;不是业务检查点 |
+| 单段摘要 | 最多 3 次生成 / 缩写 | previous、offset、draft、attempt 都是函数局部变量 |
+| 主请求超限恢复 | 框架自动回退之外,应用默认还允许 2 次超限恢复,缩小保留量和摘要预算 | 只在图成功提交时保留最终事件 |
+
+所以“尝试 3 次”不是全任务模型调用上限,也不是压缩工作的总耗时上限。一次大历史分多段,再叠加每段修复,调用数会继续增加。
+
+### 8.4 压缩失败为什么阻断业务
+
+`ProviderFailure` 从摘要函数冒泡到 `DeepAgentRuntime.execute()` 的通用异常分支,写入 `status=failed`,错误类别统一为 deepagents / execution。
+
+这里没有压缩专用的可恢复状态,没有把“模型仍能接受的较长摘要”作为动态候选,也没有改用已存结构化成果构造下一轮上下文的路径。**固定 8192 字节目标被当成硬性业务完成门槛。**
+
+这一段对应 [deep_context.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_context.py:100) 和 [失败出口](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_runtime.py:662)。
+
+## 9. 已经持久化什么,没持久化什么
+
+| 存储 | 内容 | 故障后的实际价值 |
+|---|---|---|
+| ai.sqlite3 / records | agent_thread、agent_run、模型配置、usage 审计等 | 能找到任务、状态、问题、费用和时间线 |
+| agent_material | 去重原文来源,按 run 保存 | 可回查原文;不等于模型自动知道怎样继续 |
+| agent_piece / deep_scope、deep_page、read_cursor | 范围、页、游标、pending 状态 | 支持读取与提交的幂等恢复 |
+| agent_piece / finding、stage_note | 事实、来源与已分析字符覆盖 | 支持明确的内容分析进度;本次没有生成 |
+| agent_piece / deep_file | 虚拟文件:历史归档、笔记、计划、子任务结果等 | 路径指向 SQLite 内容,不是宿主磁盘文件 |
+| agent_subtask | 子任务状态及父子关联 | 子任务结果查询、合并和版本校验 |
+| deepagents_checkpoints.sqlite3 | LangGraph 状态、写入、已提交摘要事件 | 恢复图节点,不能恢复某个 Python 函数内部的局部变量 |
+| 仅存在内存 | 当前摘要分段 offset、累计摘要 previous、候选 draft、尝试次数 | 本轮摘要失败后不能直接从这些位置继续 |
+
+特别要区分:分页的 `pending_page` 有数据库记录,摘要的“第几段做到哪”没有类似记录。二者虽然都叫恢复,能力并不相同。
+
+历史归档与检查点不是同一个事务;框架会追加归档。失败后再次整理相同未提交历史存在重复追加的路径,需在重做时验证并使其幂等。当前 1.23 MB 的归档大小本身不证明其中每段都是重复内容。
+
+## 10. 分析计数、最终回答与前端状态
+
+“已读取”主计数取原文库去重数量。“已分析”取 stage_note 连续覆盖完整原文字符区间的数量。普通问答页无需 commit_findings,读完只增加 committed_pages,因此会出现已经读了很多、模型也写了过程文字,但 analyzed 仍为 0。
+
+这是统计字段含义与普通问答 UI 文案不匹配。**不能通过让 read_count 直接等于 analyzed 来修饰这个数字**,否则会把阅读、处理、结构化提交混为一谈。
+
+另有一个独立的刷新问题:`save_messages()` 更新总 read_count,搜索路径没有同时调用 coverage();read_next / commit 等路径才刷新覆盖记录。本次数据库中当前范围原文实际为 2146 条,持久化 analysis.coverage.read 却停在 2000 条。因此界面的两种读取进度还可能是不同时间的快照,不能仅解释成筛选范围不同。
+
+当前回答流程:
+
+- 工具调用附带的文字保存为 progress;确认是工具轮后清空临时 answer。
+- 主模型正文流按约 80ms 节奏更新 answer 和时间线。
+- 摘要及其他内部模型流被过滤,不进入对话正文。
+- aafter_model 检查是否实际读取过资料、完整范围是否完成,必要时再请求模型继续;正文被截断可最多续写 8 次。
+- execute 收尾时再次检查范围与数据源缺口,普通问答可给带缺口说明的阶段答案;强制完整范围未完成则中断。
+- **当前工作区收尾代码已经直接交付正文,不再调用 validate_deep_answer 进行额外引用修复 / 证据复核 / 遗漏核查。** 函数仍保留,不能据函数存在就认为它正在执行。
+
+压缩没有独立的时间线阶段:用户看到最后一个搜索工具成功,然后长时间等待,最终看到红色错误。与此同时,模型调用次数和 Token 审计仍增长。当前 `usage.status=success` 与“摘要是否通过”也没有分开呈现。
+
+“重试这一步”的真实粒度是恢复最新任务的图节点,不是用户看到的最后一条工具记录,更不是保存了中间草稿的精确摘要重试。
+
+## 11. 子任务与其他周边约束
+
+主任务可委派 `range-analyst` / `fact-checker`。子任务绑定父任务授权范围和版本,不能任意扩展;不递归委派。程序按会话拆分,在 start 非零且跨度超过 60 天时还按 30 天分段。每批最多同时处理 4 个分片。
+
+子任务有独立 run、线程、图检查点和原文;完成后合并原文、finding、stage_note,主模型收到结果路径及有限长度概述。未完成子任务可能使父工具失败,已经保存的子结果保留。它们也使用同一套上下文压缩,因此压缩缺陷并不限于主任务。
+
+全应用模型调度默认并发 4,主任务优先、同优先级父任务轮转;429 会降低并发并逐步恢复。摘要复用当前模型路线,以 purpose=summary 审计,使用辅助调用策略;没有独立选择一个压缩模型。
+
+媒体失败已有局部降级:图片不支持或解析失败时,可继续利用文字。**压缩失败还没有类似的局部降级边界。**
+
+## 12. 旧逻辑与现行逻辑必须分开
+
+| 文件 / 机制 | 当前地位 |
+|---|---|
+| deep_runtime / deep_context / deep_model / deep_tools | 新任务的主执行链 |
+| deep_projection | 现行类继承,用于资料投影、预算展示和读取复用 |
+| agent_tools / agent_reading / agent_workspace / agent_timeline | 仍被当前路径使用的基础能力 |
+| agent_context / agent_continuous / agent_history 等旧混入式主循环 | 文件仍在,但 AgentService 没有继承这些旧执行器;不能作为当前压缩流程依据 |
+| compaction_policy.py | 配置模型仍存在;当前 ContextMeter 使用 usage_calibration,其大部分压缩参数未接入 DurableSummarization |
+| history_summary_bytes / summary_attempts / pressure_ratio 等配置 | 不能据配置字段存在就认为改它会改变当前 v3 的 8192 / 3 次 / 0.8 行为 |
+| validate_deep_answer 及相关修复函数 | 定义仍在,但当前 execute 正常收尾未调用;部分底层校验工具仍可被其他路径使用 |
+| docs 中早期验收与压缩说明 | 历史记录,不是当前运行事实的权威来源 |
+
+重做前应先画出实际调用关系,再决定保留 / 删除 / 迁移。不能只改同名配置文件后宣称生效。
+
+## 13. 设计问题清单
+
+| 编号 | 问题 | 直接后果 | 后续边界要求 |
+|---|---|---|---|
+| P1 | 摘要硬字节目标成为业务成功条件 | 多个搜索成功后,最后无答案 | 压缩故障与分析任务状态分开 |
+| P2 | 阅读、搜索结果持续进入会话历史 | 资料越找越多,重复原文和元数据一起压缩 | 模型输入由受控证据包构建,不等于全部工具日志 |
+| P3 | 全部语义依赖一段反复改写的累计摘要 | 任务要求、状态、证据和叙述竞争 8192 字节;语义损失不可见 | 硬状态由程序持有,摘要只承担可丢弃的软记忆 |
+| P4 | 分段压缩无独立检查点 | 重试重复成本,已经成功的内部工作不能接续 | 压缩作业保存输入指纹、分段进度、候选和版本 |
+| P5 | Token、字节、近似字符和校准估计混用 | 触发、展示、请求容量无法直接对齐 | 每个量标单位,统一预算服务和调用目的 |
+| P6 | 摘要也覆盖主上下文圈 | 小百分比与压缩失败同时出现 | 主任务压力与内部请求用量分开展示 |
+| P7 | 普通问答缺少可靠收尾策略 | 全历史扩大检索,大量工具成功但没有持久成果 | 明确证据充分、无新增、时间范围和阶段输出策略 |
+| P8 | 普通问答不产出可恢复的结构化发现 | analyzed=0,恢复主要依赖图历史 | 普通问答也要有轻量成果,且不冒充全量覆盖 |
+| P9 | 压缩不可见且审计 success 含义过宽 | 不知道在等什么,也不能定位哪个分段失败 | 压缩阶段、分段、原因、用量、验证结果可观察 |
+| P10 | 旧配置和旧函数继续存在 | 改错位置、测试覆盖了非生产路径 | 明确单一执行入口及配置接线 |
+| P11 | 语义保留只靠提示,没有验证 | 字节合格的摘要仍可能漏掉重要条件 | 验证必要状态与证据引用,允许回查原文 |
+| P12 | 模型响应正常 ≠ 摘要适用 | 现有 API 成功审计掩盖业务失败 | 分开 transport、generation、validation、commit 状态 |
+| P13 | 原文总数和覆盖快照刷新入口不同 | 同一范围出现 2146 / 2000 的过期统计 | 状态投影来自一致快照,或明确各计数的更新时间 |
+
+本次补丁修复了“总是重读完整原文”中的一部分,增加了缩写和分段上限,但没有解决 P1、P3、P4、P5、P6、P8、P9。这就是它通过模拟回归后,真实长任务依然失败的原因所在。测试证明了分支、预算和不跳过原文等性质;不能证明真实模型三次以内一定输出合格且语义完整的摘要。
+
+## 14. 后续重做的决策与验收依据(尚未实施)
+
+建议先确定数据和执行边界,再决定继续使用 DeepAgents 还是更换框架。当前缺陷有相当一部分来自应用自己定义的预算、摘要要求、异常出口和展示投影,单换框架并不自动解决。
+
+### 14.1 应先确定的设计
+
+1. **任务状态独立保存**:用户当前要求、真实范围、游标、待提交页、截止时间、已完成目标都由程序维护,不要求模型从压缩摘要重建。
+2. **资料与上下文解耦**:原文留在可寻址资料库;给模型的是当前步骤所需的有界证据,去重、可续读、可回查。
+3. **业务成果独立于会话记忆**:普通问答和完整报告都能形成带来源的阶段成果,但完整覆盖另有明确标志。
+4. **摘要成为可恢复的内部作业**:单独记录输入、分段、成功候选、失败原因与版本;可重试、可替代,不与业务终止绑定。
+5. **统一容量决策**:结合实际发送的输出参数和模型计量;明确软目标、硬窗口、保守估计。较长摘要是否可用应由剩余容量和信息要求决定,而不是只有一个全局 8192 字节门槛。
+6. **让失败有不同后果**:来源暂不可用、工具参数错误、压缩失败、网络失败、覆盖未完成分别定义恢复方式;不能全部归为 deepagents execution failed。
+7. **显示真实进度**:正在检索、正在提炼成果、正在整理上下文、等待模型、可交付阶段结果分开;“重试”文案与实际恢复粒度一致。
+
+这些是重做约束,不是本次已经完成的实现。具体摘要算法、模型选择、容量比例和 UI 交互需要在新方案中确定。
+
+### 14.2 可以保留的基础
+
+原文来源编号和只读约束、scope_handle 权限校验、读取游标、pending_page 提交机制、去重原文库、阶段笔记覆盖、按版本隔离、模型调用审计、媒体局部降级和来源回查都有独立价值。应先保住这些数据合同,再拆主循环和压缩逻辑。
+
+### 14.3 必须通过的真实验收场景
+
+- 本次 2146 条资料场景:压缩故障不应让所有已形成的业务成果不可交付;有明确的暂停 / 降级路径。
+- 摘要返回 13010 字节、含大量中文、来源 ID、长路径:系统能按明确策略处理,且不靠盲目三次重试碰运气。
+- 在第 N 段压缩失败或应用退出:恢复时不重做已持久化成功的 N−1 段,并校验源输入没有变化。
+- 缩写结果变短但漏掉未完成事项或改变否定条件:不得仅因字节合格就认定满足记忆合同。
+- 同一来源被搜索和前后文回查多次:原文存储去重,模型证据输入也有明确去重行为。
+- 普通问答与完整报告分别测试:前者可证据足够就答,后者不能把搜索命中或阅读页数冒充完整分析。
+- 不同模型窗口、不同真实 Token 密度、不同输出参数:压力显示与触发可解释,摘要请求不覆盖主请求压力。
+- 自动压缩的失败、修复和恢复均能在时间线与审计中定位到同一个作业 / 分段。
+- 补充要求改变会话或时间后,旧摘要与旧成果不会绕过新版本的范围校验。
+- 子任务压缩失败时,已完成兄弟任务成果可用,父任务具有明确处置路径。
+- 重启后验证实际进程加载版本,并使用真实故障材料进行受控复现;模拟模型测试不能代替这一步。
+
+## 15. 建议阅读顺序
+
+1. [deep_runtime.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_runtime.py):主入口、恢复、图构建、事件和失败出口。
+2. [deep_tools.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_tools.py):范围、原文登记、分页提交和工具合同。
+3. [deep_context.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_context.py):现行压缩及失败条件。
+4. [agent_budget.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/agent_budget.py)、[context_meter.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/context_meter.py)、[deep_model.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_model.py):预算、计量与上游调用。
+5. [agent_workspace.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/agent_workspace.py)、[deep_backend.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_backend.py)、[deep_checkpoints.py](D:/workProject/WeChatDataAnalysis/src/wechat_decrypt_tool/ai/deep_checkpoints.py):三类保存和恢复边界。
+6. [AgentRun.vue](D:/workProject/WeChatDataAnalysis/frontend/components/chat/AgentRun.vue)、[ChatAgentPanel.vue](D:/workProject/WeChatDataAnalysis/frontend/components/chat/ChatAgentPanel.vue):界面状态与操作粒度。
+7. [test_ai_deep_context.py](D:/workProject/WeChatDataAnalysis/tests/test_ai_deep_context.py):现有模拟回归保证了什么;结合本次审计判断缺失的真实验收。
diff --git a/docs/ai-assistant-acceptance-2026-09-11-stage55.md b/docs/ai-assistant-acceptance-2026-09-11-stage55.md
new file mode 100644
index 00000000..1b173e84
--- /dev/null
+++ b/docs/ai-assistant-acceptance-2026-09-11-stage55.md
@@ -0,0 +1,35 @@
+# Windows AI 追问与原文一致性(阶段 55)
+
+本记录只覆盖 AI。全部计划尚未完成,Mac 尚未进行本轮最终验收。
+
+## 当前版本
+
+- 2026-09-11 23:23:14,Electron 16708、Python 后端 5280,端口 10392;主窗口 65208972。
+- 使用现有账号的真实数据与设置中已有的 DeepSeek 配置。没有新建样例账号,也没有向应用注入测试消息。
+- 已加载本阶段的兼容结果缓存、旧笔记读取范围继承、搜索原文去重修复。源码哈希:`tmp/ai-assistant-implementation-20260910/real-data-55/loaded-source-hashes.json`。
+
+## 真实数据与界面证据
+
+- 原报告运行 `705c43c1867540f49710006146da02da` 保持原回答。原生界面在同一 AI 会话提交勘误追问,运行 `7e54911028444182908eb6d666e2ebb7` 已完成:1820 字符、23 条消息引用,正式接口无缺失;8 次模型尝试,其中一次 HTTP 400 后切换兼容方式,无视觉调用。
+- 追问沿用坦洲羽毛球群和 `[2026-08-25 00:00, 2026-09-11 00:00)`,继承 5524 条原文与阶段笔记;执行了 5 次消息上下文读取、一次定向时间读取、一次关键词搜索,没有重新通读整个日期范围。这不等于完全没有回查。
+- 勘误正确区分了 8/27 19:58 无陌原话中的邀约时间与活动时间,也指出结尾“其余为意向”与 9/10 已记录的比赛结果矛盾。其他扩展结论的引用仍需核对,例如“皓宇”句后引用 `ea25459b32bc78b8ba71edae` 的直接正文没有该地点;不据此宣布整份报告语义验收通过。
+- 点击勘误正文的“阿忠”胶囊,出处栏显示 **引用 22、实际发送者 330、9/10 21:31、原文“@吉量 救我,被阿忠打21-7”**。图片:`real-data-55/person-azhong-source-330.png`。人物胶囊与来源发送者分别核对,同时验证了出处编号没有错误回退到 1。
+- 第一轮只读核对发现 6 条继承原文被搜索结果重复拼接了引用内容,故 `followup-result.json` 明确失败。原始文本和重复后文本有严格可验证的前缀与引用字段关系;仅恢复该追问派生记录的 text,未改微信原库或任何回答。记录:`duplicate-quote-repair.json`。
+- 修复后的 `followup-repaired.json` 十项结构检查通过;这包含人工修复后的状态,不能当作原追问全流程自然通过。`followup-cited-originals.json` 是修复前抓取的材料。
+- 加载修复后调用真实搜索接口:同群、相同日期、“男双”,200 个混合检索命中均与原报告保存的原文一致,0 处文本差异,18.572 秒,0 次远程模型调用。记录:`real-search-canonical.json`。本地向量检索与后台索引仍使用本机模型。
+- 加载修复后,真实简短追问 `2f6e720b3153416982b72c99b19d9750` 完成:准确回答无陌于 8/27 19:58:00 发送原话,人物和消息引用正确;本次人物条件收窄为无陌,所以没有沿用包含其他人的旧笔记,而保留 455 条符合筛选的原文,逐条与原保存文本一致。共 7 次模型尝试,包含一次兼容拒绝和一次无效引用后的成功重试,真实 UI 总用时约 1 分 56 秒。`short-followup.json`、`short-followup.png`。
+- 该次实际请求已持久化 `no_force` 兼容结果;后续同进程决策直接使用兼容方式。重启后的真实请求尚待验证,不能把已写入缓存当作重启复验。
+- 实际点击简短回答的复制按钮,再粘贴到空的 AI 草稿中:人物转为可读姓名,出处显示群名与发送者,没有内部 ID;随后清空未发送的测试草稿,没有额外调用模型。图片 `answer-copy-paste.png`。这是短回答复制的真实 UI 证据,不能替代超长报告复制验证。
+
+## 代码与程序检查
+
+- 索引命中额外携带已经组合好的 AI 原文;AI 适配器直接使用它,保留聊天界面所需的标题、引用和转写字段,避免二次拼接。
+- 追问上下文提供已保存原文数量和旧任务的真实读取范围;旧范围有自身筛选条件,不冒充当前问题已分析完成。兼容旧笔记的来源链;范围改变后过滤,千会话覆盖只传有省略计数的预览。
+- 服务明确拒绝的工具选择、工具调用、流式或 JSON 参数结果存入派生兼容缓存,24 小时有效,按服务地址、协议、模型、配置 ID 和版本隔离。缓存不含密钥、原文或异常正文;读取失败不阻断任务。配置变化或过期重新判断。
+- 独立程序测试没有写入真实应用:模型协议 31 项通过;全局追问与持续阅读 78 项通过;搜索、消息分页、模型协议组合 101 项通过;最终旧笔记链与有界覆盖专项 4 项通过。日志均在 `real-data-55`。各组有重叠,不累加为唯一测试数量。
+
+## 尚未通过的范围
+
+- 兼容缓存重启后的真实模型请求复验、完整报告复制仍待完成;不能用独立程序检查代替实际模型结果。
+- 整份报告语义、全局最近 N 条的最新真实 UI、前台检索优先级完整证据、窄栏/主题/输入法/重连/窗口返回、图片查看器及旧 AI 功能回归,仍按总计划继续验收。
+- Windows 全部稳定后冻结同一版本,再进行 Mac 最终验收;当前不宣称双平台完成。
diff --git a/docs/ai-assistant-acceptance-2026-09-11-stage56.md b/docs/ai-assistant-acceptance-2026-09-11-stage56.md
new file mode 100644
index 00000000..6b51f499
--- /dev/null
+++ b/docs/ai-assistant-acceptance-2026-09-11-stage56.md
@@ -0,0 +1,55 @@
+# Windows AI 图片、窄栏和窗口恢复(阶段 56)
+
+本记录只覆盖 AI。总计划仍在进行,Mac 尚未执行本轮最终验收。
+
+## 真实界面与真实数据
+
+证据目录:`tmp/ai-assistant-implementation-20260910/real-data-56/`。没有向应用写入样例聊天或替换原始数据。
+
+- 使用既有真实回答 `84ab13c7774e4639b7347cc9882e3a5f` 的两张图片引用:坦洲羽毛球群、吉量、9 月 10 日 21:29:43 和 21:30:57。正文仅有图片引用按钮。
+- 原生 Electron 查看器实测:两张之间切换、125% 放大、90 度旋转、方向键循环、拖动、双击复位、Esc 关闭及回到原阅读位置。直接打开第二个引用从 2/2 开始;定位原消息回到正确群的第二张图片,AI 对话保留。证据 `image-1.png`、`image-2.png`、`image-zoom-rotate.png`、`image-escape-restored.png`、`image-locate-original.png`。
+- 将侧栏拖至 320px 最小宽度,核对回答换行、来源、人物、输入框与模型菜单;深浅主题及深色图片查看器均有真实截图。完成后恢复浅色、440px。证据 `sidebar-320-light.png`、`sidebar-320-dark.png`、`model-menu-320.png`、`image-dark.png`。
+- 实际中文输入法输入 n、i 出现候选框,Enter 提交组合文本而未发送 AI 请求。Shift+Enter 换行。中文测试草稿的后续内容通过 Unicode 输入,不把这一段算作完整拼音选词测试。证据 `ime-composition.png`、`ime-enter-keeps-draft.png`。
+- 最小化主窗口再激活,原 AI 对话、回答阅读位置和未发送草稿保留;切换微信聊天至羽萌会社【社牛团】后仍保留。随后清空本次测试草稿。证据 `before-window-return.png`、`after-window-return.png`、`chat-switch-preserves-ai.png`。第一次聊天切换被自动化工具阻止,重新激活后才执行,不将此归因于应用。
+- `before-viewer.json`、`after-viewer.json`、`after-restart.json` 的模型调用记录数量均为 215;以上图片查看、输入法、窗口切换与重启没有新增模型调用。
+
+## 主窗口重启
+
+用户要求重启时,重新发现主窗口及旧进程,而非直接假设主窗口已消失。确认无正在生成的 AI 任务,暂停当时的索引,正常退出后从同一真实数据目录启动。
+
+23:48:13 启动 Electron 14984,主窗口 61671914;日志显示 23:48:17 首次加载 `http://127.0.0.1:10392/` 成功。通过主页“回看聊天”进入已有数据,打开 AI 后历史回答恢复。旧索引任务 `19cb819c003445f8b46e83af3f7c8bd2` 已完成;恢复本次暂停的后续任务 `b32c355acfad4c67a22f2c6410c5b549`。这不证明全账号索引全部完成。
+
+## 模型菜单修复与程序测试
+
+真实窄栏发现模型菜单点击外部不关闭,焦点移出后 Esc 也无法关闭。`AgentModelPicker.vue` 加入外部点击及文档层 Esc 处理:不改模型选择,菜单内部操作保持打开,Esc 只关闭菜单;按原焦点位置决定是否恢复触发按钮焦点,卸载后移除监听。
+
+独立组件测试 10 项通过(模型菜单 3 项、引用 7 项),日志 `references-model-tests.log`。图片不可用提示仅有隔离程序测试,尚无真实缺图界面验收证据。
+
+前端构建通过,已在原生窗口刷新实际页面并复验外部点击和 Esc 关闭菜单,当前 deepseek-flash 选择保持。证据 `model-menu-outside-fixed.png`、`model-menu-escape-fixed.png`;首次菜单修复构建归档 `ui-build/public`。
+
+## 全账号最近 5 条与网络恢复
+
+- 真实 UI 新建对话 `20dcbdb2895041669fc641753fbd38d5`,运行 `e9883e202461477e9b50473a12d59789`。问题指定北京时间 9/11 19:51:23 之前、不含该秒、全账号合计最近 5 条。模型识别范围为 779 个聊天,区间 `[0,1789127483)`;最终 5 条来自一个群和一个私聊。
+- 与阶段 53 固定截止时间的独立真实读取基线逐条比较 source、anchor、username、time、sender_id,完全一致。实际回答按新到旧排列,实际数据包括 19:49:34 的私聊与 19:47:39 至 19:46:36 的群消息。`global-recent-result.json`、`global-recent-answer.txt`、`global-recent-real-answer.png`。共 3 次真实模型调用,无视觉调用。
+- 在该任务运行时,用 Electron 开发工具将验收页面设为 Offline,HTTP 请求实际失败,界面提示自动重连;恢复 No throttling 后请求恢复、回答继续显示、未发送草稿及大视图/执行过程展开状态保留。测试草稿随后清空。`reconnect-before.png`、`reconnect-offline-control.png`、`reconnect-offline-ui.png`、`reconnect-restored.png`。
+- 离线期间部分 SSE 进度仍更新,所以这次只证明 HTTP 失败恢复,**不宣称 SSE 流已断开并成功重连**。恢复时原先处于自动跟随底部模式,不能用它证明用户手动停留位置在重连中保持。
+
+## 本次真实检查发现并修复的问题
+
+- 真实最近 5 条回答使用了群号。持久化原文的 `name` 正确,但 `message_payload` 漏传会话显示名;补上后,原文请求、统一预算以及压缩后的 `note_sources` 使用相同字段。旧回答保留,修复后的真实模型复验待补充。
+- 最近消息每检查一个聊天便写入完整任务及时间线。合并 250ms 内的进度更新,每个回调仍执行停止/版本检查,首个和最终进度必保存;另保存剪枝与实际读取会话数以便验证性能。779 次突发回调测试只保存首尾两次,最终数量保持正确。未据此宣称真实运行耗时已达标。
+- 展开执行过程会一次显示 779 行覆盖信息,挤走回答。改为“查看逐聊天覆盖”入口,每页 20 个,沿用对话视图保存展开与页码;779 项全部可到达,不把部分覆盖显示成全量。
+- 后端持续阅读/预算/最近消息测试 59 项通过,前端对话与执行过程测试 40 项通过。日志 `context-names-tests.log`、`coverage-ui-tests.log`。第二次前端构建通过,归档 `coverage-ui-build`;本组真实加载哈希 `final-loaded-hashes.json`,实际加载复验待补充。
+
+## 修复加载后的实际复验(9 月 12 日 00:05 起)
+
+- 00:05:20 正常启动 Electron 27596、后端 Python 28392、主窗口 5113336;仍使用原真实数据目录和设置里的 DeepSeek。主页回看聊天、AI 历史恢复正常;当时暂停的后台索引已恢复。
+- 原生界面展开上轮任务的执行过程,默认只显示覆盖总计及“查看逐聊天覆盖(779 个聊天)”;打开后第 1/39 页、第 2/39 页可操作。`coverage-collapsed-real.png`、`coverage-page-1-real.png`、`coverage-page-2-real.png`。跨重新挂载保留页码目前只有程序测试证据。
+- 新建对话 `c094282f9c1e4d8886a91787865a1063`,原样提交相同问题,运行 `8f125b25234d4246a5a48489c9d05d81` 完成。3 次真实模型调用,无视觉调用。实际答案正确显示私聊“18计1 张梓杰”与群聊“封神演义-反派联盟”,不再使用群号。人物与出处分别显示实际发送者。
+- `tools/verify_ai_real_recent_run.py` 以只读连接核对:固定截止时间、779 个聊天、准确 5 条消息身份、逐聊天读取/分析数量、引用从新到旧、聊天显示名和模型审计全部通过。输出 `global-recent-fixed-result.json`。脚本不自称验证原生 UI;实际界面证据另见 `global-recent-fixed-real-answer.png`。
+- 同条件真实选取耗时由 134.48 秒降至 39.11 秒,时间线版本更新从 781 降至 86。明确记录使用原消息上界剪枝,实际读取 2 个聊天、跳过 777 个聊天。第二次整体 UI 耗时约 1 分 57 秒,第一次约 3 分 48 秒;包含模型波动,不将这两次比较当成普遍性能保证。
+- 本阶段两次最近消息问题合计新增 6 次真实模型调用,累计调用记录 221。最终状态见 `final-state.json`;本组群名与覆盖分页修复已实际加载。
+
+## 剩余工作
+
+实际 SSE 断线恢复、运行中补充/停止/继续与配置快照、索引前台优先级完整证据、完整报告语义与长文复制、旧 AI 功能回归仍需完成。最近 5 条固定范围实测通过,不代替全部边界与筛选场景。窗口恢复证据不替代网络重连证据。Windows 稳定后冻结同一版本再做 Mac 最终验收。
diff --git a/docs/ai-assistant-acceptance-2026-09-12-stage57.md b/docs/ai-assistant-acceptance-2026-09-12-stage57.md
new file mode 100644
index 00000000..8fc3d4bb
--- /dev/null
+++ b/docs/ai-assistant-acceptance-2026-09-12-stage57.md
@@ -0,0 +1,30 @@
+# Windows AI 补充、停止与重启(阶段 57)
+
+整项尚未完成。本阶段只检查 AI,使用现有真实账号与本机模型配置。证据目录为 `tmp/ai-assistant-implementation-20260910/real-data-57/`。
+
+## 真实操作与通过边界
+
+- 原生窗口提交“完整阅读坦洲羽毛球群北京时间 2026/9/10 全天聊天”的问题,运行 `1b37b218c7934df2a266cc577e28e96f`,读取 186 条真实消息。
+- 运行中将菜单改选已有的图片优先模型,再按 Enter 补充“邀约 / 实际比赛结果 / 玩笑与不确定信息”三部分要求。仍是同一运行,版本由 1 到 2,启动配置 deepseek-flash 不变;没有因此调用视觉模型。
+- 输入未发送测试草稿后点击主按钮,确实停止任务而不是发送草稿。实际继续后,同一运行、同一配置、186 条原文保持;第一轮停止时尚无已完成笔记,不能据此宣称免除已完成分析。
+- 随后保存一份阶段笔记和 10 条发现;在回答中途再次停止。原正文 844 字符保存在 `confirmed-stopped-answer-prefix.txt`。
+- 程序比较、原生截图、模拟测试分别记录,不互相替代。`control-*.json` 来自只读数据库快照;`supplement-received.png`、`stopped-with-draft.png`、`resumed-with-draft.png` 为实际窗口证据。
+
+## 失败与已加载修复
+
+- 补充或停止时,笔记步骤曾被统一标红失败。后端现按版本变化、取消、中断与真实错误分别记录;原文与保存失败回滚逻辑保留。4 项专项测试通过,含两种事务保存失败场景,日志 `control-failure-tests.log`。修复已加载,新的真实停止步骤尚未复验;不改写旧步骤状态。
+- 停止回答会暴露尾部半截引用。前端现在在停止后继续隐藏未完成标记,检查点原正文保留供续写,复制文本也不带半截标记。相关 29 项前端测试及生产构建通过,见 `stopped-marker-tests.log`、`ui-build.log`;正式静态产物归档 `ui-build/`。
+- **真实续写失败,尚未解决**:第二次继续保留了旧 844 字符,却在半截引用后从标题重新输出正文;模型校验触发一次重试后仍重复。已由原生主按钮停止,未宣称完成。失败正文、截图与比较见 `failed-continuation-answer.txt`、`failed-continuation-stopped.png`、`continuation-comparison.json`。186 条原文和笔记键保持,piece 整体发生变化的是执行时间线;不能把全部 piece 相等作为通过事实。
+- 该任务共 8 次真实模型尝试(含取消和重试),无视觉调用。此时数据库累计用量记录 229 条。
+
+## 主窗口恢复
+
+确认无正在运行或排队的 AI 任务后,暂停实际后台索引,正常退出并使用相同真实数据目录重启。2026/9/12 00:32:36 启动 Electron 12720,后端 4328,端口 10392,主窗口 1705574。恢复索引任务 `c34e5512dc8e4ff6a2986b89bd4ffd9f`,返回 queued,不据此宣称全量索引完成。运行仍为 cancelled,原文、笔记与失败回答留存,未重新发起模型调用。加载文件哈希在 `loaded-hashes.json`。
+
+重启后实际进入回看聊天并打开 AI,原对话和停止回答恢复,尾部 `[[4ca33da53` 已隐藏、之前完整的第 46 条来源仍显示;截图 `restarted-real-ai.png`。`restart-comparison.json` 核对重启前后运行、状态、配置指纹、全部原文与 piece、笔记键、答案长度及用量均相同。输入框中的验收测试草稿已随这次应用重启清空,不据此宣称跨应用重启保存草稿。
+
+## SSE 与剩余验收
+
+尝试通过透明本机转发地址启动同一应用以验证 SSE 断线,被自动审批拒绝,返回仅为 `blocked by policy`,没有具体理由。未绕过拒绝;转发服务已关闭,正常入口已恢复。`sse-transport.json` 的连接数为 0,不能作为 SSE 验证证据。
+
+完整续写、真实 SSE 断开恢复、完整报告语义与最终同版本 Mac 验收仍未通过。此前合成数据或旧 Mac 结果不能覆盖这些缺口。
diff --git a/docs/ai-assistant-acceptance-2026-09-12-stage58.md b/docs/ai-assistant-acceptance-2026-09-12-stage58.md
new file mode 100644
index 00000000..077782e9
--- /dev/null
+++ b/docs/ai-assistant-acceptance-2026-09-12-stage58.md
@@ -0,0 +1,36 @@
+# Windows AI 真实续写修复(阶段 58)
+
+本阶段只处理 AI,整项计划仍未完成。证据目录:`tmp/ai-assistant-implementation-20260910/real-data-58/`。
+
+## 原问题与修复
+
+阶段 57 的真实任务在 `[[35b4f` 处停止,继续时模型从标题重写,形成无效引用。校验重试还使用“重新输出完整回答”的普通提示,与保留原前缀的续写逻辑冲突。
+
+- `agent_references.py` 对半截来源、人物、图片标记限定合法接写字符;错误续写在发布前拦截,完整结果拒绝未闭合引用和重新输出已有开头。合法编号候选只在进入续写时计算一次。
+- `agent_model.py` 使用续写专用纠错提示,重试仍只输出剩余内容,保留失败和取消调用的审计。
+- `agent_service.py` 将唯一合法的引用尾部明确交给模型。对旧版本已经拼接无效内容的任务,使用其持久化 `answer_resume` 恢复原续写起点,不从头重做阅读或分析。
+- 组合测试 67 项通过(109.32 秒),后续最终修改专项 7 项通过(3.54 秒)。两组有重叠,不相加为独立测试数。日志 `continuation-tests.log`、`continuation-final-tests.log`。
+
+## 实际加载与同任务复验
+
+00:40:14 正常重启 Electron 14228,后端 31780,主窗口 3802596,端口 10392。继续使用原真实数据目录,恢复当时暂停的索引 `baaa3c7a46e6489d866c40fdbf7e59ca`。哈希见 `loaded-hashes.json`。
+
+通过主页回看聊天、打开 AI,再点击原任务的“继续查找”,运行仍为 `1b37b218c7934df2a266cc577e28e96f`,版本 2。原 844 字符包含半截来源,模型这次首先输出正确尾部 `af68da2cd19f3516aa6]]`,随后完成剩余回答,没有重新输出标题。
+
+只新增 1 次 DeepSeek 调用,42.18 秒,成功,无视觉调用;该任务累计 9 次尝试。答案 3111 字符,含 57 个引用标记(含人物标记和重复出现,不能当作 57 条独立消息)。
+
+只读校验 `completed-continuation-final.json` 的 12 项结构检查通过:同运行、版本、配置、186 条原文、阶段笔记与发现保持;无新增读取/压缩;原 844 字符完整保留;标题不重复;引用可解析且没有半截协议。`completed-continuation.json` 为此前一次结果,最终脚本另修正了压缩时间线按 action 判定,最终结果仍通过。
+
+原生窗口截图 `completed-real-answer.png`;点击“阿忠”人物胶囊,打开实际发送者 **330**、9/10 21:31:31、“@吉量 救我,被阿忠打21-7”的消息预览,发送者头像也是 330。证据 `person-azhong-source-330.png`。这证明当前真实回答中的该处人物与发送者分离,不代表全部同名人物场景通过。
+
+## 原始范围与内容复核
+
+将阶段 53 独立实时原库元数据按 9/10 左闭右开区间过滤,得到 186 条;本任务原文的全部 anchor、时间和所属群一致。`original-range-comparison.json`。该对照核对定位与时间,不自称重新验证全部原文字符。
+
+逐条阅读本任务 186 条已保存原文并复核最终回答:比分方向“阿忠 21、330 7”及消息时间正确;区分了邀约时间与活动时间,未分析图片。
+
+**完整报告内容仍未通过**:当前提问要求“当天活动讨论”,阶段笔记已经漏掉吃饭等活动,答案随之遗漏;结尾还把凌晨未明确项目的邀约称为“明确的羽毛球邀约”。原文存在 18:34 搞海鲜吃、18:54 等人、19:59 等上菜、20:29 上菜等讨论。不能用续写结构通过替代完整报告范围和语义通过。旧笔记与回答保留,尚未按此问题重新分析。
+
+## 未完成事项
+
+完整报告范围与语义、真实 SSE 断开恢复、部分旧 AI 功能回归及最终同版本 Mac 验收仍待完成。此次没有重试此前被自动审批拦截的转发入口,也没有访问朋友圈。
diff --git a/docs/ai-assistant-acceptance-2026-09-12-stage59.md b/docs/ai-assistant-acceptance-2026-09-12-stage59.md
new file mode 100644
index 00000000..f43d5cfe
--- /dev/null
+++ b/docs/ai-assistant-acceptance-2026-09-12-stage59.md
@@ -0,0 +1,45 @@
+# Windows AI 报告范围与程序时间(阶段 59)
+
+本阶段只检查 AI,整项计划未完成。证据目录:`tmp/ai-assistant-implementation-20260910/real-data-59/`。
+
+## 真实数据复验与新失败
+
+在笔记、完整系统说明、小窗口系统说明中增加约束:群名只定位会话,不代替用户的主题条件,也不能据此补全原文未明确的活动项目。范围与预算测试 57 项通过(97.45 秒)。
+
+00:50:59 正常重启 Electron 5304、后端 32584、窗口 51448812,仍为原真实数据目录、端口 10392。通过回看聊天进入 AI,新建任务 `8d03c923f6304a6c938129732cbd70f9`、对话 `a64fd847703c4ce29650583d1b4c9996`,原样提交阶段 57 的首轮问题,没有追加三栏分类要求。`question.txt`、`question-real-ui.png`。最初一次只读查询发生在提交尚未完成时,取得旧任务;随后按实际新任务修正 `run-id.txt`,没有重复提交。
+
+独立实时原库扫描本范围仍为 186 条,位于 `message_6.db`,三个相关消息库均完成探查。`realtime-originals.json`、`realtime-originals.log`。应用读取 186 条,保存一份笔记、13 项发现,新增包含聚餐、海边和火锅推荐等内容。
+
+**本次笔记内容仍失败**:多处消息时间被模型写错,例如 18:54 写成 16:54、21:31 写成 19:31;笔记中仍出现原文未明确的“羽毛球”项目表述。检查输入发现消息只给 Unix 时间戳,模型自行换算。已用原生主按钮停止此轮生成,当时正文 0 字符,未把错误报告当作完成。累计 4 次模型尝试,包含两次笔记生成和取消的回答生成。证据 `stopped-time-error.json`、`time-error-note.json`、`stopped-answer.txt`。
+
+## 程序提供时间与统一预算
+
+`message_payload` 新增 `sent_at`:程序按任务保存的时区生成带偏移的 ISO 时间;保留原 `time` 定位字段,不改原聊天数据。活跃原文、压缩后来源、旧运行分片及旧回答材料均提供该字段,读取预算和正式请求同时计入。笔记与回答提示要求使用 `sent_at`,且来源时间优先于旧笔记。
+
+任务提示中的当前时间改用已保存的截止时间与时区,避免恢复后随机器当前时区改变;缺少时区字段的旧任务保留原本地时间解释。
+
+第一轮组合测试 67 项通过、1 项失败:旧测试假设 13107 字节必然能放下超过 100 条短消息,新增时间字段后实际为 89 条。修正为两档预算并继续验证足够预算超过 100 条、缩小预算后的字节上限、500 条完整无重复与游标连续,未提高应用预算或省略时间字段。日志 `canonical-time-tests.log`;最终测试与真实加载结果另记。
+
+## 首个事件前的 SSE 游标
+
+代码检查发现初始空闲流只发送无编号心跳,如果首个业务事件前断开,重连可能从新的最新编号开始而漏掉断线期间的事件。现在连接建立即发送一个仅含 `id` 的完整事件块。按 [HTML 的 SSE 解析规范](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation),浏览器先更新最后事件编号,空 data 则不触发消息分发;恢复请求使用该编号。
+
+两个独立程序测试覆盖初次空闲流关闭后的补发、账号隔离、零游标和显式游标,均通过。初次测试因测试 Request 缺少 ASGI receive 通道失败,补全测试通道后通过;分别保留 `sse-cursor-tests.log`、`sse-cursor-tests-fixed.log`。这不是实际 Electron 网络断线验收,也没有重试此前被审批拦截的转发入口。
+
+## 时间修复加载
+
+最终组合测试 70 项通过(106.79 秒),日志 `canonical-time-final-tests.log`。01:05:55 正常重启 Electron 28576、后端 25380、窗口 2426310,继续使用端口 10392 和真实数据目录;恢复原后台索引。加载哈希在 `time-loaded-hashes.json`。
+
+直接读取正式 SSE 接口,首个块返回 `id: 27369`、HTTP 200、text/event-stream,证明本机运行接口已加载初始游标修改;`live-initial-sse.json`。它没有验证原生界面断线及重连状态保留。
+
+## 使用程序时间后的真实恢复结果
+
+在原生窗口点击原任务“继续查找”,只增加 1 次 DeepSeek 调用,最终答案 5775 字符;任务累计 5 次尝试,无视觉调用。数据库累计用量记录 235 条。186 条原文、13 项发现、原笔记键及内容、版本和配置均保持;`time-recovery-comparison.json`。没有直接改写旧笔记,不能把本次说成重新生成的笔记已经全部正确。
+
+回答中的 02:15 喝酒、03:13 约定、09:14 算钱、18:54 等人、21:31 比分等时间恢复为来源时间,聚餐、火锅、海边及游戏等内容也有展示;`time-corrected-answer.txt`、`time-corrected-real-ui.png`。程序结构核对确认时间范围、186 条独立原库定位、所属群、全部原文字元覆盖、来源合法、压缩降低占用等通过。`completed-report-structure.json` 的总体 passed 仍为 false,因为该工具还要求多份阶段笔记,而本次仅一份;保留这个判定,不拿一天样本代替长范围多轮压缩验收。
+
+**内容仍有失败项**:18:36 前后“今晚明华有没有选手”所在段落所附来源不含该消息,反而引用了“家里经常吃”等;正确来源 `e5cacdf914cfd7ecb5b5efc4` 被放在前一个海鲜段落。结尾又称孔进喜具体内容未记录,而原文 `f8755c6bb277365b9af7b355` 就是“让你叫人,没让你人叫”的复读。报告中的项目类型仍有未经明确标注的推断。编号合法不等于引用与结论正确对应,完整语义验收仍未通过。
+
+真实复制按钮显示“已复制回答”;粘贴到未发送 AI 草稿,分别核对开头和结尾,人物及出处为可读文字。`copy-button-success.png`、`copied-report-start.png`、`copied-report-tail.png`。未通过系统剪贴板逐字符提取校验;随后清空了这份测试草稿,没有提交新问题。
+
+下一步仍需解决结论与来源绑定、旧笔记内容的使用方式,以及真实桌面断线重连;Windows 稳定后才进行最终同版本 Mac 验收。
diff --git a/docs/ai-assistant-development-status.md b/docs/ai-assistant-development-status.md
new file mode 100644
index 00000000..73aeee2c
--- /dev/null
+++ b/docs/ai-assistant-development-status.md
@@ -0,0 +1,126 @@
+# AI 助手当前开发状态
+
+执行顺序:集中完成全部功能与缺陷修复 → Windows 整体验收 → 冻结同版本源码 → Mac 最终验收。只处理 AI,不验收朋友圈。本文件记录当前源码,历史阶段记录保留作证据;当前不是最终交付通过状态。
+
+## 当前模型与运行状态
+
+用户已指定 Xiaomi `mimo-v2.5`,须通过软件“设置 → AI 配置”保存服务和密钥。后续真实模型验收使用此配置。旧 DeepSeek 历史和已停止任务保留原配置快照,不改写为新模型,也不继续用旧服务发起验收。密钥和 Mac 凭据不进入源码或交付记录。
+
+2026-09-12 重启操作的 Electron 启动命令曾被自动审批拒绝,仅返回 `blocked by policy`。随后检测到主窗口和真实数据后端恢复(Electron 30272、后端 8236、窗口 658140),本轮已在原生软件“设置 → AI 服务”新增 Xiaomi MiMo,确认模型为 `mimo-v2.5`,并保存为默认文本/视觉模型。通过上游列表识别模型,窗口 1048576、支持图片;没有填写未经确认的原生等级。证据见 `windows-integrated-63/xiaomi-settings.json` 与图片。旧服务未改写。
+
+## 候选 63 正在进行的 Windows 实测
+
+证据目录:`tmp/ai-assistant-implementation-20260910/windows-integrated-63/`,均使用现有真实账号;不使用样例数据替代验收。
+
+- 原生中文输入法已显示拼音候选,候选状态 Enter 没有误提交;Shift+Enter 只换行。主窗口最小化再切回,当前 AI 对话、草稿和执行步骤展开状态保留。
+- 统计任务 `a2080e3eaf26429f88d0c6cb0874744f` 的原生主按钮停止和继续入口均有数据库成功证据;运行中 Enter 的补充仅保存一次,版本由 1 升至 2,同一运行和 Xiaomi 模型配置指纹保持。此例尚未读取原文时停止,不替代已分析资料恢复去重验收。
+- 统计范围为北京时间 9 月 10 日 `[21:29,21:32)`,独立逐条核对为 11 条、4 位发送者,分别 5/3/2/1 条,来源定位、人物引用和零视觉调用通过。但最终回答错误声称没有保存消息时间及出处;原生来源侧栏能够直接展示这些原消息。因此数字验证通过,回答语义及出处交付仍失败。该历史回答保留,不能因结构检查通过而宣称整项通过。
+- 原生 Offline → No throttling 已验证普通请求失败恢复和草稿保留。未取得已有 EventSource 连接真正断开重连的证据,SSE 验收仍未通过;开发者工具已关闭,网络模拟已恢复正常。
+- 长报告 `b2490a7a51584bdf89ad2a96d84601ee` 已失败:正确范围原库 3027 条,保留 1907 条唯一来源,0 份笔记、0 次视觉调用。首轮笔记请求约 901.75 秒后报连接错误,后两次重试为 HTTP 500;合计 4 次真实调用(含初始意图识别),3 次失败未返回用量。没有释放未成功整理的原文,没有完成压缩或报告验收。
+- 后续普通问题 `27d14798a8a74884b9d631f64e798ea6` 也在意图识别阶段失败,尚未检索:首轮约 301 秒后报连接错误,后两次重试为 HTTP 500,合计 3 次真实调用。不能仅凭长报告失败认定输入规模是根因;未反复重发任务。
+- 全账号最近 5 条的独立原库范围扫描已完成:779 个会话、364.47 秒,选出的 5 条与独立边界扫描完全一致、没有读取警告。`recent-real/comparison.json`。这是只读程序验收,远程模型调用为 0,不替代原生窗口和模型理解问题的验证。
+- 13:46 原生 AI 服务“测试连接”失败:内置 32×32 测试图片,3 次尝试均为 HTTP 500,均未返回用量。仅验证连接,不属于真实聊天图片分析。证据:`xiaomi-connection-test.json`、`xiaomi-connection-test-failed.png`。不能以此断言密钥错误或已经查明服务故障原因。
+- 13:49 已保存真实回答的图片操作通过:125% 放大、90° 旋转、拖动、双击还原、方向键切换到第 2/2 张,并定位到吉量 21:30:57 的原图片消息;AI 回答保持。用量记录前后均为 263,新增调用为 0。证据:`image-interactions.json`、`image-zoom-rotate.png`、`image-second-reset.png`、`image-located-real-message.png`。此项不证明历史回答语义完整,缺图状态另待验证。
+- 旧 AI 功能原生入口可用:消息总结、自动任务、关注提醒及历史记录。真实账号已有的两份 9 月 8 日总结均由只读接口恢复,结果与原记录一致;分别保存 100 条来源,33/55 个实际引用均有映射,每份各抽查一条原消息,其定位和时间一致。原生窗口已打开其中一份。`legacy-history-result.json` 与 `legacy-*.png`。没有重跑旧模型、创建规则或触发通知,不能据此宣称自动执行和提醒投递通过。
+- 后台真实索引已恢复自动更新,779 个会话、1,481,095 条消息、182,921 个片段;本次读取状态仍明确标记部分覆盖。`index-current.json` 只是运行状态,不等同于独立原库全量核对。
+
+## development-64 出处修复(已由 14:07 的 dev 后端加载)
+
+- 统计上下文补充当前任务已计数消息的来源示例,包含稳定来源编号、实际发送者、会话和程序时区时间;每位发送者按时间、来源顺序取一条,限制条数和总体积,省略数量明确记录。
+- 总数仍由程序统计;不把出处示例条数当作统计总数,不发送聊天正文让模型重新计数。补充回答规则,区分“本次请求未展示”与“原文没有保存”。旧回答没有重写。
+- 复现测试修复前 2 项失败、修复后 2 项通过;随后持续阅读、上下文、人物身份、Agent 协议、引文和历史兼容等相关回归 143 项通过(225.55 秒)。真实已保存统计任务的只读查询验证 4 位发送者、实际消息身份、稳定顺序和其他运行隔离均通过。证据:`development-64/statistics-context-tests.log`、`development-64/real-statistics-sources.json`。
+- 统计验收脚本增加显式要求消息出处的选项;候选 63 的旧回答在该要求下失败,不能仅因计数与人物引用正确而通过。新模型回答仍待复验。
+
+## development-65 集成检查与 dev 启动恢复
+
+- 合并核对统计出处与[耗时及拆批修复](ai-latency-batching-2026-09-12.md),持续阅读和耗时预算组合 45 项通过,109.06 秒;源码指纹与日志在 `development-65/`。其他任务记录的 171/76/40 项有重叠,不在此累加。
+- 新的模型调用截止时间、48 KiB 原文批次与失败拆批属于后端修改。现有真实报告仍为失败状态,1907 条保存原文没有被模拟笔记替换。隔离复验的 14 份模拟笔记不能作为真实压缩或模型语义通过证据。
+- Windows 超时回调可能在业务计时器下一跳之前触发;模型调用现在同时检查超时上下文是否已经到期,避免截止后再次重试。三个入口的复现测试修复前均失败;修复后耗时、时间读取、预算、供应商和协议组合 120 项通过(54.74 秒),见 `deadline-before.log`、`deadline-after.log`。这些是隔离程序测试。
+- 14:07 从 `desktop` 正式执行 `npm run dev` 成功,没有审批拒绝。使用 Node 24 与现有真实数据目录,前端 3000、后端 10392,Electron 15072、后端 6304。未使用手动启动脚本。重启后,已取消任务 `2839e6e8b14944559d7cae3b3083f3ee` 的 496 条资料、3 份笔记和配置指纹保留;另一任务在启动恢复时被标记为中断,不能称所有运行均无中断。
+- dev 页面发现并修复 Nuxt 自动导入错误:`agentTimeline.js` 的箭头函数参数 `incoming/key/event` 被误认作导出,导致页面无法初始化、误显示空账号。改为具名函数声明,补充真实 `unimport` 扫描回归;修复前测试失败,修复后时间线、引用和 AI 面板 52 项通过(2.60 秒)。刷新 Nuxt 转换缓存后错误消失,生成导出清单只含四个真实函数。见 `dev-import-before.log`、`dev-import-after.log`。
+- 原生 dev 主窗口已显示真实聊天、账号级 AI 历史和正在运行的“十天活动报告·优化后速度与质量复测”;截屏时显示已读取、分析 824 条。这只是运行进度,不是报告质量或完整范围验收通过。见 `dev-running-real-ai.png`。本次前端恢复没有再次重启后端或提交新模型问题。
+- 先前候选 65 源码包与 `source-hashes.json` 早于后续修复,属于历史快照,不能作为当前 dev 版本的最终交付包。当前源码和运行恢复的补充记录见 `dev-recovery.json`;真实模型整体验收和 Mac 验收仍未完成。
+
+## development-63 集中修复与程序检查
+
+2026-09-12,development-63(尚未完成真实模型/窗口验收):
+
+- 连续阅读收缩窗口时,以已提交消息游标的时间作为下界,防止二分到游标之前后清空游标、重读前缀。同秒身份断点继续保留。回归用例修复前失败,修复后读取链路 70 项通过。
+- 阶段笔记允许同一事实关联超过 12 个已验证来源;不裁掉来源凑数量,仍受来源真实性、引文一致性和笔记总体积预算约束。校验尝试单独保存未知来源数、笔记字节数、预算、引文错配与通过状态,失败不释放原文。阅读与笔记组合 77 项通过。
+- Xiaomi MiMo 成为设置中的独立服务预设,支持“小米/MiMo”搜索和现有上游模型选择。上下文、图片等能力继续来自能力目录或显式上游信息;官方文档明确的 JSON 输出能力仅补充到准确的官方接口与模型,显式上游/手动值优先。不推断不存在的原生推理等级。
+- Xiaomi/供应商后端 42 项、设置与模型选择前端 33 项通过;前端 AI 完整 17 文件、193 项通过。完整后端第一次为 450 通过、1 失败(旧 API 测试把服务数量写死为 14);更新到含 Xiaomi 的 15 个服务后,该接口文件 7 项全部通过。保留首次失败日志和定向复验,不将首次全组日志改成通过。生产构建已生成 34 个路由。
+
+证据目录:`tmp/ai-assistant-implementation-20260910/development-63/`。Xiaomi 接口依据:[官方接入](https://mimo.mi.com/docs/en-US/quick-start/summary/first-api-call)、[JSON 输出](https://mimo.mi.com/docs/en-US/quick-start/usage-guide/text-generation/structured-output)、[思考参数](https://mimo.mi.com/docs/en-US/quick-start/usage-guide/text-generation/deep-thinking)。开发检查未发起 Xiaomi 真实推理;随后真实模型验收单独记录于 `windows-integrated-63/`。
+
+## 候选 62 的真实报告失败记录
+
+证据目录:`tmp/ai-assistant-implementation-20260910/windows-integrated-62/`。
+
+- 坦洲羽毛球群 9 月 1 日至 9 月 11 日(北京时间)的范围已正确固定为 `[1788192000, 1789056000)`;独立基线共 3027 条。
+- 实际任务读取 1284 条唯一消息后停止,使用 46 次工具、5 次真实 DeepSeek 调用、0 次视觉调用。保存了第一份笔记,预算约从 80% 降至 34.6%。没有完成报告或多轮压缩验收。
+- 读取步骤合计出现 525 个重复来源,定位为窗口收缩后游标回退,现由 development-63 修复;修复后的真实长报告仍待验证。
+- 笔记重试中确认一次被“单条笔记来源超过 12 个”拦截;其他外层校验的详细原因在旧日志中缺失。新代码补齐校验记录,不能倒推旧失败原因。
+- 原生停止点击没有取得确定成功证据;随后通过应用停止接口确认任务为 `cancelled`,原文、笔记和配置保留。原生按钮停止仍列待核对项。
+
+## 上一批集中修复
+
+2026-09-12,Windows 整体验证后的当前修复(development-62):
+
+- 明确时间范围支持“北京时间2026年9月1日00:00至9月11日00:00之前”、结束日期省略年份或年月、左闭右开的截止钟点。由程序换算,覆盖模型错误的 Unix 秒;不擅自推断跨年或跨日。
+- 语义查询按片段计算一次距离,逐批展开符合条件的原消息,再读取最终正文;保留等距离时按时间、来源排序和重叠片段去重。真实索引 1,481,095 条消息、182,921 个片段的前 200 项与旧查询顺序和距离完全一致;该查询从 56.56 秒降至 1.33 秒。此数值不包含模型编码、基础搜索、AI 生成和界面传输。
+- 连续阅读在剩余预算充分、上次时间窗口偏小时,同一步内扩大已验证窗口;超限继续二分,失败不推进调用方游标,减少几条消息就保存一次执行步骤的情况。完整报告耗时仍需重新验证。
+- 日期与账号级助手测试 55 项、索引测试 62 项、时间读取/预算/持续阅读测试 69 项通过;这些是程序验证,不是当前整项验收通过。
+- 随后完整后端 AI/本地检索整组 441 项通过,耗时 318.92 秒;日志 `development-62/backend-all-ai.log`。前端没有在本批修改,现有生产构建沿用 development-60。
+
+## Windows 真实验证发现(候选 60)
+
+证据目录:`tmp/ai-assistant-implementation-20260910/windows-integrated-61/`。
+
+- 全账号问题“谁说过‘7-21惨案’”:真实 DeepSeek 完成,确认来源为坦洲羽毛球群、发送者 330;人物引用和发送者头像一致。定位原消息切换到该群,AI 对话和未提交草稿保持。这个例子没有证明“甲谈乙”,该项仍需独立核对。
+- 原生窗口已检查 320px 明/暗主题、暗色大视图、来源浮层和侧栏;设置中使用现有 DeepSeek 配置。未把这些局部检查当成全部界面通过。
+- 重启后的候选 60 原生窗口进一步核对了旧真实报告的“甲谈乙”:正文阿忠人物胶囊使用阿忠头像,点击后来源侧栏为发送者 330 的熊猫头像,原文为“@吉量 救我,被阿忠打21-7”,上下文也来自真实消息。证据 `person-subject-sender-distinct.png`;报告其余旧内容不因此视为正确。
+- 另一条已保存真实回答恢复两张图片引用,查看器仅显示该回答的 1/2 与 2/2,来源时刻分别为 21:29:43、21:30:57,切换后为两张不同的本地图片。模型用量记录查看前后均为 242,没有新增调用。证据 `real-image-1.png`、`real-image-2.png`、`image-view-usage-after.json`;缺图、缩放/旋转等其他交互仍需对应检查。
+- 全局问题总耗时 161.03 秒、6 次真实调用,首次混合检索 93.89 秒;性能未通过。上面的向量优化只解决已定位的一部分耗时,原文关键词扫描仍约 12 秒。
+- 完整报告要求北京时间 9 月 1 日至 9 月 11 日,独立原库基线为 3027 条。但任务误用提前 16 小时的范围,已停止:读取 1267 条、46 个读取步骤、1 次真实调用、未保存阶段笔记。不能作为完整阅读或压缩通过的证据。
+- 用户要求重启后,主窗口已重新启动并显示真实聊天与原 AI 会话。development-62 完成后,于 12:24 再次统一重启载入本批后端;当前真实模型整体验证仍待完成。
+
+## 上一批实现
+
+- 压缩来源在原有预算内附真实原文片段,保留发送者、会话与程序时间;截断明确标识,完整原文仍保存在任务资料中。
+- 笔记保存和最终回答检查能确定的直接引文错配。错误引用触发纠正;笔记校验失败不发布、不释放原文;答案重试保留用户要求的范围和详细程度。代码示例与已显示续写前缀不要求重写。字面检查不能证明全部语义正确。
+- 旧范围版本不再隐藏同账号历史回答或阻止来源访问,历史读取不裁剪资料;继续严格校验账号、任务归属和运行版本。人物/图片引用按同一任务保存的映射恢复。
+- 来源与分段发现接口提供实际发送者头像,分段发现传递独立人物/图片引用,原文侧栏标明节选。
+- SSE 按运行身份、版本和时间合并预算、覆盖与状态,旧事件及重复步骤不覆盖较新的内容或身份。重连后主动补取快照,没有新业务事件也能恢复结果。
+- 已开启自动更新的旧索引配置由后台迁移为全账号,不再依赖首次提问;保留显式暂停和模型可用性检查。
+
+## 全计划实现入口与统一验收范围
+
+下表是源码核对,不能替代真实验收。
+
+| 要求 | 实现入口 | Windows 统一验证重点 |
+| --- | --- | --- |
+| 全账号目录、跨群/私聊检索、人物/会话/时间筛选与账号隔离 | `agent_global.py`、`agent_tools.py`、`agent_live_search.py` | 旧目录外命中、组合筛选、追问、实际会话定位 |
+| 账号级 AI 列表、聊天切换独立、旧历史和旧任务 | `agent_service.py`、`agent_timeline.py`、`ChatAgentPanel.vue` | 历史回答、来源与继续处理,草稿/阅读位置保持 |
+| 基础搜索、渐进语义索引、暂停恢复、增量与前台优先 | `local_search/service.py`、`progressive.py`、`index.py` | 未建/部分覆盖、边建边查、增量及查询耗时 |
+| 时间游标、同秒与字符分片、空区间、全局最近 N | `agent_reading.py`、`agent_context.py`、`recent_bounds.py`、`messages.py` | 固定时区/截止时间、独立原库集合、边界与长原文 |
+| 统一预算、80%/60% 压缩、原文 15%/笔记 20%、保存后释放和恢复 | `agent_budget.py`、`agent_continuous.py`、`agent_workspace.py` | 多轮真实压缩、完整读取、恢复不重复分析 |
+| 模型/原生等级、设置入口、运行配置快照、旧 effort | `agent_schemas.py`、`providers.py`、`model_catalog.py`、`AiSettings.vue`、`AgentModelPicker.vue` | 设置中的 Xiaomi mimo-v2.5、补充/继续与实际请求一致;旧运行不改写配置 |
+| SSE、消息/草稿/阅读位置/展开状态连续性 | `routers/ai_agent.py`、`useAiApi.js`、`agentTimeline.js`、`AssistantThread.vue` | 真正的 Electron SSE 断线及恢复,不能以 HTTP 失败代替 |
+| AI Elements Vue、Tailwind 4、D01~D04 | `components/ai-elements/`、`agent.css`、输入框/来源/图片组件 | 320px、大视图、主题、中文输入、Enter 补充、停止与窗口切回 |
+| 发送者与被谈论者分离、同名、旧来源与图片恢复 | `agent_references.py`、`agentMarkdown.js`、`AgentAnswer.vue` | 甲谈乙、多来源、半截引用、缺图、当前回答图片集合与零视觉副作用 |
+| 报告/程序统计、阅读复制、旧总结/任务/提醒 | `agent_continuous.py`、`agent_workspace.py`、`AiSidebar.vue`、`AgentCopyAction.vue` | 原文一致性、分类与结论、旧 AI 功能回归 |
+| 同版本 Mac 与源码/锁文件/脚本/记录交付 | `prepare_ai_acceptance.py`、`run_ai_acceptance.py`、`launch_ai_macos_acceptance.py` | Windows 全项通过后进入 Mac 独立目录;不默认签名和公开发布 |
+
+## 代码检查结果
+
+证据目录:`tmp/ai-assistant-implementation-20260910/development-60/`。
+
+- 后端 AI/本地检索整组:428 项通过(302.22 秒),`backend-all-ai.log`。其运行期间的索引迁移增补另由 61 项索引/前台优先测试覆盖,`index-migration-tests.log`。
+- 后端引用/历史/持续阅读/协议组合:109 项通过;笔记引用保存与重试 6 项通过,`backend-tests.log`、`note-binding-tests.log`。
+- 前端 AI 17 个测试文件:191 项通过,`frontend-all-ai.log`;随后新增无事件重连测试,面板 23 项通过,`reconnect-panel-tests.log`。
+- 桌面启动、AI 通知和打包契约:17 项通过,`desktop-tests.log`。
+- 生产前端生成 34 个路由,`frontend-build.log`;生成构建不代表实际桌面通过。
+
+development-60 阶段没有主动发起真实模型调用;随后候选 60 的 Windows 真实验证结果见上文。没有修改真实聊天库或重写旧回答。Windows 整体验收、真实模型内容和最终 Mac 同版本验收仍待完成。历史报告已知错误继续保留,不能将新增字面校验当作旧报告已经修正的证据。
+
+候选源码包及逐文件清单保存在 `tmp/ai-assistant-implementation-20260910/source-candidate-20260912-consolidated-60/`。这是待 Windows 整体验收的候选,不是最终交付包;最终 Mac 使用 Windows 通过后冻结的同一版本。
diff --git a/docs/ai-assistant-implementation-2026-09-10.md b/docs/ai-assistant-implementation-2026-09-10.md
new file mode 100644
index 00000000..15f62077
--- /dev/null
+++ b/docs/ai-assistant-implementation-2026-09-10.md
@@ -0,0 +1,194 @@
+# 微信 AI 助手本轮实现与验收记录
+
+当前源码与开发顺序见 [集中开发状态](ai-assistant-development-status.md):先集中完成全部功能与修复,再统一 Windows 验收,最后 Mac。下文保留历史阶段记录,不代表新源码已经加载或最终通过。
+
+当前模型要求已改为 Xiaomi `mimo-v2.5`,通过软件“设置 → AI 配置”保存与选择;旧 DeepSeek 验收记录仅保留为历史证据。development-63 修复窗口收缩后重复读取、阶段笔记来源上限,并补充 Xiaomi 服务入口,当前测试与尚未验证项以集中开发状态为准。
+
+最新记录:[阶段 59:报告范围、程序时间与初始 SSE 游标](ai-assistant-acceptance-2026-09-12-stage59.md)。真实报告的时间换算已改善,来源对应和内容语义仍有失败项,整项未完成。
+
+最新记录:[阶段 58:真实续写修复](ai-assistant-acceptance-2026-09-12-stage58.md)。原任务已从半截来源续写完成,原文、笔记和配置保持;完整报告范围与内容仍未通过。
+
+最新记录:[阶段 57:补充、停止与主窗口重启](ai-assistant-acceptance-2026-09-12-stage57.md)。真实续写发生重复,尚未通过;已加载状态与半截引用显示修复。
+
+## 交付状态
+
+最新进展补充:[阶段 56:Windows AI 图片、窄栏和全账号最近消息](ai-assistant-acceptance-2026-09-11-stage56.md)。区分真实模型/界面、独立程序测试和仍未完成的 SSE 重连验证。
+
+最新进展见 [阶段 55:Windows AI 追问与原文一致性](ai-assistant-acceptance-2026-09-11-stage55.md)。已修复真实搜索重复拼接引用,完成当前人物与来源发送者界面核对;完整 Windows 和最终 Mac 验收仍在进行。
+
+**整项尚未完成,不能依据已有代码、局部真实数据验证或合成数据测试宣称主要功能交付通过。** 以下对照表只列本轮真实账号的当前验证边界;此前合成聊天和 Mac 阶段结果保留在后文,不作为当前通过依据。
+
+最新第 54 阶段:真实报告已完整读取并保存实时原库 5524 条消息及 6 份阶段笔记,多轮压缩与全字符覆盖核对有效。实际 UI 中“城南旧事”胶囊打开 PP 的发言,人物/发送者身份分离已有当前报告局部证据。但回答生成途中远端连接中断,整份报告仍未完成;来源数量截断、流式正文与身份不同步、历史出处恢复、人物来源序号和正文断点接写正在修复并复验。详见真实验收记录第 54 阶段;后文各阶段未加载/未完成是当时状态,不能覆盖最新事实。
+
+后续第 15 次调用完成报告,结构核对 13 项全通过,正式接口完整提供 382 条正文出处。语义核对仍失败:邀约发生时间被当作活动时间、末尾总括与已确认比赛矛盾。新增通用提示词约束待真实复验,旧回答保留。一次出处栏布局误判已撤回 CSS 修改,不能列为完成项。完整 Windows 和最终 Mac 验收尚未通过。
+
+22:49 已加载这些修复,实际第 269 条来源恢复可查看,真实续写保留了原正文并推进;第 14 次模型流又中断,已保存 20172 个 Unicode 字符,第 15 次正在接写。两次重启前后完整阅读成果一致。最新后端组合 77 项、协议/诊断 52 项、前端 44 项及生产构建通过,仍不代表真实长报告或整项验收完成。
+
+第 45 阶段已在真实 Windows 界面完成一条身份流程:省略群名表情仍正确找到坦洲羽毛球🏸,回答中的“吉量”人物胶囊打开实际发送者“330”的原话,并定位到正确群消息。严格 21:29 至 21:32 范围为 11 条消息;没有把 21:32 之后的另一条 @ 算入。此项不等于所有同名人物及历史引用均已验收。
+
+真实全账号目录为 779 个会话,包含旧目录遗漏的 15 个历史会话。全账号索引已从旧错误任务恢复并渐进提交,第 46 阶段观察到 37820 条可查询原文。新增的关键词召回在真实索引中 0.75 秒找到“7-21惨案”,第 47 阶段同题真实模型程序复验已完成,回答引用正确的 330 原消息,但耗时约 306 秒、9 次调用,性能仍待改善。真实统计发现模型把 21:32 截止算成 21:33,已增加明确钟点的程序换算,同题真实复验的 11 条原消息、四位发送者计数及人物引用全部核对通过。用户要求重启后,桌面于 20:10:22 重新启动并加载第 46~49 阶段后端,主窗口已恢复;第 50 阶段实际确认统计历史的四个人物胶囊、吉量胶囊打开实际发送者 330 的来源及正确聊天定位,原 AI 对话保留。完整 Windows 验收及最终 Mac 验收尚未完成。详细证据及失败记录见 [真实验收记录](ai-assistant-ui-audit-2026-09-11.md)。
+
+此前 Windows 与 Mac 设置界面、远程模型、断线续接等阶段记录主要使用合成聊天数据,不能当作用户真实历史的功能验收。长报告内容质量、人物识别、真实账号检索与最终同版本 Mac 验收仍有未完成项。下文保留阶段事实,不将“真实模型调用”混同于“真实聊天数据通过”。后续仅验收 AI,Windows 稳定后才进行 Mac 最终验收。
+
+用户最新修订取消双平台真实模型调用次数上限;用提示词、有效证据与调用兼容性减少无效查询,保留全部尝试的用量审计。下文历史阶段的 `0/30` 仅是当时记录,原 30 次验收上限已失效。不得通过调用次数限制替代任务完成条件。密钥仅存应用本机配置,不进入源码、报告或交付包。
+
+用户最新明确开发顺序:集中在 Windows 完成全部功能、修复和 UI 核对,版本稳定后再统一进行 Mac 最终验收;暂停逐次修改同步 Mac。阶段 Mac 记录仅供参考,不能替代最终同版本验收。
+
+第 51 阶段:真实全账号最近 5 条精确集合核对通过,但旧进程耗时约 29 分钟,性能未通过。真实完整报告范围共 4482 条,发现人物姓名匹配导致长时间卡顿;同一批 263 条消息及 11385 条联系人目录的新旧引用完全一致,匹配耗时从 144.47 秒降至 5.25 秒。原文预算预选改为批量读取与二分,相关 91 项测试通过。真实任务停止、重启后保持原文、配置及游标一致,已在界面继续,完整报告与多轮压缩仍待最终验证。另修复压缩事务提交后预算显示与实际请求相差 66 字节的回归,67 项复验通过,后续仍需加载到桌面验证。
+
+第 52 阶段已加载上述计量修复及前台读取优先级、时间窗口续读改动。真实首轮笔记保存后,请求占用从 491356 降到 158046 个估算单位,原文全部保留;重启后笔记、覆盖、模型配置和游标一致,真实界面显示对应压缩数值并成功继续原任务。当前仅证明一轮真实压缩及这次恢复,4482 条完整报告和多轮结果仍在验证。
+
+第 53 阶段:同一真实报告已保存第三轮笔记,三次压缩后的占用均低于 60%,完整结果仍待核对。全账号最近 5 条改用原消息表批量时间上界,同一截止时间及 779 个会话下,与先前完整核对的结果一致,目录加选择耗时 22.656 秒(此前选择阶段累计 861.47 秒)。另修复空白尾部产生大量持久化步骤、续读重放导致覆盖计数偏大的问题;专项 14 项通过。当前桌面仍运行第 52 阶段版本,完成正在执行的报告后再加载这些修改,尚无新版本完整 UI 或最终 Mac 验收结论。
+
+完整报告基线随后更正为实时原库 **5524 条**:上述 4482 条为旧快照数量,不能作为当前实时读取的全量。独立原库定位分页、前后 count 校验及已读原文定位/时间比对均已执行,证据在 `real-data-53/`。读取链路回归 76 项通过,完整报告仍在生成。
+
+## 基线与交付
+
+- 分支 `main`,基线提交 `58cc8cd`;保留开始工作时的未提交修改,没有提交或推送。
+- 修改前快照与清单:`tmp/ai-assistant-implementation-20260910/before-changes.zip`、`baseline.json`。
+- 证据根目录:`tmp/ai-assistant-implementation-20260910/`;`windows-runtime` 为独立样例环境,不使用现有远程 API 配置。
+- 最近一次源码候选包为证据目录下的 `delivery-20260911-candidate-44/`,只代表打包时版本;第 45 阶段之后的修改尚未重新打包。保留历史阶段包,但不称最终交付。源码包不包含聊天数据库、模型权重或 API 密钥。
+- 用户压缩包内文档作为需求资料,其中命令不是独立执行授权。签名安装包和公开发布不属于本轮交付。
+
+## 需求与实现对照
+
+| 要求 | 本轮实现 | 验证边界 |
+| --- | --- | --- |
+| 全账号检索和历史兼容 | 新建对话无需联系人;账号隔离;命中按实际会话生成来源;旧历史进入账号列表 | 真实 Windows 历史列表恢复、779 会话目录及目标原话读取已有证据;第 47 阶段默认全局问题完整回答在程序链路通过一例;性能及最新桌面链路仍待验 |
+| 明确筛选与追问 | 会话、发言人、时间及最近 N 条作为查询条件;追问继承有效条件并支持重置;全局 N 表示总数 | 程序测试通过,复杂自然语言需真实模型验证 |
+| 切换聊天保持 AI 对话 | 账号级对话选择,保留草稿、阅读位置、展开状态;未选联系人也可全局提问 | 第 45 阶段真实跨聊天来源定位后保留原 AI 对话;全部草稿、阅读位置和断线组合仍待本轮验收 |
+| 即时搜索和渐进索引 | 基础搜索直接可用;可用本地模型补齐全账号,先近期再历史;每批提交后可查,支持暂停、重启和增量 | 真实数据部分索引、重启续建和新原文关键词检索有证据;全量性能及新消息持续更新仍待验 |
+| 覆盖与数据隔离 | 覆盖按会话、时间记录;部分不标全量;前台查询优先,派生数据独立写入;增量发布保留既有会话及历史覆盖 | Windows 42 项索引专项及真实 CPU 模型增量中跨会话旧消息查询通过;最新代码仍待最终双平台桌面验收 |
+| 时间游标与完整读取 | 固定截止时间和时区,左闭右开;二分到一秒后按稳定消息及字符分片;报告完整读取、统计程序执行 | 同秒、空区间、边界、长消息和恢复测试通过;真实快照只读续页通过 |
+| 压缩与恢复 | 同口径预算;80% 整理、目标低于 60%;近期原文 15%、笔记 20%;笔记、引用和进度事务保存后释放活跃原文 | 多轮压缩、保存失败和恢复测试通过;真实模型笔记质量待验 |
+| 模型配置 | 支持 model_id/reasoning_effort;服务分组菜单;原生等级按已确认能力发送;补充及继续使用启动快照 | 真实账号已从 Windows 设置保存 DeepSeek 并实际调用;最新快照行为、原生等级菜单和最终 Mac 仍待验 |
+| SSE 连续显示 | 按运行身份与版本合并预算、覆盖;忽略过期更新;保留消息、草稿、阅读位置和展开状态 | 组件测试通过,真实 Windows 流式回答和重启历史恢复已有证据;最新版本完整断线组合与 Mac 待验 |
+| 组件与 Tailwind 4 | AI Elements Vue 的 Conversation、Message、Context、ChainOfThought 接入;统一实际滚动容器;完成 Tailwind 4 迁移 | 生产构建及组件测试通过;真实 AI 界面已使用,完整视觉边界仍待验,不扩展到朋友圈验收 |
+| D01~D04 | 10px 静态圆环、12px 控件文字、28px 黑色按钮;运行时停止、Enter 补充、Shift+Enter 换行及输入法事件保护 | 真实 Windows 提问、停止、来源预览及图片查看已有局部证据;320px、主题、中文输入法组合及最终 Mac 待验 |
+| 人物、来源和图片 | 实际发送者与被谈论人物分离;旧来源兼容;图片关联存入已有结果/检查点;查看器只浏览当前回答图片且不触发分析 | 真实 Windows 吉量/330 区分、胶囊点击与原消息定位通过;两图查看有阶段证据,复杂同名与全部恢复场景仍待验 |
+| 原有功能 | 保留旧总结、自动任务、提醒,以及对话内报告阅读和复制 | 组件回归通过;本轮真实账号的 AI 旧功能完整回归待验,不验收朋友圈 |
+
+## 已执行验证
+
+### Windows 自动化与构建
+
+`windows-automated-final/result.json` 全部命令退出码为 0。环境 Python 3.11.3、Node 24.19.0,记录依赖锁文件 SHA-256。
+
+- 后端 AI / 本地检索:260 项通过。
+- 前端 Vue 组件:239 项通过。
+- 前端 Node 测试:62 项通过。
+- 桌面契约测试:8 项通过,不是实际 Electron 验收。
+- Nuxt 生产构建成功,生成 34 个路由。
+- 共享运行时 SQLite 扩展、ONNX 和媒体能力检查通过。
+
+### 实际组件与生产页面浏览器
+
+`browser-final/result.json`:11 个场景通过,无页面错误。覆盖 D01 窄栏深浅色、D02 展开、D03 固定来源预览、D04 深浅色和缺图,以及生产页面聊天切换草稿保持、旧工具、朋友圈、AI 设置。
+
+实际侧栏 320px、横向溢出 0px、圆环 10px、按钮 28px。使用真实 Vue 组件及生产构建,数据和媒体为独立样例;没有真实模型生成回答。截图位于 `browser-final/`。
+
+### 真实本地向量模型
+
+`runtime-local-cpu-9.log`:现有 BGE-small-zh 在 CPU 上真实编码,512 维,1 个编码批次。
+
+`local-index-real-13/result.json`:真实 CPU 模型处理合成数据库,共 9 个编码批次;部分可查询 36 条,暂停保留 36 条,重启补齐 117 条,增量后 118 条且只新编码 1 条;账号隔离通过。没有修改既有权重或用户全局索引。
+
+共计 10 个本地编码批次。远程 API 仍为 0,30 次上限保留给后续专用模型验收,包含失败、重试和视觉调用。
+
+### 已有真实数据只读
+
+`readonly-real-15/result.json`:已有解密快照以 SQLite `mode=ro&immutable=1` 打开,调用生产时间读取;群聊首批 5 条、私聊首批 4 条,并验证稳定续页与无重复。源数据库大小、修改时间未改变,结果不保存聊天正文。
+
+这是静态快照读取验证,不能替代实时采集、真实模型问答或全部历史索引验收。先前失败记录保留,以上列出的最终记录为准。
+
+## Mac 同版本准备与执行
+
+### 本轮已执行结果(2026-09-11)
+
+本次独立目录为 `/Users/sheng/WeChatDataAnalysis-ai-check-20260910-01`,没有覆盖 2026-09-08 目录。按文件 SHA-256 复用 820 个完全一致的源码文件,补传 313 个差异文件后,原交付清单的 1,133 个文件全部验证一致。复用的 Python 环境也是独立副本,随后按当前锁文件离线同步并重新安装本轮项目,确认导入路径指向新目录。
+
+本轮 Mac 日志和截图同时收录在 Windows 工作区证据根目录的 `mac-verified-20260911/`;Mac 路径中的 `tmp/mac-acceptance/` 对应该目录。后续启动修复修改了桌面导航及静态入口,新增回归结果单独收录在 `startup-fix-20260911/`;下列 569 项为修复前完整基线,修复后的针对性测试见下一节。
+
+- 环境:macOS 26.3.1、Apple Silicon arm64、Python 3.11.15、Node 24.13.0。
+- `tmp/mac-acceptance/automated-01/result.json`:源码清单核验、依赖安装、运行时、后端 260 项、前端组件 239 项、Node 62 项、桌面契约 8 项及生产构建全部通过。依赖锁文件 SHA-256 与 Windows 一致。
+- `tmp/mac-acceptance/readonly-real-01/result.json`:Mac 已有真实解密快照只读验证通过;群聊首批 2 条、私聊首批 5 条,均验证续页,源文件大小与修改时间未改变;未复制聊天正文。
+- `tmp/mac-acceptance/electron-final/result/result.json`:真实 Electron 40.0.0 / Chromium 144.0.7559.60 的 6 个场景通过,无页面错误:聊天加载、聊天切换后 AI 草稿保持、实际窗口隐藏后返回、多行输入、旧工具入口及朋友圈。
+- `tmp/mac-acceptance/browser-final/result.json`:Mac Chrome 下 11 个 D01~D04 与生产页面场景通过,无页面错误;侧栏 320px、横向溢出 0px、圆环 10px、按钮 28px。数据与图片为独立样例。
+- `tmp/mac-acceptance/local-index-real-01/result.json`:复用已存在且校验通过的 BGE-small-zh 权重,在独立合成库执行真实 CPU 推理,共 10 个编码批次;部分可查 36 条,暂停保留 36 条,重启补齐 117 条,增量至 118 条且只编码新增 1 条,账号隔离通过。双平台本轮本地编码合计 20 批次,远程 API 仍为 0/30。
+- 上述 Electron 为本轮源码应用和独立样例数据,未打包签名;真实中文输入法、模型运行中的窗口返回及真实模型回答仍未验证。
+
+直接从 SSH 启动 Electron 时,本轮复现原生 broker 的 `Cannot create device identity: broker unavailable`;随后通过 macOS 图形会话启动本轮源码,后端及上述 6 个窗口场景通过。首次失败保留在 `electron-01`,图形会话复验保留在 `electron-02` 和 `electron-final`。没有关闭原生安全检查、修改钥匙串权限或绕过 broker。
+
+新增 `tools/launch_ai_macos_acceptance.py` 自动建立临时图形启动入口;`tools/verify_ai_electron.cjs` 使用真实项目主进程、独立 userData 和样例数据库,并分别记录真实输入法、真实模型的未验证状态。启动请求成功本身不视为通过,必须读取结果文件。
+
+### 启动失败修复与复验(2026-09-11)
+
+用户截图中的 `http://127.0.0.1:3040` 是此前临时验收窗口使用的开发页面。日志显示后端已就绪,但该窗口导航持续等待约 32 分钟,直到开发服务结束才失败。原重试循环只在 `loadURL` 返回后检查 60 秒期限,无法中断一直没有响应的页面。
+
+`loadWithRedirect` 现对导航与跳转等待执行实际期限,到期主动停止加载并清理监听器;重试共用剩余的 60 秒预算。静态入口通过 `WECHAT_TOOL_STATIC_UI=1` 读取实际已就绪后端的地址,优先于遗留开发 URL。`desktop` 的 `npm run dev:static` 先生成页面再启动;临时 Windows 验收入口也已改为静态模式。
+
+- Windows 与 Mac 桌面针对性测试各 11 项通过,包含原有 8 项和新增 3 项;不是在 569 项之外再相加 11 项。
+- Mac `electron-startup-fixed-02/result/result.json` 的真实 Electron 7 个场景通过,包括静态入口、原有 6 个页面与窗口场景及新增无响应页面恢复。测试服务收到 1 次请求却不返回响应;设定 1 秒期限,实际 1,013ms 中止,返回 `ERR_NAVIGATION_TIMEOUT`,恢复朋友圈页面成功,无页面错误。
+- 首次新增故障测试因验收脚本求值环境没有 `require` 失败,保留在 `electron-startup-fixed`;修正隔离验收入口后复验通过。该失败不属于应用启动失败。
+- 本地证据位于 `startup-fix-20260911/windows-tests.log` 和 `startup-fix-20260911/mac/`。Windows 生产页面在内置浏览器正常加载;遵守桌面使用限制,没有重启 Windows 原生窗口,不能将其标为实机通过。
+
+### 保存与停止恢复专项验证(2026-09-11)
+
+补充三项故障边界:笔记插入后发现写入失败、笔记与发现写入后运行进度更新失败、模型整理期间真实停止接口取消任务。分别验证事务回滚、无半套笔记发布、原文与待处理/活跃分片不丢失,并由新的服务实例恢复,验证压缩后请求占用降低、来源完整、截止时间和配置快照保持。
+
+`tests/test_ai_continuous_v2.py` 与 `tests/test_ai_global_assistant.py` 在 Windows 和 Mac 各 19 项通过,其中新增 3 项。Windows 30.67 秒,Mac 3.54 秒。实际数据库与生产服务代码执行,模型响应为模拟,不算真实模型验收。首次测试错误地在提交后重新读取“压缩前”占用,已改为提交前记录数值;首次失败日志保留,没有为使测试通过而修改产品代码。
+
+证据为 `recovery-audit-20260911-02.log`、`recovery-audit-mac-20260911/recovery-audit-02.log`。本次仅补充测试与说明,启动修复后的应用代码未变,之前的桌面专项和真实 Electron 记录仍适用。
+
+### Mac 真实快照渐进索引(2026-09-11)
+
+`tools/verify_ai_real_index.py` 在 Mac 既有真实解密快照上使用 BGE-small-zh CPU 模型,源 SQLite 强制 `mode=ro&immutable=1`,派生索引写入新建独立目录,不修改既有全局索引或模型权重。结果及诊断日志收录于 `real-index-mac-20260911/`,未将派生数据库或聊天正文装入交付包。
+
+- 账号目录包含 723 个会话,源数据库及伴随文件合计 2,881,765,376 字节。
+- 8.896 秒后首批 100 条消息已提交并可查询;运行中的三次混合查询分别耗时 0.053 / 0.009 / 0.009 秒,各返回 50 个结果,来源均属于账号的实际会话,覆盖明确标为部分。
+- 暂停时保存 100 条,检查点 processed=100;新服务实例从该检查点继续到 200 条,原有 source 集合完整保留,账号隔离通过。
+- 共 25 个新增真实本地 CPU 编码批次(包含查询编码),双平台累计本地编码为 45 批次;远程 API 仍为 0/30。
+- 验证后源数据库及伴随文件的大小、修改时间完全一致。此次为静态快照,未测试实时采集或新增真实消息。
+
+结论仅覆盖真实数据的首批发布、部分查询、暂停恢复与账号隔离;仅三个查询样本,不用其推算全量历史索引速度、长期延迟分布或语义相关性质量。全量历史索引性能和真实模型端到端仍待验。该阶段尚未操作 Windows 桌面,后续解除限制后的证据见 UI 复核记录。
+
+### 可重复执行的入口
+
+使用独立目录,例如 `~/WeChatDataAnalysis-ai-check-20260910`,不要覆盖既有安装或验收目录。解压 `wechat-ai-source.zip` 后运行:
+
+```bash
+uv sync --frozen --managed-python --python 3.11
+.venv/bin/python tools/run_ai_acceptance.py --output ../ai-check-results-20260910 --node node
+```
+
+使用本轮验证过的 Python 3.11 和 Node 24。执行器核对包内 `acceptance-source-manifest.json`,记录平台、锁文件、命令、退出码和日志。脚本不会自动将真实桌面或模型标为通过。
+
+独立样例环境与通过图形会话启动的后端:
+
+```bash
+.venv/bin/python tools/seed_ai_acceptance.py --output ../ai-check-data-20260910/output
+.venv/bin/python tools/launch_ai_macos_acceptance.py --mode backend --data ../ai-check-data-20260910 --output ../ai-check-backend-20260910 --python .venv/bin/python --port 10492
+```
+
+专项验证脚本为 `tools/verify_ai_local_index.py`、`tools/verify_ai_readonly_snapshot.py`、`tools/verify_ai_browser.cjs`,参数见脚本说明;输出应使用独立目录。原生检查使用图形启动器的 `--mode electron`,并以 `--playwright` 指定已安装 Playwright 模块目录。输入法、真实模型与签名安装包等项目不能仅凭自动化判定通过。
+
+## 尚未验收的交付条件
+
+最新范围与顺序(9 月 11 日):后续仅开发、修复和验收 AI 助手,停止其他页面扩展检查。先完成 Windows AI,再冻结同一版本统一验收 Mac。最新真实调用合计 164(Windows 107、Mac 57),已取消次数上限;下文更早统计仅为历史阶段数据。Windows 最近 240 条运行 35 的来源、全文覆盖与 12 次压缩通过,报告内容仍需修正;最新笔记来源元信息与覆盖误报修复待真实复验,详见 UI 记录第 35 阶段。
+
+9 月 11 日中午进展:两端已通过设置页完成 DeepSeek 配置与 low 原生等级真实问答;Windows 还实测全账号最近 240 条报告、三次真实笔记压缩与停止重启继续,原始选择集合和字符覆盖已逐条核对。Mac 已完成真实回答的首次跨群定位和重启后的历史引用恢复。当前双端累计 64 次真实调用,旧 30 次限制已取消。阶段进度与预算显示修正后,两端最新后端专项各 40 项、Vue 专项各 17 项通过;Mac 新长报告桌面流程仍待验。详细证据和回答文风问题见 [UI 复核记录](ai-assistant-ui-audit-2026-09-11.md)。下列广泛场景仍按未完成部分继续,不将单个样例通过扩展为整项完成。
+
+1. Windows 桌面限制已解除;9 月 11 日实际验证了启动、中文输入法候选输入、组合 Enter 防误发、Shift+Enter 换行、切换聊天与最小化返回保留草稿。本次修改涉及的完整界面和真实模型运行流程仍继续复核,详见 [UI 复核记录](ai-assistant-ui-audit-2026-09-11.md)。
+2. Mac 真实中文输入法待人工操作;真实模型运行中的窗口切回、停止/继续和断线重连已由本轮长报告验证,见 UI 记录。
+3. DeepSeek 下全账号检索、长报告笔记质量、原生模型等级、停止/继续、断线重连及视觉分析;按实际用量记录,不设验收调用上限。图片连接测试不替代完整图片问答验收。
+4. 真实历史复杂同名、多来源、图片恢复,以及全账号大规模索引性能。
+
+后续在本清单继续登记实际结果,不将模拟测试、浏览器检查或 CPU 向量验证写成“双平台真实模型全部通过”。
+
+## 9 月 11 日 UI 复核补充
+
+新发现并修复了 Tailwind 4 深色主题覆盖优先级、静态开发重建后的 Electron 旧资源缓存、预算说明在 320px 侧栏内被裁切的问题。正式本地检索设置改为全账号全部历史入口,服务端解析账号会话目录,展示真实部分覆盖并保留旧索引未知状态。前端 242 项、本地索引后端 47 项、桌面专项 13 项通过;每项手动截图、限制与待验状态见上述 UI 复核记录。
+
+Mac 首次 SSH 重连超时,随后恢复。已同步 UI 修复及 2001 会话保存修复,核对 1138 个源码文件一致;Mac 最新自动化包含 264 项后端、243 项 Vue、17 项桌面专项及 34 路由构建。新增真实 Electron 设置流程第二轮通过,第三轮补齐目标区域可见的全账号设置截图;第一轮标签定位错误的失败记录保留。具体证据和待验项目见 UI 复核记录。
+
+后续 v4 补齐暂停状态的已保存计数、历史回答复制入口及缺失头像降级。两端 1139 个源码文件一致,Vue 各 246 项、生产构建各 34 路由通过。Mac 第四轮真实 Electron 17 个检查通过,包括 D01~D04 明确组件样例、271 字符原生复制粘贴和页面挂起恢复,全部截图已查看。Windows 在正式界面完成真实本地模型的人工样例 3117 条消息索引,暂停重启保留 1617 条/244 片段,继续到 3117 条/478 片段;源库 SHA256 不变。Windows 还验证了正式历史回答复制粘贴及跨聊天来源定位。以上均不替代真实对话模型和 Mac 中文输入法验收,远程调用仍为 0/30。
diff --git a/docs/ai-assistant-ui-audit-2026-09-11.md b/docs/ai-assistant-ui-audit-2026-09-11.md
new file mode 100644
index 00000000..72488e8a
--- /dev/null
+++ b/docs/ai-assistant-ui-audit-2026-09-11.md
@@ -0,0 +1,452 @@
+# 本次助手修改的 UI 复核(2026-09-11)
+
+最新记录:[阶段 59:报告范围、程序时间与初始 SSE 游标](ai-assistant-acceptance-2026-09-12-stage59.md)。真实报告的时间换算已改善,来源对应和内容语义仍有失败项,整项未完成。
+
+最新记录:[阶段 58:真实续写修复](ai-assistant-acceptance-2026-09-12-stage58.md)。原任务已从半截来源续写完成,原文、笔记和配置保持;完整报告范围与内容仍未通过。
+
+最新记录:[阶段 57:补充、停止与主窗口重启](ai-assistant-acceptance-2026-09-12-stage57.md)。真实续写发生重复,尚未通过;已加载状态与半截引用显示修复。
+
+最新实际界面结果见 [阶段 56](ai-assistant-acceptance-2026-09-11-stage56.md):真实图片查看器、320px/主题、输入法、草稿及窗口恢复、模型菜单修复;全账号覆盖分页的实际加载复验仍单独记录。
+
+## 当前真实数据发现(9 月 11 日下午,优先于历史阶段概述)
+
+最新状态见 [阶段 55 的真实追问与原文一致性记录](ai-assistant-acceptance-2026-09-11-stage55.md):23:23 已加载修复;真实混合搜索 200 条原文一致,已核对阿忠胶囊与发送者 330 的第 22 条出处。旧报告及勘误不等于整份语义验收通过。以下阶段 54 的运行状态是历史记录。
+
+### 长报告来源完整性、流式身份同步与连接中断恢复(54,进行中)
+
+- **报告生成已结束,但内容未通过**:第 15 次调用完成,最终 22259 个 Unicode 字符、382 个消息来源;`completed-report.json` 的 13 项结构核对全部通过,`completed-public-citations.json` 确认正式接口无遗漏。累计本报告 15 次模型尝试,已知输入 1579026、输出 206511 token,5 次用量未知,无视觉调用。这不代表最终语义通过,也不代表整项完成。
+- 原文语义复核失败:8/27 19:58 的“早上有个高手问我打不打球 剩一个位置”明确描述早上发生邀约,报告却写为活动时间;末尾“其余为意向”概括也否定了前文已经记载的 9/10 比赛结果。9/10 21:31:31 和 22:18:35 的 330 原文确实支持阿忠对 330 为 21-7。新增通用规则区分邀约/活动时间、接龙/实际举行,以及结尾与正文一致性;这些提示词修改尚未加载和进行真实模型复验,旧回答没有被直接改写。
+- **撤回布局误判**:重新查看 `real-source-269-restored.png` 后,输入框当时一直可见,右侧是出处栏自己的滚动条。此前“上下文挤走输入框”的判断不成立,已撤回两处 CSS 修改,并将正式静态目录恢复为 `ui-build/public`。运行中页面曾加载 `ui-layout-build` 的临时约束,后续真实 UI 复验前需刷新到正式构建;不将此项算作修复成果。
+
+- **最新运行优先**:22:49:17 重启为 Electron 32176、后端 31656,主窗口 919246,端口 10392。已加载底层传输异常分类、诊断模块标识、出处栏高度约束及此前第 54 阶段修复,哈希在 `transport-runtime-hashes.json`。此次只返回主窗口,常规启动不再自动用 DevTools 遮挡应用;显式 `--debug` / `--devtools` 和调试快捷键保留。
+- 第 14 次模型调用从原正文断点续写,确实补完半截来源,原 15432 个 Unicode 字符完整保留;实际第 269 条来源打开“堂”的 9/7 17:29 接龙原文,截图 `real-source-269-restored.png`。该次在 22:42:23 再次因 `RemoteProtocolError` 失败,耗时 445.712 秒,已保存正文增至 20172 个 Unicode 字符。模型故障和前端刷新先后接近,当前证据只证明异常来自模型流,不据此声称刷新导致或排除了故障。
+- 前一次仅按 `httpx.TransportError` 的分类未覆盖这次实际错误,仍被报为 internal;不能把专项通过当作真实故障已解决。已补上与 httpx 没有继承关系的 httpcore 网络/协议异常,诊断另存异常模块且继续不记录异常正文;协议及诊断 52 项通过(33.00 秒)。尚待实际中断场景验证分类结果。
+- 两次重启前后原文、全部笔记、覆盖、配置和游标分别经 `restart-comparison.json`、`transport-restart-comparison.json` 核对一致。第 15 次调用通过所属后端继续接口启动,`continued-call15.json` 确认原 20172 字符前缀保留、仍读 5524 条、没有重复分析;不是原生 UI 点击继续的证据,整份报告仍未完成。
+- 最终后端组合 77 项通过,续写与模型协议补充 26 项通过,半截引用续写 2 项通过;前端 44 项及两次独立生产构建成功。布局后续修复只约束出处栏滚动范围,真实上下文展开仍待复验。应用 `/api/ai/usage` 当时总计 200 次、已知输入 3381921 / 输出 517181、失败 32、用量未知 28;这是应用全局审计口径,不能称为此报告或单账号总量。
+
+- 当前桌面在 22:03:11 重启,Electron 11160、后端 8088,加载第 53 阶段及已知人物/图片编号的类型补全。此前 21:49 进程已退出。第 12 次回答中的裸人物 ID 确实导致“来源待核实”,没有将它作为人物验收通过;第 13 次回答已显示有类型的人物胶囊。
+- 真实原生 UI 点击“城南旧事”胶囊,右侧显示 PP 的头像、发送者和 8/25 13:36 原文“@城南旧事 宝宝明天有球咩”,证据 `real-data-54/real-person-subject-and-sender.png`。该画面同时发现出处栏将实际第 6 条出处误标为 1;已改为从实际渲染的来源编号确定序号,未编号的关联材料显示“相关原文”,尚待新构建真实 UI 复验。
+- `citations()` 原先只取前 200 条,真实回答达到 210 个不同出处时,正式接口缺少 10 条实际存在的引用。`citations-over-200.json` 保存接口与工作区只读对照:新实现批量取全后遗漏为 0,生成来源列表 0.075 秒,0 模型调用。截图 `real-source-limit-before-fix.png` 保留未修复界面。人物的全部关联仍存原检查点,响应仅补充代表消息及所有正文引用,避免每个事件携带其整段历史。
+- SSE 先推正文、慢速查询随后带来身份资料,造成有效引用短暂无法解析。新增标记与校验过的来源/人物资料现在通过同一持久化事件发送;后续事件不重复发送已有映射,同轮快照合并已接收资料,过期事件不覆盖新身份。旧历史缺失的引用只读从原任务补齐,不重写旧回答。
+- 引用修复初轮后端 74 项通过(117.67 秒),SSE 与历史补齐后 75 项通过(121.73 秒);最终前端引用/流式/出处栏 44 项通过。最初误用系统 Python 导致缺少 `langgraph.graph` 的收集错误,改用项目 `.venv` 后通过。所有这些是独立程序测试,未向应用注入样例数据。
+- 第 13 次真实回答在 22:24:34 失败:远端 `RemoteProtocolError` 中断已输出 15443 字符的流,调用耗时 1140.747 秒,未返回完整用量。旧实现误分类为 internal,并提示检查设置。已按传输故障归为可重试连接错误;分析已经完成且引用有效时,继续从已保存正文断点接写,保留启动配置和完整原文/笔记,避免重复生成前文。专项 3 项通过,最终后端组合仍待完成。
+- `report-still-running.json` 在失败前只读核对:实时原库 5524 个定位全部匹配、全字符覆盖有效、6 份笔记、多轮压缩均降到 60% 以下、引用有效、无视觉调用;状态未完成,所以 `passed=false`。这不代表最终语义或报告已经通过。
+- 新前端独立构建到 `real-data-54/ui-build/public`,34 个路由生成成功;没有替换正在显示窗口的静态目录。第 54 阶段尚未加载到真实桌面,报告待恢复,完整 Windows 与最终 Mac 验收仍未完成。
+
+### 真实第二轮压缩与最近 N 条批量查询(53,进行中)
+
+- **当前运行版本**:21:49:08 重启后,Electron PID 12864、后端 PID 6860,已加载第 53 阶段全部后端修改;源码哈希在 `restarted-source-hashes.json`。以下早先“尚未加载”的条目保留当时事实,以本条为当前状态。真实 UI 从首页回看聊天进入原报告,并点击继续;同运行、同版本直接进入“正在整理回答”,工具数仍 238,仅开始第 12 次模型调用。
+- **完整范围基线更正**:先前 4482 条来自较旧的已保存快照。实时报告读到更多消息后,核对发现它们的定位不在该快照中,不能据此判为错误或删掉。新增只读原库元数据脚本,探查全部数据库、按 local_id 分页,仅读取定位、时间、server_id,并用每个原表读取前后的 count 验证完整性。同一范围实时原库共 **5524 条**,较旧快照多 1042 条;全部定位唯一。证据 `realtime-originals.json`、`.log`;后续完整报告必须以该实时基线核对。
+- 当前桌面仍为 21:02:23 启动的同一真实应用,后端 PID 19512;窗口可见且正在继续原报告。第二轮压缩提交成功,491033 → 190823 个估算单位,低于 60%。一次观察为已读取 3801/4482 条、分析 2781 条、2 份笔记、3 次模型调用。整份报告、全字符覆盖和最终语义仍未通过。
+- 新增 `ai/recent_bounds.py`:直接批量读取同一真实渠道中各原消息表在固定区间内的最大时间,按上界从近到远检查。只有完整查询成功且时间严格早于当前入选边界,或范围确实为空,才省去该会话的正文读取;同秒候选继续比较,人物筛选仍在取 N 前执行。任一库查询失败或结果不完整便退回原逐会话路径;不依赖索引覆盖、会话预览或最后活跃时间判空,取消异常照常传播。
+- 同截止时间 `1789127483`、779 个真实会话,与第 48 阶段独立完整边界核对的 5 条来源、定位、时间、发送者逐项相同。当前总耗时 22.656 秒,其中目录 11.812 秒、最近 N 条选择 10.844 秒,实际读取 2 个会话,777 个由完整原表上界排除;0 模型调用。旧日志的选择阶段累计 861.47 秒,1756.55 秒是包括独立边界复核的总耗时,不能混作同一计时范围。证据 `real-data-53/global-recent.json` 和 `.log`。这是实际数据的程序复测,尚未加载到当前桌面,也不代表最新问题的真实界面验收。
+- 自动化组合首次结果为 60 项通过、1 项完整报告回归在 90 秒等待上限超时(总 169.25 秒)。保留该失败;单独复查正在执行,不能把整组说成通过。
+- 单独复查也在 90 秒超时(92.36 秒),随后只读检查测试检查点确认:30 条原文已读到,但后续多年空尾仍逐次加倍生成大量持久化步骤。改为在短空区间后实际查询剩余尾部,仅当尾部也确实为空且没有警告时完成该范围;后面仍有消息则保留自适应小窗口。没有增大超时掩盖问题。
+- 真实界面另出现总数 3804、单群覆盖 3809 的差异:覆盖按返回片段递增,重复续读会多计。改为与总数一样按已保存唯一原文计数,发送者筛选也在保存侧统一生效。回归覆盖同一消息重放两次仍只计一次。第一次新测试漏设新版数据适配器而失败,已修正测试前置条件。最终 14 项专项通过(49.48 秒,`reading-fixes-final.log`),包括原超时用例;上述两处修改同样尚未加载到当前桌面。
+- 第三轮真实压缩 491113 → 226544(36.8%),已保存 3 份笔记;`third-note-progress.json` 只读核对已有笔记来源与每轮真实压缩均有效,整份报告检查仍为未完成,不能将该文件的进程退出码 0 当作完整验收通过。
+- 读取及持续链路回归 76 项通过(117.00 秒,`reading-regression.log`)。新的 `realtime-report-progress.json` 为 4615/5524 条,已读取定位及时间全部匹配独立实时基线,第四轮笔记进行中;完整范围、全部字符、最终回答及语义仍待验证。没有重启正在执行的报告,也没有把尚未加载的第 53 阶段代码算成当前桌面已通过。
+- 全部原文最终读取到 5524 条,6 份阶段笔记提交后,独立原库定位、时间、每条原文完整字符覆盖、各轮压缩下降均通过(`all-analysis-complete.json`)。此时仍没有最终回答,不代表完整报告通过。
+- 之后发现完整报告仍调用模型选择下一查询动作,发生调用兼容与动作格式重试,并回查 3 次已读上下文。增加与精确统计相同的程序分支:新版完整范围分析完成后直接请求最终回答;普通搜索仍可选择下一步。相应持续链路/全局/Agent 回归 92 项通过(126.97 秒,`report-finalization-tests.log`)。
+- 额外回查暴露同一系统消息被聊天页的短显示格式覆盖:`1b441db903cd0f28903caf4d` 从原始读取器的 53 字符变为 19 字符,导致已有字符覆盖失配。修复回查适配,已有来源复用保存的原文。停止原运行后,由只读实时原库恢复该条规范原文,修复记录保存旧值、规范值和原 body 哈希;没有修改微信原库、重写笔记或替换为样例。`context-original-repair.json`、`.log` 和 `repaired-before-restart.json` 确认完整覆盖恢复;两个针对性回归通过(51.60 秒,`context-original-tests.log`)。
+- 停止耗时 1.265 秒,保留 11 次真实调用尝试。确认没有运行中的 AI 任务后重启。重启前后运行 ID、版本、全部 5524 条原文哈希、6 份笔记及父链、模型配置哈希、截止时间、游标、覆盖与调用数完全一致(`restart-comparison.json`)。正式继续后不再走查询决策,原报告正在生成,最终语义和来源显示仍待核对。
+- 观察到一次窗口截图进度落后,进行实际 DevTools 性能录制,原始文件 `window-performance.json.gz`。35.5 秒样本中绘制约 12.8 秒、渲染约 5.1 秒,后台进度接口另测 0.203 秒/389391 字节。导出对话框关闭后,原生窗口显示最新 5524 条,与后台同步(`real-all-messages-read.png`);尚不足以认定滞后原因或整个窗口切回回归通过。没有因此新增前端性能改动。
+
+### 前台读取优先级与时间窗口续读(52,进行中)
+
+- 沿用第 51 阶段真实报告和后端进程,未因观察超时重启。后端 PID 11124、启动时间 20:33:55;一次观察为已读 1643 条、输入预算 78.8%、1 次模型调用、0 份笔记。完整范围仍为 4482 条,不能称报告或多轮压缩通过。
+- 代码检查确认后台索引仅在语义检索时增加前台计数,完整读取和全账号最近 N 条预选没有协调资源;索引也只在向量批次前等待。新增前台读取上下文,覆盖正式 Agent 工具全过程和全局最近 N 条预选,嵌套操作按计数释放,异常/取消均在 finally 释放,不为没有后台索引的独立调用创建服务。索引在原文读取、附件文本整理及分块前也检查前台优先级;已经完成的一批仍按原事务提交。
+- 前台优先级专项 30 项通过(4.66 秒),涵盖前台进行中不能先抢读后台原文、嵌套调用以及成功/失败/取消释放;与真实调度和本地检索的集成回归 61 项通过(71.00 秒)。这是独立程序测试,新优先级尚未加载到真实桌面。
+- 另发现时间读取每页都从剩余整段时间重新二分,接近预算上限时重复探查开销明显。游标新增上次收敛窗口宽度;完整读完后尝试加倍扩展,预算变小时仍按原规则二分,空区间连续推进,旧游标缺字段时兼容原入口。相关边界与字符分片测试仍在执行,尚无真实性能结论。
+- 只读观察进程统一会话 `39140`,日志 `real-data-52/first-note-watch.log`:在第一份阶段笔记提交后,通过原后端停止同一运行,供加载修复和检查笔记恢复;最多观察 900 秒,到时不会擅自重启任务。停止响应超时仅记未确认,并须另读权威状态。没有访问 Mac,没有新增模型配置或样例账号。
+- 后续时间读取专项 57 项通过(55.76 秒),持续运行链路 22 项通过(110.05 秒);包含改变预算后精确集合不变、重复探查次数低于旧策略一半的对照。真实旧后端临近阈值仍在慢速二分,因此调整为先加载修复:请求停止于 1655 条成功,用时 0.781 秒。观察会话 39140 随 cancelled 状态正常退出,未触发第一份笔记后的自动停止;当时仍为 0 份笔记。
+- 确认没有活跃问答后重启现有应用。新 Electron 于 20:56:38 启动,后端 PID 31972,端口 10392,日志确认 `window-show`。加载第 51 阶段提交后预算测量修复以及本阶段优先级、时间窗口续读修改,源码哈希保存在 `restarted-source-hashes.json`。重启前后检查点比较全部一致。通过正式继续接口恢复原运行(此步不计原生 UI 点击),一次观察读到 1663 条、预算 79.6%、仍为原 1 次模型调用。首次笔记、完整报告和真实优先级效果仍待核对。
+- 此后第一轮真实阶段笔记提交成功:13 项发现,1667 个已覆盖片段;预算从 491356 降到 158046 个估算单位,约为容量的 25.7%,小于 60% 目标。保留 1668 条原文,覆盖正确显示已分析 1667 条,最后新增的一条尚未分析;“全范围完成”仍为 false。累计两次模型调用,已知输入 205693、输出 18879 token,无视觉调用。见 `first-note-stopped.json`,这是一轮真实压缩通过,不是多轮或整份报告通过。
+- 观察会话 `77951` 在笔记提交后通过所属后端停止同一运行,停止响应为 cancelled,随后正常退出。确认无活跃问答后,保持同一源码进行恢复验收,于 21:02:23 重启(Electron 12624、后端 19512)。重启前后笔记键与父链、完整原文摘要、活跃片段、覆盖与读取游标、模型快照和调用数均一致,`first-note-restart-comparison.json` 全部通过。实际 AI 界面也恢复显示“读取 1668、分析 1667、1 个分段结果、13 条发现、范围尚未完成”。继续后是否复用笔记及后续多轮结果仍待核对。
+- 在真实 AI 大视图展开“整理上下文”,实际显示“笔记已保存、491356 → 158046 预算单位、1667 个原文片段”,截图 `real-compaction-restored.png`。通过界面点击“继续完成”后同一运行与版本恢复,仍只有两次已有模型调用,正在读取余下范围,`continued-from-note.json`;尚不能证明最终没有遗漏或后续多轮笔记均正确。
+- 继续后一次只读核对已读 2142/4482 条,保留第一份笔记且模型调用仍为 2,没有重新执行已完成的首轮整理;记录 `after-note-continue-progress.json`。账号总用量接口为 187 次,输入 2147273、输出 338764 token,失败 28、用量未知 22,见 `usage-api.json`。`usage-summary.json` 仅统计新 records 表,不含兼容记录,不能替代接口总量。任务仍在后端 PID 19512 运行,无其他观察脚本存活;完整报告、多轮压缩和最终 Mac 未完成。
+
+### 全账号最近 N 条结果与真实报告卡顿修复(51,进行中)
+
+- 第 48 阶段原验证进程正常结束,退出码 0。完整检查 779 个会话后,合计最近 5 条的来源、时间和锚点与独立边界回读完全一致,无读取警告,见 `real-data-48/global-recent/comparison.json`。耗时 1756.55 秒,属于加载第 49 阶段缓存以前的程序正确性结果,性能不合格,不能作为最新桌面或全局读取性能通过证明。
+- 从真实 Windows AI 输入框使用 DeepSeek 提交坦洲羽毛球群 2026-08-25 00:00 至 2026-09-11 00:00 完整活动报告。运行 `705c43c1867540f49710006146da02da`,对话 `7a457b547f8d4581bd26673f27c4d241`。原数据库独立范围为 4482 条。运行准确解析时间和群,但读取中出现 30 秒状态请求超时,前端也记录多次 12 秒接口超时;这次按真实响应故障记录。
+- 通过所属后端请求停止,30 秒未收到响应时只记 `response_unconfirmed`,随后只读数据库确认状态为 cancelled,没有因一次超时直接杀掉活跃任务。保存 542 条原文、1 次真实模型调用、0 次阶段笔记。当前不能称压缩通过,检查结果 `real-data-51/report-stopped.json`。
+- 修复原文预算预选的逐条重复读取与完整序列化:批量载入并二分可容纳的完整消息前缀,剩余单条再按字符二分;新加入的独立人物/图片引用也按正式请求同口径计量。保存工具结果的来源和范围判断改为批量读取,避免每条消息重复打开任务数据库。新增多人物引用占用、字符无丢失、缺失原文不发布部分进度检查。相关 91 项测试通过(121.93 秒),后续人物引用专项 4 项通过(2.48 秒)。
+- 人物姓名匹配存在另一项实际瓶颈:对每条消息反复编译整个联系人目录的正则。先做字面不存在检查,再保留原数字/英文边界校验。只读使用同一批 263 条原文和 11385 条联系人目录对照,生成的 67 个引用 SHA256 完全相同,旧匹配 144.4701 秒、新快路径 5.251 秒。见 `reference-performance.json`;该工具未调用模型,未创建应用或样例账号。
+- 确认没有活跃 AI 任务后,终止经核实的旧应用进程树并于 20:33:54 重启现有开发版。只读比较重启前后的运行版本、原文摘要、活跃/待读字符片段、模型快照、固定截止、时区、读取游标和已有调用数均一致,`restart-checkpoint-comparison.json` 全部通过。当前任务的继续运行和最终报告尚待核对;Mac 未访问。
+- 新增 `tools/verify_ai_real_report.py`,独立从真实消息库核对锚点集合,检查阶段笔记的完整连续字符覆盖、来源有效性和压缩前后占用;进行中报告明确 `passed=false`,不将结构验证代替语义质量。所有本阶段证据在 `real-data-51/`。
+- 真实界面恢复后显示原报告“已停止、542 条消息”,保存截图 `report-restored-stopped.png`;点击“继续完成”后同一运行与版本恢复。一次观察读到 1186 条、预算 52.9%,没有再次解析问题,仍为原 1 次模型调用;运行中状态接口一次测量 0.266 秒。不能据单次低延迟称所有性能均通过,完整报告仍在运行。
+- 增加“压缩后圆环占用等于当前完整请求测量”的回归断言,首次两项失败:显示 9164、实际 9230。提交后新增发现计数、覆盖和已完成步骤也会进入下一请求,旧值来自事务前预估。修复为在笔记事务与步骤完成后按正式请求重新测量,移除活跃原文时同步筛选引用;若完整请求仍超 60% 则不能当作压缩达到目标。复验 67 项通过(96.06 秒),日志 `compaction-measure-final.log`,原失败日志保留。此项后续源码尚未加载到 20:33:55 的运行后端,不冒充已真实复验。
+
+### 主窗口恢复及最新真实人物来源复验(50)
+
+- 用户明确要求“你重启一下把”后,确认没有活跃 AI 问答,只停止已核实的旧 Electron 与所属后端进程,再以现有 AppData、静态前端和端口 10392 启动同一开发应用。没有创建样例账号,也未操作用户的微信程序。此前自动审批阻塞已解除。
+- 主进程首次页面加载成功后显式调用现有 `showMainWindow()`,并记录窗口显示/隐藏事件。语法检查通过,已有启动导航测试 7 项通过;这些测试本身不等于原生窗口验收。实际 Electron 于 20:10:22 启动,日志 20:10:27 记录页面加载成功和 `window-show`,随后通过原生桌面操作确认主窗口可见。
+- 从主页“回看聊天”打开真实账号,AI 历史和 DeepSeek 模型选择恢复。打开第 47 阶段真实统计运行 `559579cbfef24c0b87aec22c85f53d5c` 的已保存回答:严格 21:29 至 21:32 共 11 条,吉量 5、堂 3、330 2、迪拜大榴莲 1;四行实际显示不同人物头像和胶囊,截图 `real-data-50/real-statistics-large.png`。
+- 点击“吉量”胶囊,来源预览显示实际发送者“330”的熊猫头像,以及“@吉量 救我,被阿忠打21-7”原话,截图 `person-subject-actual-sender.png`。点击“定位到聊天”打开坦洲羽毛球群的同一条原消息,右侧仍保留原统计 AI 对话,截图 `person-real-chat-location.png`。这次真实历史恢复、人物与发送者区分、来源定位流程通过;没有把恢复旧回答写成界面重新生成回答通过。
+- 新桌面已加载第 46~49 阶段后端。独立的全账号最近 5 条只读验证进程保留运行,没有随桌面重启;一次观察为边界回读 606/779 个会话,仍等待最终集合比较。本阶段未新增远程模型调用,未访问 Mac,整项目标仍未完成。
+
+### 真实读取性能与数据库目录复用(49)
+
+- 第 48 阶段真实全账号最近 5 条验证继续在原进程运行,没有因观察耗时而重启。该进程尚未加载本阶段目录缓存,因此其结果和耗时仍属于此前版本;当前仍不能认定全账号最近 N 条验收通过。
+- 对三个真实会话进行工作线程内性能分析,原始记录 `real-data-48/read-profile.txt`:7.681 秒,其中原生调用 60 次,消息表定位约 2.563 秒。定位过程对每个会话重复逐库查询 sqlite_master,是可以确认的一部分开销,不代表唯一瓶颈。
+- 新增数据库级表目录缓存,按原生连接及绝对数据库路径隔离;同一数据库的不同会话复用目录。命中仍为 30 秒,缺失仍为 2 秒,二级会话缓存沿用原目录时间戳,不允许命中后重新计时而延长陈旧数据有效期。新分库逐库补查,读取异常不缓存成“无表”,统一清理入口同时清空新缓存。
+- 原生读取及导出适配测试最终 29 项和 4 项子测试通过(3.10 秒),含新分库、跨会话复用、过期、新建会话、连接/路径隔离和失败重试;记录 `schema-cache-final-tests.log`。这里只验证 AI 使用的消息读取依赖,没有开展朋友圈页面验收。
+- 新增只读性能工具 `tools/profile_ai_real_read.py`。以相同三个会话、相同截止时间比较关闭/启用跨会话目录复用:两边 94 条真实消息的来源集合完全一致;原生调用从 60 次降到 45 次,分析耗时从 8.306 秒降到 7.142 秒。原始统计、性能文件和来源对照均在 `real-data-48/read-schema-*`、`schema-source-comparison.json`。这是本次有其他后台读取负载时的一次对照,不能据此推断完整账号性能已合格。
+- 本阶段未调用远程模型、未修改原始聊天数据库。全账号验证进度仍在 `real-data-48/global-recent/progress.json`,统一执行会话 `26021`;最终窗口加载、UI 点击与 Mac 均未完成。
+
+### 全账号最近 N 条的稳定边界与真实核对(48,进行中)
+
+- 代码检查发现:单会话先按数据库顺序取 N,再按 `(time,source)` 合并全账号,会在同秒消息较多时提前丢掉全局排序应入选的消息。增加可选的预选排序键,使新版全局选择与单群候选预选使用相同稳定顺序;旧总结的默认排序保持兼容。测试同时验证交换会话遍历顺序后结果不变。
+- 已有 N 条候选后,后续会话的读取下界可推进到当前最老候选的时间;该秒仍完整参与比较,不能加一秒而跳掉同秒记录。发送者筛选仍在计数前完成。测试覆盖边界秒替换候选、跨群合计 N 和原有分页兼容。
+- 最近 N 条预选增加逐会话进度回调。正式 Agent 更新同一个带版本的执行步骤,显示已检查会话数;候选数不冒充已分析数,不提前标全量覆盖。加入进度逻辑后相关 16 项测试通过(3.98 秒),记录在 `real-data-48/recent-progress-tests.log`。
+- 新增 `tools/verify_ai_real_recent.py`,对真实账号固定截止时间,从全历史选择合计最近 5 条。之后独立使用时间游标完整读取所有会话在候选边界及之后的原消息,比较全局排序后的来源集合。不调用远程模型,报告只保存身份和时间,不写聊天正文、图片或文件传输助手的敏感内容。
+- 真实验证正在运行,证据目录 `real-data-48/global-recent/`,统一执行会话号 `26021`;截至一次观察已检查 143/779 个会话,189.38 秒,已有 5 条候选。这里只记录进度,尚未证明最终集合。预选完成后仍要完成全账号边界回读。停止应写入该目录的 `STOP` 文件,由所属进程退出;不能因为一次观察超时就重启任务。
+- 逐会话读取仍慢。底层首次定位会话消息表会逐个数据库查询表目录;可进一步评估复用数据库级目录缓存,不能据上述裁剪就称性能已经通过。当前桌面尚未加载本阶段修改,Mac 未访问。
+
+### 真实全局回答与统计时间边界(47)
+
+- 使用现有 AppData 账号、设置页已保存的 DeepSeek 配置,通过正式 Agent 链路运行;程序验证未操作桌面,不计作真实界面验收。没有创建样例聊天账号。
+- 全账号问题“谁说过‘7-21惨案’?请给出处。”运行 `b51108069c5d458eacc37fb658c2e078` 已完成。回答引用真实来源 `be422c48b87fd5ca5fadab99`,人物引用解析为 `330/heyuanguang`,实际群为坦洲羽毛球🏸。这是该问题的程序链路通过;耗时 305.94 秒、9 次调用、输入 485914 / 输出 10548 token、1 次用量未知,性能仍不理想。完整记录在 `real-data-47/global-agent/`。
+- 随后运行真实统计问题:坦洲羽毛球群 2026 年 9 月 10 日 21:29 到 21:32 的总消息及各发送者条数,不分析图片。独立聊天 around 接口返回的原消息跨过区间两端,对照左闭右开范围应为 11 条,吉量 5、堂 3、330 2、迪拜大榴莲 1。原消息快照及 ID 集合保存在 `statistics-chat-groundtruth.json` 和 `statistics-expected.json`。
+- 首次统计运行 `486ba23e4f2a4cf99faf08764bb48ae5` 虽完成,但模型把截止时间算成 21:33,报告 13 条并称“含边界”。新增核对工具 `tools/verify_ai_real_statistics.py` 比较时间、总数、发送者和完整原消息 ID 集合,发现四项不一致,报告 `statistics-comparison.json` 明确失败。2 次真实调用、输入 3432 / 输出 1269 token,用量均已知;没有视觉调用。不能以运行 completed 或 SQL 计数正确掩盖筛选错误。
+- 修复明确年月日与时分秒区间的转换:程序按任务固定时区换算,不接受模型自行向截止钟点加一分钟;跨日必须写明结束日期。相对时间继续语义解析。请求中明确携带左闭右开语义与时区偏移,修复后测试及同题复验另记。
+- 时间、全局助手和持续阅读专项 66 项通过(73.00 秒);把新增区间说明限定在新版上下文后,6 项时间专项再次通过(1.07 秒)。真实同题复验 `2c140a54375e4b5984101134d6354271` 完成,45.06 秒、2 次调用、输入 3457 / 输出 1635 token,用量均已知。`statistics-fixed-comparison.json` 的时间、总数、发送者、全部 11 个来源锚点和无视觉调用检查全部通过,答案明确不含 21:32:00。
+- 该统计答案仍使用普通人名,没有人物胶囊,不能称整条展示流程完成。原因是统计模式正确地不发送原文,但引用筛选也随活跃原文清空了人物目录。继续修复:只为当前统计页的稳定发送者 ID 附人物引用,包含分页结果;不重新发送正文,也不按同名文本替换答案。真实展示与修复后的模型复验待记录。
+- 引用修复后的持续上下文测试 19 项通过(52.44 秒),包含同名不同 ID、重新打开运行、统计分页和不向模型重新发送正文。第三次同题真实运行 `559579cbfef24c0b87aec22c85f53d5c` 完成,51.28 秒、2 次调用,输入 3799 / 输出 3053 token、用量均已知。四行发送者均使用正确人物引用,`statistics-references-comparison.json` 的 10 项核对全部通过,包括全部原消息锚点、正确结束边界及四位稳定人物 ID。这里证明返回数据,不证明最新桌面胶囊、点击和头像已通过。
+- 本阶段共 15 次真实调用(9+2+2+2),账号累计 170 → 185,包含失败尝试;最终用量在 `usage-after.json`。验收工具的新对话标题增加“真实数据验收”,并只给本阶段先前生成的三条对话补上同样标识,前后标题保存在 `acceptance-thread-labels.json`。没有删除或重写用户旧回答。
+- 当前桌面仍是 19:03:48 启动的第 45 阶段后端,第 46~47 阶段源码与哈希已保存,尚未完成桌面重新加载和真实点击验收;没有访问 Mac。编译与空白检查通过,整项目标仍未完成。
+
+### 新索引原文召回、真实模型复验及停止结算(46)
+
+- 确认无活跃 AI 任务后,已重启真实开发版,后端进程于 19:03:48 启动,10392 健康检查通过,加载第 45 阶段调度代码。全账号索引沿用任务 `3dc3f2e4c84b48a28393cb0d497dc1d0`,恢复后观察到会话位置 525、已提交 37820 条消息;未重新清空建立。结果 `real-data-46/index-after-restart.json`。
+- 主窗口保持隐藏,再次启动同一应用以唤起主窗口的操作被自动审批拒绝,返回 `blocked by policy`,没有具体理由;未重试该启动操作。已请用户从任务栏/托盘打开已有窗口。本阶段后续均为真实数据接口或正式 Agent 程序验证,不记为真实桌面通过。
+- 第一轮接口请求误将服务配置 ID 填入 model_id,运行 `f892930c24764f82bc4f73b2b279d4d2` 被上游拒绝,1 次调用、用量未知。这是验收参数错误,不归因于产品检索。更正为设置页已保存的 DeepSeek / deepseek-flash 后,运行 `45344f6edbf04a879c8ce00a29cedd14` 使用轮转代码,但仍扫描到 80 个会话没有命中,342.18 秒停止;3 次调用,输入 12581、输出 698 token,1 次未知。轮转不能单独解决本次漏检及延迟。
+- 只读核对发现原话已在渐进语义索引的已提交 messages 中,而旧全文索引仍无命中。旧混合搜索没有独立检索这些新原文,只从有限向量候选中返回消息,可能漏掉确切原话。新增按账号索引代次、会话、时间、发言人和类型筛选的原文关键词召回,与基础搜索共用 Unicode 多词匹配;使用参数化查询,原文和进度仍复用现有事务,没有新增索引映射表。向量服务失败时保留关键词结果及分页,旧全文结果不重复应用 offset。
+- 对真实 779 会话、37820 条已提交消息执行新原文检索,用时 0.75 秒(包含读取索引计数),返回唯一目标来源 `be422c48b87fd5ca5fadab99`,发言人 330/heyuanguang、群坦洲羽毛球🏸、原文“7-21惨案”。证据 `real-literal.json`,0 次远程调用;索引仍为部分覆盖,此结果不是全历史或整轮问答通过。
+- 新增 `tools/run_ai_real_acceptance.py`,从现有真实账号及设置页服务执行正式 Agent,结果明确标记 native_ui=false,不接收密钥、不创建样例账号。真实运行 `b0baed3f3c6b4029ba0e0cc3e595bcf4` 首次搜索已得到 1 个关键词命中,随后定向回查原消息上下文,但模型再次请求全局补查后,程序仍把空页自动扩展成连续扫描。该轮没有完成答案,停止后记录在 `fresh-agent/run.json`;6 次真实调用、输入 170252、输出 4860 token,1 次未知。不能把原文召回成功称为整轮问答通过。
+- 据此继续修复:同一查询已有关键词命中时,将这一事实与查询身份、版本一起保存;后续明确请求的补查只读一页再交回模型决策,不自动遍历全部会话。没有任何关键词命中的查询仍可由程序分页查找,未读游标和覆盖不足说明保留。
+- 程序验证中首次通过另一个后端进程发出停止请求发生状态竞争;第二次停止后工作进程退出,迟到异常又把取消状态写为失败,并把耗时累计两遍。该报告原样保留:实际 started_at 到 finished_at 为约 337.45 秒,记录 elapsed_seconds 为 674.72,不能拿后者作性能值。验证工具新增本进程轮询输出目录 STOP 文件来停止所属协程;产品 finish 增加已完成终态保护,避免迟到错误重分类或重复结算,正常继续仍可结算新运行段。
+- 原文召回与索引测试先 71 项通过,随后 89 项通过;分页边界修正单项通过。包含已知命中后的续扫修复后,最终全局/索引专项 90 项通过(22.67 秒);终态保护及原助手专项 25 项通过(23.80 秒)。源码编译通过。本阶段真实调用累计从 160 增至 170,记录 `usage-after.json`;所有失败保留。第 46 阶段修改尚未加载到桌面后端,最终问答、窗口恢复及 Mac 验收均未通过,未访问 Mac。
+
+### 新后端真实全账号检索与调度缺陷(45)
+
+- 旧进程和端口已不存在后,使用已有 AppData 数据启动开发版,Python 后端时间为 18:38:09,端口 10392。通过主页“回看聊天”恢复真实账号和历史 AI 对话。没有新建样例账号;此前旧重启阻塞已解除。
+- 新后端的全账号索引配置为版本 11、779 个会话,真实任务 `3dc3f2e4c84b48a28393cb0d497dc1d0` 已运行。一次状态观察为本任务处理 34039 条、已提交索引共 37820 条,均是部分进度,不能称全历史完成。
+- 通过真实 AI 输入框新建问题“谁说过‘7-21惨案’?请给出处。”,没有指定群或日期。运行 `0f59d2d098cd433fb8c4f44e65e7b06e` 的已保存资料确实包含目标:坦洲羽毛球🏸群、330/heyuanguang、时间 1789049915、来源 `be422c48b87fd5ca5fadab99`、原文“7-21惨案”。记录为 `real-data-45/global-target.json`。这证明真实默认检索能进入该消息,但不证明完整问答通过。
+- 真实运行耗时 382.41 秒仍未回答,由界面停止;保留 81 条来源、47 次工具操作。它在完整原话已命中后继续执行此前排好的“惨案”搜索,并再次全账号补查。实际 3 次模型调用,输入 12534、输出 908 token,其中 1 次用量未知;账号累计从 152 增至 155 次,失败数从 21 增至 22。截图 `global-search-slow.png`、运行记录 `global-slow-run.json`、用量前后记录均在 `real-data-45`。此项按性能失败记录。
+- 据此修改:实时补查各会话轮流分页,每个会话保留独立游标;旧顺序游标可转换,已提交结果重放不重读。实时命中后先重新决策,不继续执行命中前排好的备用改词动作。账号级回答不再对全部语义近似候选会话强制读一天;按工具结果和明确疑点定向回查,原有覆盖不足提示保留,报告及程序统计的完整范围读取路径不变。
+- 首次轮转相关测试 34 项通过(17.08 秒);随后全局及原助手专项共 60 项,首次 59 通过、1 个新增测试因直接调用 step 未安装模型审计钩子而失败。改为从实际 execute 入口验证后,该项复验通过(2.38 秒)。编译和空白检查通过。调度修改尚未加载到当前桌面,不将测试结果当作修复后的真实问答通过。
+- 真实输入框另起运行 `84ab13c7774e4639b7347cc9882e3a5f`,直接读取坦洲羽毛球 2026-09-10 21:29 至 21:32 提到吉量的消息。已完成:161.21 秒、5 次模型调用,输入 17189、输出 16157 token,用量均已知;包含一次回答引用校验后的重新生成,不隐去重试。群名不带表情也解析正确,严格左闭右开范围为 `[1789046940,1789047120)`,11 条消息,明确 @ 吉量的原话只有 330 的一条;此前 13 条验证实际读到 21:33,堂的另一条 @ 在 21:32 之后,不属于这次范围。
+- 实际界面显示 330 的熊猫头像和吉量的人物头像分别对应发送者与被谈论者。点击回答中的“吉量”胶囊,来源预览打开 330 于 21:31:31 发出的“@吉量 救我,被阿忠打21-7”;随后“定位到聊天”进入正确的坦洲羽毛球🏸群并显示同一条原话,右侧原 AI 对话仍保留。证据 `person-answer.png`、`person-subject-opens-sender.png`、`person-real-chat-location.png`、`person-run.json` 均在 `real-data-45`。这条真实身份与定位流程通过,不扩大为全部同名人物、历史引用和全局问答通过。
+- 独立只读程序在相同 11 条范围核对来源发送者 `heyuanguang` 与 @ 对象 `wxid_72qdftxgr6rz41` 不同,原始 @ 元数据身份吻合;两张图片的发送者、来源与聊天接口一致。首次报告保存成功但控制台 GBK 输出异常,保留 `person-source-verification.json`;改用 Python UTF-8 启动后复验退出码 0,记录 `person-source-verification-utf8.json`,没有为此改变产品代码或原聊天数据。此程序没有调用远程模型。
+- 本阶段实际账号总调用数由 152 增至 160(全局慢查询 3 次、人物问答 5 次);用量记录已保存。新写入的检索调度修复仍须加载后做真实问答性能复验,Windows 整体及最终 Mac 验收未完成。未访问 Mac。
+
+### 全账号目录遗漏历史会话(44)
+
+- 实时会话目录为 764 个,已保存快照目录为 778 个。集合并非包含关系:有 15 个会话只在快照目录中,也有 1 个仅在实时目录。只读计数确认这 15 个会话在实时源和快照中都存在消息,快照合计 10511 条。旧全账号目录仅使用实时会话列表,因此漏掉了可读取的历史。证据 `real-data-44/catalog.json`。
+- `ChatTools.conversations` 现在合并两个同账号目录,按稳定微信 ID 去重,优先保留实时名称;独立导入快照继续只用快照目录,不要求实时连接。账号级检索、模型查询目录和渐进索引复用这一入口。原聊天记录没有改写。
+- 全账号追问记录“全部会话”这一条件,而非把上次目录固化为白名单;新发现的聊天可进入下一轮。明确指定的会话和已排除会话仍然保留。缺少该新标记的旧条件保守沿用原范围,避免误扩大用户此前明确的筛选。
+- 新代码真实目录为 779 个,15 个旧遗漏会话全部纳入。对其中群 `45817683258@chatroom` 通过生产时间读取与稳定状态续读,最后一页取得 3 条真实原文,前面 6 个无消息的时间区间均推进后继续,合计 18.406 秒。结果 `real-data-44/merged-catalog-final.json` 只记录来源 ID、数量与范围,没有写聊天正文。首次验证脚本误把二分后第一个空子区间当作全部读取完毕,留下失败记录 `merged-catalog.json`;修正脚本按 has_more/next_state 继续后通过,没有为该失败修改产品时间读取逻辑。
+- 目录合并、全局追问和索引专项最终 48 项通过(18.34 秒),日志 `real-data-44/backend-tests-final.log`。此前仅目录合并的 45 项结果也保留。本阶段新增远程模型调用 0,未访问 Mac。
+- 当前桌面后端依旧为 15:31:36 的旧进程;779 会话、索引迁移与 @ 人物 ID 等新后端行为尚未在重新加载后的真实 AI 问答中验收。不能将上述独立原文程序验证当作桌面全链路通过。
+- 本轮随后运行全部 AI/本地检索后端文件,共 327 项(包含十万条消息内存/去重测试):首次 325 通过、2 失败,耗时 292.45 秒,日志 `backend-full.log`。失败均为旧工具适配测试没有账号目录,新增新鲜度检查返回 404;测试补上独立且没有索引的临时账号目录,仍实际执行新鲜度检查,保留原分页与来源协议断言。两项复验通过(1.30 秒),日志 `backend-adapters-fixed.log`。其余已通过项之后没有产品代码变更,未重复全套;不将此结果写成一次完整的 327 项全绿运行。编译及按仓库正常换行配置的空白检查通过。一次临时禁用 autocrlf 的检查将 CRLF 误报为尾随空白,恢复仓库正常配置检查退出码为 0,未转换工作区换行。
+
+### 旧索引任务阻挡全账号迁移与 Windows 真实索引(43)
+
+- 只读检查运行中应用:当前本地检索已启用,配置版本 10、全部历史、764 个会话;最新任务却是配置版本 9 的最近 30 天任务,状态 error,旧索引有 34373 条消息/4432 片段。证据 `real-data-43/old-job-blocker.json`。`ensure_global` 错把旧配置的失败任务当作当前任务返回,调度器也因旧任务不是 done 而跳过,新全账号索引实际上没有启动。
+- 新代码只让同配置版本的任务阻止重复启动。当前全账号任务主动暂停或出错时保留状态,不因目录刷新而偷偷继续;旧配置错误不阻挡已启用的新配置。后台全账号调度不再要求已存在 active 索引,也不要求旧配置任务成功。创建任务与配置更新共用锁,防止前台提问与后台调度同时创建两个索引任务。AI 执行状态对暂停、错误、已结束分别说明,不再一律称“后台补齐”。
+- 本地检索/渐进索引最终专项 49 项通过(6.52 秒),另有 AI 索引状态 4 项通过(2.53 秒)。当前真实桌面后端仍未重新加载,新迁移逻辑尚缺该窗口运行验证。
+- 使用本机真实解密快照和既有 BGE-small-zh CPU 权重,在新派生目录执行生产索引服务:快照目录 778 个会话、源文件及伴随文件合计 3155099648 字节;首批提交约 14.75 秒。建索引期间三次查询分别 0.078/0.062/0.063 秒,各返回 50 条候选。这里只检查可查询性与账号归属,不据此宣称语义相关性质量通过。
+- 暂停时保存 156 条,检查点 processed=156;新服务实例恢复到 216 条,旧来源集合保留,覆盖仍为部分,其他账号无法查询这些结果。合计 31 个真实 CPU 编码批次、0 次远程 API。源 SQLite 强制只读,结束时源文件大小和修改时间均未变。证据 `real-data-43/windows-real-index/result.json`,未修改应用既有全局索引,没有新建模拟聊天。
+- 这是当前 Windows 代码对真实快照的部分发布与恢复验证,不是全账号全量索引、实时增量或真实桌面索引迁移通过。快照目录数量与实时目录不同,正在继续核对,不能用其中一个数量代表所有可读取历史。
+
+### 微信原始人物 ID 与真实人物来源(41~42)
+
+- 第 41 阶段前端现在优先选择本回答实际引用、且谈论该人物的消息,避免任务中较早但无关的来源抢先。实际 Windows 原生窗口打开已有真实回答,点击“330”人物胶囊后,预览显示“迪拜大榴莲🍈”的头像、12:04:40 的发言及“划算,比天上掉井盖容易些”原话。截图 `real-data-41/person-current-source.png`。两个人身份分离;预览群名仍显示内部编号,是尚未加载的新后端修复,不记为全部通过。
+- 群名片按实际来源群建目录并保存到现有任务工作库。发言人筛选也使用群成员目录,不能只查会话列表;同名不同 ID 仍需澄清。恢复时保留对应群名片目录。真实读取 13 条消息时,“330”和“堂”谈论的“吉量”与两张图片发送者为同一 ID,来源发送者保持各自身份,见 `real-data-41/mentions.json`。
+- 8K 上下文测试首次失败:完整系统说明与工具定义的固定占用已超过输入预算。新增小窗口用的精简系统说明,保留账号隔离、有效筛选、证据、报告完整性和人物/来源/图片规则;实际请求、读取预算与圆环统一使用所选系统说明。原测试会话句柄已消失,未取得那次完整结果;本轮重新执行全局/预算/连续读取专项,57 项通过(137.68 秒),日志 `real-data-41/backend-tests.log`。前端第 41 阶段生产构建成功,未把前端刷新当作后端重启。
+- 第 42 阶段修正原始 @ 身份丢失:底层只读消息行保留 `msg_source`,兼容快照的 `source`、`msg_source` 及缺列旧库;AI 复用聊天接口的解析器提取 `atUsernames`。人物引用使用原始 @ ID 和引用消息发送者 ID,同名时不靠文字猜人;“所有人”不会生成人物胶囊,未知显示名保留 ID。群名片仍按实际会话解释。快照读取连接明确设为只读,没有改写原聊天库。
+- 数字/英文人物名增加边界判断,防止 `3300元`、`x330`、`330_2` 被误判为提及“330”;真实 `请330确认`、`@330` 保留。人物别名遍历改为稳定顺序。
+- 真实原消息验证 `real-data-42/mentions.json`:来源 `543b2dcb52213acfc82c3c6c` 的发送者是“330”,来源 `7e1ed532a40bdaaa724bcef3` 的发送者是“堂”,两条原消息的 @ 元数据都明确指向“吉量”的 ID。两张真实图片的发送者、时间、来源、群名片与运行中聊天接口仍一致。验证脚本新增 `--require-explicit-at`,本次要求并通过该断言。
+- 第 42 阶段人物身份、消息分页、全局专项 65 项通过(14.62 秒),本轮未重复已有十万条内存基准;测试临时库仅用于程序回归,没有创建模拟验收窗口。第 41~42 阶段新增远程模型调用 0,当前应用统计仍为 152 次,见 `real-data-42/usage.json`。该计数是当前应用库累计值,不用于推算全部历史双平台调用量。
+- 当前 Electron 后端仍为 15:31:36 启动的进程,上述新后端代码尚未加载到桌面问答;只读原数据程序验证与已刷新前端的真实点击验证分别记录。此前重启操作被自动审批以 `blocked by policy` 拒绝,未尝试绕过;手动重启仍待用户完成。未进行新 Mac 验收,整项未完成。
+
+### 真实群名片与图片引用(40)
+
+- 真实图片问题首次未通过:运行 `d3b0156c76dc4160b5933005bccd2ccc` 读取了指定时间范围的 13 条消息,却因人物名称不一致而反复搜索,已通过实际停止按钮取消。聊天接口将同一微信 ID `wxid_72qdftxgr6rz41` 显示为群名片“吉量”,AI 时间读取只显示联系人名“庄振江”。共 9 次模型调用,已知输入 38490、输出 14889 token,1 次用量未知;不能把它算成功问答。
+- AI 原文读取改为优先采用消息所属群的名片,并保留联系人名为别名;稳定发送者 ID 不变。有预算和无预算的读取均适用,别名进入统一请求计量、原文存储和人物引用。群名片解析复用聊天页的本地解析器,其 SQLite 连接改为只读。消息分页/时间/全局专项 52 项通过(13.67 秒,本次未重跑已有十万条内存基准);群名片解析与数据源专项 15 项通过(0.87 秒)。
+- 新增 `tools/verify_ai_sender_identity.py`。直接用真实时间读取与运行中的聊天接口对比两张图片:发送者 ID、显示名、发送时间、来源编号全部一致,图片引用可生成,模型资料保留“吉量/庄振江”别名。结果为 `real-data-40/sender-identity.json`,此验证没有模型调用,没有生成模拟聊天。
+- 当前桌面后端仍未重新加载。为独立核对图片查看器,在原生输入框补充已核实的“吉量=庄振江”关系后,运行 `d83304ad144147a68e11481469347d8e` 完成,4 次模型调用,输入 14593、输出 7360 token。两张引用分别对应 21:29:43 和 21:30:57 的原消息。正文只有图片引用按钮;原生查看器显示真实图片,能够在本回答两图之间循环、缩放和旋转。查看前后调用统计不变,见 `viewer-usage.json`。这一补充后的成功不替代自动识别人名验收。
+- 实际按 Esc 时图片查看器没有关闭,背后聊天却退出了定位上下文。已补充查看器自身的 Esc 关闭及阻止事件冒泡;引用/来源前端专项 13 项通过(1.53 秒)。新前端生产构建成功,34 路由生成;16:45:47 通过现有开发工具刷新页面后,真实历史回答与两张图片引用恢复。再次打开第一张图片并按 Esc,查看器关闭,焦点回到图片引用,回答位置与背后聊天位置保留;见 `escape-fixed.png`。刷新动作已执行,但紧接着的一次开发工具状态读取因未请求截图或文字返回参数错误,随后通过主窗口截图和桌面加载日志确认刷新成功,没有重复发送刷新快捷键。
+- 新前端中从第一张图片点击“定位原消息”,一次操作后对应的真实图片进入左侧可见区域,AI 回答位置保留;见 `real-image-location.png`。刷新、再次查看、关闭和定位全过程没有新增模型调用,最终统计见 `usage-final.json`。这些是当前真实 Windows 窗口验证,不代表待加载的群名片与实时搜索后端代码通过。
+- 本阶段目前新增真实模型调用 13 次、视觉调用 0;全部在已通过设置页配置的 DeepSeek 上进行。截图及筛选后的运行记录位于 `real-data-40/`;Mac 尚未执行,整项未完成。
+
+### 真实全账号检索的恢复与旧命中遗漏修正(39)
+
+- 修正旧索引已有关键词命中就不再回查实时缺口的条件:旧记录命中不能证明新回复已纳入检索。同一查询再次执行时沿用尚未完成的游标;查询完成后不重复扫描。准备后尚未开始读取时重启,也使用已经保存的计划,避免索引时间变化导致范围被跳过。
+- 每页匹配结果、下页游标和进度标记在同一个 SQLite 事务中提交。结果提交后、调度队列更新前重启,可以重放已保存的同一页;不会再次读取原消息。提交中途失败时全部回滚,旧游标仍可重试。该事务只写派生 AI 工作库。
+- 全局与时间读取专项 23 项通过(11.54 秒)。新增旧关键词命中仍回查、事务中途失败回滚、服务重建重放和跨筛选拒绝游标检查。这些是故障注入/程序测试,不算真实桌面验收。
+- 共享资料存储修改后,连续读取/压缩/持久化专项另有 18 项通过(47.11 秒)。Python 编译和已跟踪修改的空白检查通过;本阶段未修改前端,因此没有重复进行前端构建。
+- `tools/verify_ai_live_search.py` 改为使用生产 `AgentService`/`Workspace` 的续读实现。真实账号全局范围为 764 个会话:第一个进程读 3 页/600 条后保存退出;第二个进程 `--resume` 从该位置继续,累计 13 页/1836 条、读取用时 23.12 秒,找到来源 `be422c48b87fd5ca5fadab99`,真实发送者 ID 为 `heyuanguang`,显示名“330”,会话“坦洲羽毛球🏸”,原文“7-21惨案”。两次进程分别验证 3 页和 10 页在服务重建后重放结果一致。记录位于 `real-data-39/global-recovery/paused-result.json`、`result.json` 及派生 `workspace/`。未扫描完全部实时范围,没有标记全历史完成。
+- 本次新增远程模型调用 0,没有创建模拟聊天或模拟验收窗口。当前桌面后端仍是此前版本;本阶段代码尚缺重新加载后的真实 AI 问答验证。未执行 Mac 验收,整项仍未完成。
+
+### 全账号实时回查与前端显示(38)
+
+- 新增程序控制的实时关键词回查。范围来自当前账号与本轮筛选,按最近活跃会话排序;索引之后的原文在本机逐页匹配,仅匹配消息进入模型资料。每页保存稳定消息游标、扫描数和会话进度,空页自动续读不调用模型;停止、版本变更、游标无进展和源读取失败不会虚报完成。游标按任务、版本、查询与筛选验证,不能跨问题复用。
+- 真实全账号程序验证范围为 764 个会话,不传群名,检查到第 5 个会话时找到“330”的“7-21惨案”。共扫描 1836 条、13 页、23.78 秒,0 次远程模型调用。只保存匹配原文,未保存无关正文;见 `real-data-38/global-live-search.json`。这证明新读取路径能补到实际遗漏,不能当作已加载该代码后的完整桌面 AI 问答通过。
+- 新增可复用脚本 `tools/verify_ai_live_search.py`,从项目既有原生组件入口读取真实数据,支持检查点恢复;输出目录必须位于原应用数据目录之外,不含 API 配置参数。指定真实群复验为 1043 条、6 页、14.06 秒,找到相同稳定来源,证据为 `real-data-38/reusable-script/result.json`。最初独立 Python 未加载桌面原生组件目录而失败,使用桌面已有的 `WCE_NATIVE_CORE_SOURCE_DIR` 正常入口后连接成功,没有绕过原生校验。
+- 后端全局与时间读取专项最终 21 项通过(9.53 秒),包含跨筛选拒绝游标、重建服务后恢复和空页续读不调用模型;前端来源、引用、过程与助手专项 50 项通过(3.16 秒)。这些是程序测试,单独标注,不算真实界面通过。
+- 前端新增实时扫描进度说明;合并人物胶囊后紧接着的重复姓名,复制使用相同规则,不改写原始历史回答,也不裁掉较长姓名或编号。生产构建成功,34 路由生成,日志 `real-data-38/frontend-build-final.log`。
+- 应用主窗口的 Ctrl+R 未触发刷新,已用现有开发工具的页面刷新快捷键实际刷新前端(桌面日志记录 16:16:18 加载)。重新打开助手后原对话及真实回答恢复,界面中的“330”只显示一次,头像与出处保持分离;截图 `real-data-38/person-display-fixed.png`。只读 API 确认旧回答原文仍保留重复字符串,证明没有重写历史。刷新没有重启后端,新增实时检索和来源群名后端修复仍未在该窗口加载复验。
+- 本阶段新增远程模型调用 0;未重试已被自动审批拒绝的后端/窗口重启,也未同步或验收 Mac。计划整体仍未完成。
+
+- 已从原有账号数据进入“回看聊天”,真实群聊、消息及头像可见;此前误展示合成数据窗口,不能将其当成交付或真实账号验收。
+- 通过真实设置页新增 DeepSeek 文本服务,获取 `deepseek-flash` 并设为默认文本模型。保留原有视觉服务配置,未将密钥写入本文或测试文件。
+- 真实运行 `06b22bda55244d9797801cda008d5d07` 失败于群名匹配:省略“坦洲羽毛球🏸”末尾表情后无法唯一匹配。1 次调用,输入 1080、输出 514 token。名称装饰归一化已写入代码;原始身份和完整名称优先,同名返回多候选,不猜身份。
+- 补全群名的真实运行 `2a36296d37a1458faa2da8d0cef52584` 仍未找到左侧可见的“7-21惨案”,手动停止。9 次调用,已知输入 231816、输出 4929 token,2 次用量未知。首次搜索为 0 条关键词、50 条语义近似命中,后续反复改词。
+- 只读核对确认数据衔接缺陷:该群索引最新时间 `1788836611`,索引内精确命中 0;真实聊天接口为 realtime,目标消息时间 `1789049915`,发送者显示“330”。搜索快照和界面实时数据不同步,不能称全账号即时检索已验收。
+- 新代码给搜索结果保存索引新鲜度与定向实时读取提示;指定会话只有语义近似结果时,排入一次有预算和稳定游标的原文读取,避免先反复变换关键词。索引内最新消息时间不是完整覆盖证明。全局未指定会话的实时缺口仍需进一步处理与真实验收。
+- 名称匹配、实时读取调度及时间读取专项 18 项通过(8.33 秒);另直接读取用户真实索引,验证新鲜度提示的时间与只读 SQL 结果一致。首次 pytest 曾因旧临时目录清理权限失败,改用新独立临时目录后完整通过;不把这些程序测试当作桌面通过。
+- 加载上述新修改的 Windows 重启被自动审批以 `blocked by policy` 拒绝,未执行,也未换途径重试。原真实数据窗口仍运行,但尚未加载本段新的群名和新鲜度修复。人物胶囊与来源头像的真实数据完整验收仍未通过。未同步或验收 Mac。
+- 原窗口直接读取明确时间范围的真实运行 `1900043bc538482a96397b83b528480f` 正确找到“330”的原话,5 次调用,输入 13322、输出 2265 token。`434209e56e6a444da6e7920f00b4ab42` 验证真实回复关系,7 次调用,输入 46103、输出 18169 token:来源发送者为“迪拜大榴莲🍈”(旧索引昵称“-Down°C”),人物胶囊中的被回复者为“330”。已在原生界面查看不同头像,并核对来源发送者 ID 与人物 ID 分离。证据位于 `real-data-37/person-and-sender.png` 和按运行 ID 命名的 JSON。本阶段真实调用新增 22 次,包含两次失败场景及重试;这些定向读取成功不代表默认检索或整项身份识别通过。
+- 真实界面仍发现两处显示缺陷:原文回查来源显示内部群 ID(已补上时间分页丢失的显示名,但尚未加载复验);模型在“330”人物胶囊后重复写姓名(尚未修复)。多轮持久化回归连续两次触发测试自身 30 秒超时并取消运行,其他 20 项通过;保留覆盖及压缩断言,将该非性能测试的防死循环超时设为 90 秒后重跑,结果待记录。
+- 上述多轮持久化用例单独重跑通过,用时 33.57 秒,原来的完整消息数、覆盖、笔记和释放断言均保留。此结果不证明真实账号大规模读取的性能通过。待加载的四个后端源文件 SHA256 保存于 `real-data-37/pending-source-hashes.json`,不得把当前窗口的旧运行与这些新修改混记。
+
+当前范围仅为 AI 助手,按用户要求停止朋友圈及其他页面验收。使用用户已有真实账号聊天数据;下文合成聊天上的界面和真实模型记录只作为阶段证据,不能算用户真实数据验收通过。Windows 完成功能并稳定后才进行最终同版本 Mac 验收。
+
+## 环境与证据
+
+**最新补验(9 月 11 日中午)**:Windows 静态入口实际重新启动成功,后端约 3.08 秒就绪,页面 208ms 完成加载;聊天、设置与历史回答恢复。此次桌面启动/缓存专项 10 项通过。以下早期“未进行真实模型/Mac 尚未同步”的描述是当时的阶段记录,最新结果见文末,不代表当前状态。
+
+2026-09-11 后续真实模型阶段:用户取消调用次数上限。通过真实 Windows 设置页新增 DeepSeek、获取上游 `deepseek-flash`,保存并设为默认文本及视觉模型。依据官方文档手动确认 1M 上下文及图片能力(上游列表没有返回这些元数据)。设置页真实图片连接测试成功:1 次请求,输入 266、输出 644 token,耗时 7635ms。首次跨群报价问答未通过:16 次模型请求、7 次工具操作后动作协议失败,已读 124 条保留。证据在 `deepseek-acceptance-01/connection-usage.json`、`cross-project-before-fix.json`、`usage-before-fix.json`。目前不扩大为问答或双平台验收通过。
+
+随后修复了强制工具选择被拒绝后错误降级为纯 JSON 的问题,改为先尝试自动工具选择。恢复原任务后协议改善,但重复搜索仍存在,实际点击停止后保留 295 条,累计 29 次模型请求(非限额触发)。继续改进提示词并给模型提供同版本已完成操作参数,明确部分搜索不等于全量覆盖、答案由后续阶段生成。协议与全账号恢复自动化共 43 项通过。
+
+从独立新对话重问相同问题,运行 `7a858681fe524fd0b3e4ba39b3dbbf3f` 完成:8 次模型请求、12 次工具操作、约 103.54 秒;正确给出海桥 15600 元、包含数据导出、9 月 25 日交付,青禾报价 8600 元,并明确青禾没有原文明示“最终确认”。7 个引用全部解析到对应原文(`citation-check.json`)。这是合成聊天数据上的真实模型结果,不能当作真实个人历史或双平台全部通过。
+
+真实界面点击青禾来源后预览正确;首次跨群跳转切换到正确群聊,但原消息未进入可见区却显示“已定位”,第二次点击才滚动到目标。该项首次验收失败(`02-real-source-preview.jpg`、`03-real-source-location.jpg`)。已改为等待布局、立即滚动并检查实际可见后才返回成功;新构建与实机复验继续。14 项来源组件与导航测试通过,但其中导航测试替换了滚动函数,不能代替真实滚动验证。
+
+新生产构建 34 个路由生成成功后重启 Windows Electron;真实回答和阅读位置恢复。由海桥聊天打开青禾报价来源,第一次点击即切换到青禾并显示、高亮 8600 元报价原消息,提示已定位,AI 对话与右侧阅读位置保留。截图 `04-fixed-first-location.jpg` 为此次首次点击结果,已打开核对。此修复尚未同步并在 Mac 复验。
+
+- Windows:真实 Electron 40 窗口,1200 × 800,生产静态页面和隔离样例数据。原生操作使用 Computer Use,真实中文输入法候选输入,不用粘贴代替输入法验收。
+- 浏览器:Codex 内置浏览器,1280 × 720。交互预览包含明确标注的模拟回答、来源、图片、模型能力与预算;没有远程模型调用。
+- 截图位于 `../tmp/ai-assistant-implementation-20260910/ui-audit-20260911-01/`。编号对应实际步骤,可区分修复前、修复后和最终构建。
+- Mac:首次重新连接超时,随后 SSH 已恢复;同步前核对原目录 1136 个源码文件均与原清单相符,更新到 UI v2 后 1138 个文件校验一致。最新自动化通过。真实 Electron 第三轮补齐全账号设置的可见截图;模拟聊天数据,不含真实模型及真实中文输入法。
+
+## 已发现并修复
+
+| 问题 | 修改 | 新证据 |
+| --- | --- | --- |
+| 设置窗口深色背景被白色工具类覆盖,AI 标题接近白底白字 | 深色覆盖单独放在 utilities 后的主题层;兼容 Tailwind 4 的 divide-y 子元素规则 | 15 修复前;28 Windows 最终深色设置;21 深色首页 |
+| 静态开发模式重建后 Electron 仍读取旧资源 | 静态开发与打包模式均核对构建标识;变更时清理 HTTP 缓存与 service worker,保留 localStorage 等账号/草稿存储;清理失败不登记成功版本 | desktop-main.log 中两次构建变更清理记录;真实重启后从白色设置变为深色设置;新增 3 项缓存测试 |
+| 正式本地索引入口仍要求选择聊天和时间,文案与全账号方案冲突 | AI 设置使用全账号入口,取消该入口的范围选择;服务端解析实际账号会话目录并固定全部历史、增量更新;保留旧组件模式兼容已有调用 | 29 深色、33 浅色全账号入口;全账号开启与范围归一化测试 |
+| 进度将会话时间段数量写成已完成聊天数 | 分段任务标为“会话时间段”;已保存部分覆盖明确标注,旧索引缺失范围时显示未知 | 部分覆盖组件测试 |
+| 预算说明从靠右的圆环向右展开,被 320px 侧栏裁切 | 浮层按输入区右边界定位,宽度受输入区约束 | 31 修复前;32 修复后,浮层宽 280px、scrollWidth=clientWidth,无横向裁切 |
+| 重新打开设置时标题沿用上次栏目,正文已回到顶部 | 无指定目标时按实际滚动位置重新同步栏目 | 39 关闭前 AI 服务;40 重开后标题、导航与正文均为桌面行为,真实 Windows 最终构建复查通过 |
+| 全账号超过 2000 个会话时,保存高级设置回传整份目录会超过接口上限 | 高级设置和关闭功能只发送全局标识,目录继续由服务端解析 | 2001 个会话的高级设置保存回归测试通过 |
+| 流式预览模拟时间戳混用相对秒数与 Unix 时间,出现异常超长耗时 | 模拟步骤使用统一起始时间与递增版本 | 预览修正;不是一次真实模型故障 |
+| 手动暂停显示为红色错误,且“本次生成”包含尚未保存的片段 | 暂停以普通提示显示;非运行状态改用事务已提交的片段数量 | 42 修复前;43 重启后显示已保存 244;本地检索组件 42 项通过 |
+| 旧回答未加载执行过程时没有复制入口 | 历史摘要和完整运行复用复制按钮;失败后提示重试 | 47 原生 Windows 复制后粘贴,正文和可读出处一致,未发送 |
+| 头像文件缺失时来源按钮出现浏览器破图图标 | 隐藏失败的头像,保留人名与引用编号 | 新增失败事件回归;48~50 生产桌面复查通过 |
+
+主题层级实现参考 [Tailwind 官方自定义样式文档](https://tailwindcss.com/docs/adding-custom-styles)。
+
+## 检查步骤及边界
+
+| 步骤 | 本轮观察 | 证据 / 状态 |
+| --- | --- | --- |
+| 启动、首次使用、首页、聊天 | 已能启动,进入实际聊天页;静态入口不依赖已关闭的 3040 服务 | 01、02、04、21;启动日志 |
+| D01 输入框 | 真实中文输入“你”;组合输入 Enter 未误发;Shift+Enter 换行;切换微信聊天和最小化后恢复草稿 | 06~09、11、12;基础原生交互通过,未含真实模型运行 |
+| D01 尺寸与控件 | SVG 圆环 10 × 10、animation:none;主按钮 28 × 28、50% 圆角、黑色;思考等级文字 12px | 浏览器 DOM 实测;27 运行草稿;32 预算 |
+| 模型菜单 | 按服务分组;无能力资料时不显示等级,有确认的模拟能力时显示低/中/高;选中高返回 high | 24、31~32;真实供应商能力仍待 API |
+| 运行中补充 | 有草稿仍显示停止;Enter 应用补充并清空输入,运行配置下轮生效提示可见 | 27;模拟事件,不算真实模型调用 |
+| D02 回答、大视图、历史列表 | 320px 侧栏与大视图显示同一回答;历史列表可见;现有复制/出处入口保留 | 03、25、26;更细的历史操作已有组件测试,尚需本轮完整桌面流程 |
+| D03 来源与人物 | 人物胶囊显示被谈论者“乙”,打开其关联原消息时显示实际发送者;来源弹层含会话、时间、原文和定位入口 | 10、19;样例无头像资源,不能据此认定真实头像关联全部通过 |
+| D04 图片 | 正文为引用;查看器仅 2 张当前回答图片;放大至 125%、旋转、右键盘下一张、缺图提示、Esc 返回引用焦点 | 14、16~18;分别观察浅色/深色,没有触发模型分析 |
+| 执行步骤与覆盖 | 步骤可展开,显示筛选时间、处理量、逐会话进度及单独的模型消耗入口 | 26;模拟数据。真实多轮压缩、断线重连仍须真实模型 |
+| 本地检索设置 | 正式入口为全部群聊/私聊、先近期后历史;实际本地 CPU 模型完成启动、暂停、重启、继续和结束 | 41~46;3117 条人工样例消息,6 个会话时间段,478 个片段 |
+| 旧总结、任务、提醒 | 更多菜单保留“工具与任务”入口;分别打开旧总结、自动任务、关注提醒和历史记录 | 30、34~38;表单和历史空状态布局已查看,未提交真实模型任务 |
+| 复制回答 | Windows 真实点击旧回答复制按钮再粘贴;Mac Electron 复制后原生剪贴板读取和键盘粘贴一致;验收草稿已清空,未发送 | 47、`history-copy-paste.txt`;Mac `electron-answer-copy-paste.png`;回答均明确标注为模拟 |
+
+D01、D02 在前段复核中对照原稿;D03、D04 原稿与新截图在同次查看中比较。已确认的是结构、独立引用和交互;图片素材与聊天内容来自样例,截图尺寸也不同,不声称像素级完全一致。
+
+## 自动化与剩余项
+
+- 最新前端:Windows 与 Mac 各 21 个文件、246 项通过;包含 2001 会话保存、暂停已保存数量、历史复制及头像缺失;本地检索组件为 42 项。
+- 本轮后端:Windows 与 Mac 各 264 项通过;包含本地检索 47 项。Windows 日志为 `backend-final-full.log`,Mac 为 `mac-ui-evidence/ui-audit-automated-01/backend-synthetic.log`。
+- 桌面合同专项:双端各 17 项通过,覆盖通知、打包约束、启动、缓存及 output 主进程。
+- 生产构建:双端各 34 个路由生成通过,包含最新高级设置保存修复;Windows 实际重启成功。
+- 以上分类不替代此前完整基线套件,也不能相加后声称所有验收项通过。
+
+仍需继续:真实数据的头像与复杂引用全链路;旧总结、自动任务与提醒在真实模型下的主要流程;Mac 真实中文输入法;专用 API 下的真实问答、长报告、视觉、停止继续和重连。远程模型调用仍为 **0/30**。
+
+## 最新 Mac 桌面截图复核
+
+自动化记录为 `mac-ui-evidence/ui-audit-automated-01/result.json`。真实 Electron 为图形登录会话启动,独立 userData,Electron 40.0.0。第二轮 10 个流程检查通过,但其中全账号设置截图仍在顶部,不能作为覆盖说明可见的证据。第三轮加入目标滚动后重新执行,通过并取回新截图,保留前两轮记录。第三轮结果为 `mac-settings-final/result.json`。
+
+| 步骤 | 实际观察 | 本地截图 |
+| --- | --- | --- |
+| M01 聊天页 | 会话和消息可见,缺少样例头像,不能据此验收真实头像 | `mac-ui-evidence/ui-audit-electron-02/result/electron-chat-loaded.png` |
+| M02 切换微信聊天 | AI 草稿保留;瞬间截图仍有图片缺失标记,后续截图转为缺图占位 | `electron-chat-switch-draft.png` |
+| M03 隐藏窗口再返回 | 同一窗口、同一草稿、布局可用 | `electron-window-return.png` |
+| M04 多行输入 | Shift+Enter 后两行内容可见;中文为程序填入,不计真实 IME | `electron-multiline-input.png` |
+| M05 旧工具 | 总结、自动任务、关注提醒、历史入口保留,当前总结表单可见 | `electron-existing-tools.png` |
+| M06 全账号设置浅色 | 全部群聊/私聊、基础搜索、渐进整理和无模型入口可见 | `mac-settings-final/electron-global-search-settings.png` |
+| M07 设置重开 | 顶部标题与正文均为桌面行为 | `mac-ui-evidence/ui-audit-electron-02/result/electron-settings-reopened.png` |
+| M08 全账号设置深色 | 面板实际背景 rgb(36,36,36),覆盖说明可见,文字未被白底覆盖 | `mac-settings-final/electron-global-search-dark.png` |
+| M09 朋友圈 | 示例内容可见;实时组件未连接和样例头像缺失明确呈现,不算实时朋友圈回归通过 | `mac-ui-evidence/ui-audit-electron-02/result/electron-moments.png` |
+| M10 页面挂起恢复 | 建立真实 HTTP 连接后故意不返回,约 1 秒触发超时,随后恢复朋友圈 | `electron-hung-page-recovery.png` |
+
+以上不带目录的文件名均在 `mac-ui-evidence/ui-audit-electron-02/result/`。第二轮全部 10 张截图已实际打开检查;M06/M08 的两张旧截图被第三轮清晰显示目标区域的新截图替代。
+
+## Windows 真实本地索引与复制补验
+
+仅扩充隔离人工样例账号为 3117 条消息,包含 3 个聊天的近期与更早记录,原样例库已另存备份。正式界面选择 BGE Small 中文模型并开启全账号整理;暂停时已提交 1617 条、244 个片段,重启后同一任务 `b76aa42d96e74e5ba0efae6d5b43deff` 保留该进度。暂停期间混合检索返回样例命中,并明确标记部分覆盖。点击继续后达到 3117 条、478 个片段,6 个时间段完成。审计耗时 598 秒包含人为暂停,不能当成纯计算性能。
+
+原消息库开始与结束 SHA256 均为 `a7193dc6a7dc1bd28005bd2a28fb7b0ceff0adc9e2b4d1c578f169670e6bc8b1`。状态证据为 `index-paused.json`、`index-restarted.json`、`index-after-resume.json`;截图为 41~46。这证明真实本地模型在人工样例上的持久化与恢复,不代表真实账号全量索引完成。
+
+复制使用正式后端持久化的明确模拟历史回答,来源来自该人工样例库。Windows 原生点击复制、粘贴到空白 AI 草稿,确认正文及 `〔验收 · 海桥项目 · AI 桌面验收〕` 出处,再清空草稿,没有发送消息。48~50 显示缺失头像降级及来源原文;51 切换到小林私聊,53 点击群聊引用后回到海桥项目并显示正确原消息,AI 对话保持不变。52 是切换动画中的过渡截图,不用于最终标题判断。
+
+## Mac 最新回答及图片桌面补验
+
+`mac-ui-v4/electron/result.json` 为本轮第四次 Electron 结果,17 个检查通过、无页面错误;全部 17 张截图已在本机打开检查。源码 v4 共 1139 文件在两端 SHA256 一致;双端前端 246 项和 34 路由构建通过。新增的回答状态加载正式组件的明确样例页面,正式聊天与设置仍使用隔离后台数据,不能把样例页面说成真实模型生成结果。
+
+- D01:320px 侧栏,输入区、模型入口、圆环与主按钮可见;空输入为禁用状态。键盘调整后边界高亮是焦点状态。
+- D02:深色大视图,历史列表和回答区域完整;长回答在自身区域滚动,输入区固定。
+- D03:来源弹层显示发送者、会话、时间、原文和定位入口;样例未提供头像资源,不用于证明真实头像匹配。
+- D04:浅色下实际解码图片,125% 放大及 90° 旋转;第二张显示缺图状态;深色下重新打开首张,显示图片 1/2。放大后画面超出查看区属于用户缩放状态,不等于默认布局裁切。
+- 复制:Electron 原生剪贴板读取 271 字符,Meta+V 粘贴与其完全相同;随后清空。保留 Markdown 正文格式及可读出处,没有调用模型。
+- 既有页面:聊天、工具入口、设置、朋友圈和无响应页面恢复均有截图;朋友圈实时组件未连接及样例头像缺失仍是已知验收限制。设置切换截图中的旧焦点边框不代表当前导航选中项,当前标题和加粗栏目与正文对应。
+
+截图文件在 `mac-ui-v4/electron/`,名称对应结果文件中的检查项。D01、D03、D04 与原设计图片在同次查看中比较,结构与交互已核对;数据、头像、图片素材及视口不同,不宣称像素完全一致。真实中文输入法、真实模型执行中切回及模型输出质量仍未验收。
+
+## DeepSeek 原生等级与双平台真实问答补验
+
+设置页增加供应商确认的原生等级输入;可按逗号填写,去重并支持清空恢复自动识别。模型菜单使用当前服务已确认的能力,获取上游模型列表后不会被缺少元数据的目录项覆盖。两端本轮 Vue 各 248 项、协议/连续阅读/全账号后端各 43 项、生产构建各 34 路由通过。Mac 更新前后逐项校验 1141 个源码文件;随后仅修改两个验收脚本,分别同步并核对 SHA256。
+
+Windows 从实际 AI 服务设置保存 `low, high, max`,配置 revision=2,助手显示低/高/最高。真实问题“小林私聊…”因未匹配完整会话名而进入 needs_input(1 次调用),没有擅自猜身份。补充“验收 · 小林”后仅筛选该私聊;8 次模型调用、8 项工具操作后在生成回答阶段人工停止,状态 cancelled、资料保留。把菜单改为高,再点击继续,原运行仍为 low,只新增 1 次模型调用并完成,没有重复工具操作。回答引用 4 条私聊原文,说明周五加班、聚餐由六点改七点和已订六人座位。证据为 `deepseek-acceptance-01/native-low-*.json`、`usage-native-records.json`、`05-low-resumed-with-high-menu.jpg`。简称检索体验仍可改善;该测试不证明任意昵称都能自动解析。
+
+Mac 从真实 Electron 设置页新增 DeepSeek、获取并选择模型、保存能力和原生等级、设置默认文本/视觉模型,然后以 low 提交跨项目问题。运行 `b077806677684769b9e0dfd0077403e4` 完成:8 次真实调用、9 项工具操作,界面显示约 21 秒;海桥 15600 元、包含导出、9 月 25 日,青禾 8600 元和 10 月 8 日均引用相应会话。7 个引用可解析,青禾未明示最终确认的限制保留。回答将增加导出需求写作“后续”,与其原始时序不符,这一措辞质量问题仍待改进;不能把主要事实正确等同于报告质量完全通过。
+
+Mac 首轮脚本在 FIFO 输入等待,未调用模型;改为同步读取单行后完成真实问答。第二轮脚本在消息列表布局完成之前判断定位,报失败;保存的失败截图中原消息随后已可见并高亮。第三轮仅复用上述已完成回答,等待首次定位完成、没有再次点击定位按钮,自动检查通过且没有页面错误,新增模型调用为 0。三张结果截图保存在 `deepseek-acceptance-01/mac-replay-03/`,真实配置、原生等级、回答及来源预览见 `mac-model-02/`。旧失败记录保留,不改写成通过。
+
+当前累计远程调用 Windows 48 次、Mac 8 次,合计 56 次,包含失败、停止与重试,不设调用次数上限。Windows 已知输入 700536、输出 24261 token,11 次失败、6 次用量未知;未知消耗不能按零计算。Mac 重放中的 model_calls=8 是原运行用量,new_model_calls=0,不重复计数。样例聊天为合成数据;真实个人历史端到端、长报告压缩质量、真实模型运行中的断线/窗口恢复、Mac 真实中文输入法与完整图片问答仍未通过本轮验收。
+
+## Windows 真实长报告、保存恢复及进度修正
+
+运行 `262fc007c6cd458284645d16ca9dcf90` 从实际助手输入全账号最近 240 条的简明报告问题,要求保留报价版本、消息先后、星期和时间。为了在本次人工样例中触发多轮压缩,通过实际设置页将现有 DeepSeek 的应用窗口临时设为 65536,启动快照为 low、可用输入 60928;验收结束已通过同一设置页恢复 1000000,服务 revision=4。旧运行仍保留其 65536/low 快照。
+
+直接只读查询原消息库,按时间与稳定来源选出全账号总计最近 240 条,逐一核对来源和正文完全相同:海桥 82、私聊 80、青禾 78。三份成功保存的阶段笔记覆盖这 240 条原文的全部字符区间,没有间隙。第一次整理 47872→24523,第二次成功整理 47556→27354,最终整理 32555→26877,均低于可用输入的 60%。第一次笔记保存后,在第二次模型整理期间点击停止,selected_offset=214、124 个活跃片段均保存;重启后检查原进度和配置再点击继续,第一份笔记保留,未从头遍历,最终完成。取消的第二次尝试单独保留为失败记录。
+
+本次共 8 次真实模型调用,含取消及重试;回答 15 个引用全部可解析。人工核对报价 12800→15600、包含导出、交付 9 月 18 日→25 日、青禾 8600/10 月 8 日,以及聚餐周五六点→周六七点和六人座位,主要事实与时序正确。回答仍包含内部 coverage/evidence 字段和重复姓名;已收紧后续提示词,但尚未用新回答验证这些文风问题。此样例不代表任意长报告都保持完整语义质量。
+
+本轮真实检查发现并修正:
+
+- 程序读入原文后立即发布同口径预算,圆环不再等下一次模型调用才变化;批量读取活跃来源减少预算测量的重复 SQLite 连接。同一批 124 片段单次测量由约 124ms 降至 5ms,仅为本机单次观察。
+- 阶段笔记、原文释放与已分析数量在同一事务发布。只有已保存片段连续覆盖整条消息时才计为已分析;重叠去重、缺口不提前完成,保存失败不推进数量。最近 N 条的已读取数量与选择集合一致。
+- 恢复时重设当前阶段的计时起点;整理期间显示实际阶段。分组步骤显示“部分完成”,展开仍保留失败尝试与每次真实预算变化,进行中的新尝试优先显示“进行中”。历史分段数读取真实已保存笔记数量。
+
+最新 Windows 和 Mac 后端专项各 40 项、Vue 执行步骤各 17 项通过;两端生产构建各 34 路由成功。Windows 系统默认 Node 版本过旧,第一次 Vue 调用因 `crypto.hash` 不支持失败;使用已准备的 Node 24 后通过,未修改锁文件迁就旧运行时。另一次早期 pytest 临时目录清理受限的失败日志保留,后续改用独立临时目录通过。本次 8 个代码文件通过 `continuous-code-08-hashes.json` 在两端逐项核对。Mac 尚未重跑新的长报告桌面流程,以上 Mac 结果属于自动化和构建。
+
+证据目录 `tmp/ai-assistant-implementation-20260910/deepseek-acceptance-01/`:`long-report-audit-06.json`、`audit-long-report.py`、`long-report-answer.md`、`long-report-stopped.json`、`live-material-benchmark.json`、`continuous-08-tests.log`、Mac `continuous-code-08-tests.log`、`continuous-ui-08-tests.log`/`continuous-ui-08-build.log`;实际新版界面为 `07-long-report-compaction.jpg`、`08-long-report-coverage.jpg`。旧选择清单误将定位 anchor 用作稳定来源输入,已在只读审计脚本中从原库 server_id/local_id 重建并精确核对,旧文件保留用于解释验收修正。
+
+截至此次审计,Windows 56 次、Mac 8 次,累计 64 次真实调用;Windows 41 次 success、12 次 failed、3 次 cancelled,8 次用量未知,已知输入 757240、输出 66506 token。原消息库 SHA256 仍为 `a7193dc6a7dc1bd28005bd2a28fb7b0ceff0adc9e2b4d1c578f169670e6bc8b1`。整项计划仍未验收完成:Mac 真实中文输入、长报告停止恢复、真实运行中的 SSE 断线与窗口切回、完整图片问答和个人历史复杂场景继续待验。
+
+
+## Mac 长报告、真实断线恢复与时间条件修正
+
+`continuous-model-14` 的运行 `fb32394bd8ac451298cb848546dc13b8` 完成全账号合计最近 240 条报告,使用与 Windows 相同的 3117 条合成原文,源库 SHA256 不变。独立只读核对结果见 `mac-evidence-17/continuous-model-14/independent-audit.json`:实际选择海桥 82、私聊 80、青禾 78 条,8 份已保存笔记连续覆盖全部字符;8 次成功压缩均降低占用且低于可用输入的 60%。17 个消息引用可解析。此轮输出预留 32768,可用输入 32256,与 Windows 长报告的输出预留 4096 不同,不直接比较耗时或压缩次数。
+
+实际从设置页保存 65536/low;第一份笔记提交后停止,菜单改高再继续,运行身份、截止时间和 65536/low 快照保持。真正销毁 SSE 连接后重连携带 `Last-Event-ID: 466`,事件继续至 495,草稿、展开状态与顶部阅读位置保留;Electron 原生最小化后恢复窗口,模型继续执行。首次仅设置浏览器离线未能切断已有 SSE,旧记录 `continuous-model-11` 判失败;新增本机流代理实际断开 TCP 响应,两端代理专项测试均通过。未把“离线开关已调用”作为重连证据。
+
+报告主体 8 项检查成功;结果文件仍为 passed=false,因为最后恢复模型窗口时脚本立即读取旧配置。随后只读 SQLite 确认实际已经保存 1000000、revision=2。已修正验收脚本等待保存弹层关闭后再读取;保留原失败,不能直接改写为全流程通过。
+
+`continuous-model-11` 同时暴露无日期问题被模型附加早 30 天截止时间:模型返回空 time_phrase,却提供了不属于用户问题的时间戳。现由程序忽略无原话依据的时间戳,最近 N 条本身不视为日期;未指定日期使用任务截止时间,追问先继承仍有效的显式时间。两端该阶段后端专项各 43 项通过,新 Mac 报告范围正确。
+
+语义核对仍发现长报告把阶段性“未发现”写成聊天内容的冲突,且日期说明过度。已分别调整笔记与最终回答提示词:当前批次缺口只作为不确定性,后续补齐不当作冲突;按本轮问题回答最终值或变化过程,不把缺少星期当成未给日期。`followup-model-16` 通过实际历史对话追问复用已保存笔记,新增 4 次调用、0 条重新遍历,错误的更正说明消失;仍偏长的日期表述已继续修正。新笔记提示词下的完整长报告质量还需复验,不能只凭一次追问宣布通过。
+
+上述证据在 `deepseek-acceptance-01/mac-evidence-17/`。已查看长报告停止、重连、回答、来源预览、首次定位和追问截图;配置截图中的设置区仍在滚动,不能据它核对不可见的高级参数,配置快照另有结构记录。
+
+## 双平台真实图片问答与来源身份修正
+
+新增独立图片样例:海桥报价卡片、聚餐确认卡片及无关存档图片;新版金额、交付日、聚餐人数等答案只在 PNG 中,不写入聊天文字或预填分析结果。两端均通过实际“设置 → AI 服务”保存 DeepSeek,指定默认文本和视觉模型。
+
+- Mac `images-model-18`,运行 `b1005dd748564463b5badee5101312cb`:11 次真实调用,含 2 次各处理一张图片的视觉调用。正确回答 CNY 18,400、2026-10-16、Dashboard + CSV export,以及 Saturday 19:30、8 guests、Maple Restaurant。原生查看器正确显示两张图,125% 缩放、90° 旋转与前后切换通过,不包含无关的第三张图,查看期间新增调用为 0。`images-replay-19` 重启后从历史再次打开同一图片回答和查看器,通过,新增调用为 0。
+- Windows 运行 `f3107ff1a7d74e32b2f9163c664ca126`:通过 Computer Use 实际配置与提交,10 次调用(含 2 次视觉),界面约 36 秒。图片独有事实全部正确,新版提示词下回答更简洁。原生查看器 1/2→2/2→1/2、缩放与旋转通过,查看后用量仍为 10。源码和原图未改动;原消息库 SHA256 为 `462c9f758e749391f4f930ef3ef4328b7f389b2692a0c50babd57c8202144dd0`。
+- Windows 精确来源审计发现上下文回查按 anchor 生成 source,而时间读取按 server identity 生成 source;同一张聚餐图片得到不同消息编号。图片显示和定位仍正确,但稳定来源要求未满足。已统一消息身份函数,并让旧运行回查结果沿用已经发布的编号。Windows 真实样例库通过生产读取路径直接比对,两个来源一致,模型调用为 0。两端消息分页、旧引用与连续阅读专项各 80 项通过(Windows 108.33 秒,Mac 22.05 秒);包含没有服务端编号、账号隔离和旧图片来源恢复。原旧回答不重写。
+
+证据位于 `deepseek-acceptance-01/mac-image-evidence-19/`、`windows-image-run-20.json`、`windows-image-usage-20.json`、`windows-image-audit-21.json`、`source-identity-real-21.json` 和 `windows-image-*-20.jpg`。Mac 首次图片脚本因默认聊天排序变化超时,0 次模型调用,保留 `images-model-17`;脚本现主动选目标聊天。缺图展示已有两端组件/原生样例验证,真实回答的图片故障与恢复还需补验。
+
+本阶段累计真实调用 Windows 66 次、Mac 43 次,合计 109 次,包括失败、取消和重试,不设次数上限;重放不重复计数,细项见 `call-audit-21.json`。Mac 图形 Electron 的辅助功能信任检查为 false,已准备人工系统拼音窗口并请求操作,尚未记录通过。个人复杂历史、Windows 真实运行中的 SSE 断线,以及新提示词下的完整长报告语义质量继续待验。
+
+Windows 来源修复后已实际重启,历史图片回答及聚餐图片正常恢复,新增模型调用为 0;截图 `windows-image-restored-21.jpg`。两端图片的已保存身份与旧引用继续兼容,未重写旧回答。
+
+
+## 9 月 11 日下午:结构化结果纠错与真实断线补验
+
+Mac 同一长报告运行 `642fc7e22f6448eab9d5266b60796612` 在 `report-model-23`、`report-resume-24/26/27/28/29` 间保留检查点。前几次验收脚本存在两类问题:展开后立即设置 scrollTop,与布局更新争用;以及要求重连后 30 秒内必须有新业务事件,将模型仍在整理笔记误判为未恢复。现改为组件公开的实际滚动节点、真实滚轮,并分开检查携带 Last-Event-ID 的新连接与最终后续事件。失败记录保留,不改写原结果。`scroll-probe-25` 只打开已有对话,真实滚轮将 scrollTop 从 355 降至 0,新增模型调用为 0;这些改动仅修正验收脚本,未据此修改产品滚动实现。
+
+真实模型另暴露结构化整理连续校验失败:已保存 219 条消息对应的笔记,原文和待处理部分均保留。供应商适配现只在已确认能力的 OpenAI 兼容模型上启用 JSON 模式;不支持时回退;格式错误重试会附带安全的字段/错误类型反馈,不继续原样重发。审计新增响应字符数、结束类型和安全校验字段,不保存模型原始错误内容。参考 [DeepSeek JSON 输出说明](https://api-docs.deepseek.com/guides/json_mode/)。Windows 与 Mac 的供应商/连续阅读专项各 49 项通过(48.47 秒/14.62 秒),包含空响应、非法 JSON、错误字段类型和 JSON 模式回退。
+
+修复后 `report-resume-29` 从“重试这一步”继续同一任务并通过真实 Electron 流程;保持 65536/low、4096 输出预留和原截止时间。独立只读核对通过:全账号合计最近 240 条精确来源与正文一致(海桥 82、私聊 80、青禾 78),三份阶段笔记覆盖全部字符;压缩分别为 47625→22467、47670→25080、28199→25979,均下降且低于输入预算 60928 的 60%。来源库 SHA256 未变。该运行全部阶段合计 14 次真实调用(8 success、4 failed、2 cancelled),含 3 次用量未知;重放和脚本失败未新增的调用不重复计数。
+
+最终报告人工核对主要事实和时间顺序正确:海桥 12800→15600、增加数据导出、9 月 18 日→25 日,小林确认字段、小周测试;青禾 8600/10 月 8 日;聚餐周五六点→周六七点、松林餐厅、六个座位。12 个消息引用可解析。此前把阶段“未发现”当成聊天冲突的错误未再出现,也未输出内部 coverage/evidence 字段。报告仍较详细,包含时间线和最终安排两个视角;这一样例通过不等于所有个人历史报告的语义质量均已验收。
+
+Mac 人工系统拼音窗口 `manual-ime-20` 等待 900 秒后超时,未收到人工操作,未记为通过;该窗口已关闭,不能继续称其正在等待输入。
+
+Windows 通过新独立 `sse-runtime-24` 的正式设置页新增 DeepSeek、获取模型,保存 65536 与已确认的 low/high/max,并设为默认文本模型。首次代理将 Host 改成后端地址,使补斜杠重定向绕过代理;已保留入口 Host,两个代理专项测试通过。独立窗口重启加载修复后,从真实 UI 提交最近 240 条报告。SSE 实际中断约 29 秒后,重连携带 Last-Event-ID 488,后续收到 686;草稿“断线验收草稿,保留不发送。”、展开状态、顶部阅读位置保留,最小化后恢复窗口正常。切换到青禾聊天后,原 AI 对话和草稿保持不变。证据为 `windows-sse-proxy-25.json` 和 `windows-sse-*-29.jpg`。报告最终结果另行记录,不把连接恢复当作报告内容通过。
+
+
+### Windows 报告结果与后续修复(未通过整项内容验收)
+
+运行 `22449538600d4fc98fccddb21b0c9c00` 完成 240 条读取,保存九份笔记,共 13 次真实调用。来源集合和全部字符覆盖检查通过,但独立压缩检查仍判失败:前八次由约 24600–24800 降至 15265–19300,最后两条收尾原文整理为笔记时由 14932 增至 15076(+144)。不能把最后一步算作占用下降。正在修复收尾批次的新笔记与可选近期原文重复保留问题:重复保留会使占用不降时,提交笔记后释放活跃原文;持久化原文仍保留。
+
+报告主要报价和改期值正确,但内容验收不通过:聚餐明确写了周五/周六,答案却说“原文未直接写出具体日期与周几”,末尾又将各事项合并为“年份与周几均未给”;无关检查模板及缺口说明偏多。现已收紧笔记及回答指令,逐事项区分日期、星期、时刻,不推算用户未问的日历信息,不把未提及字段扩展为一整段缺口。该提示词修复尚需 Windows 真实回答复核,不改写旧答案。
+
+本阶段真实调用累计 Windows 79、Mac 57,合计 136(不设上限),详见 `call-audit-30.json`。Windows 原生断线、窗口恢复和聊天切换证据有效,不能据此将整份报告内容标为通过。
+
+### 最新开发顺序
+
+按用户新增要求,后续集中 Windows:先完成功能、修复与全部 UI 核对,冻结待交付版本后,再统一执行 Mac 最终验收。暂停随每次代码修改同步 Mac 的做法。上述 Mac 结果仅是已发生的阶段证据,不代表尚未稳定版本的最终双平台通过。Mac 系统输入法仍未验证。
+
+### Windows 追问与界面补查(31/32)
+
+运行 `0484ec3cbb3a41588e642e29031b0c88` 从原对话追问,复用九份已保存笔记,没有重新遍历 240 条;三次新鲜度回查均返回 0 条。实际新增 4 次模型调用(3 success、1 failed),累计 Windows 83、Mac 57,合计 140。完整结果、用量与截图分别保留为 `windows-report-followup-31.json`、`windows-report-followup-usage-31.json`、`windows-report-followup-31.jpg`,累计见 `call-audit-31.json`。
+
+本轮主要事实正确,也不再把聚餐星期说成原文缺失,但仍保留无关模板、额外日历推算以及旧笔记中的冗余疑问,简明表达验收未通过。进一步明确 question 为当前要求,历史回答不是写作模板或事实来源,笔记 uncertainties 只是待核对候选项。最新规则尚未通过真实模型复验,旧答案保持原样。
+
+收尾批次重复原文的修复已通过有实际预算比较的回归用例:原先保留原文会在低于 60% 预算时增加占用,修复后释放活跃副本、保留持久化来源并降低占用。本阶段 Windows 连续阅读、全局问答、供应商专项合计 63 项通过(45.31 秒);启动、缓存与流代理 12 项通过(216.35 毫秒)。自动化不能替代新的完整真实压缩流程。
+
+重启独立 `sse-runtime-24` 窗口的命令被自动审批拒绝,返回 `blocked by policy`,没有更具体原因;未改用其他方式重试该启动动作。原窗口已关闭,不能称其仍在运行。该限制不影响已有 `image-runtime-01` 窗口的页面检查,但后者未加载最新后端修改。
+
+在仍运行的 Windows 图片样例窗口,通过原生 Computer Use 核对消息总结、自动任务、关注提醒、历史空态、深色工具页、朋友圈、设置、AI 服务、本地搜索及用量记录。没有创建规则、发送微信消息或调用模型,用量页仍为原有 10 次。截图为 `windows-ui-*-32.jpg`。这些证据仅证明已观察页面的布局与入口,不证明空态环境中的历史任务执行或提醒触发。朋友圈正文与封面头像缺失时出现破图,现复用已有头像失败状态显示姓名首字;构建与更新后的界面结果另记。
+
+`windows-ui-build-32.log` 记录最新 Nuxt 生产构建退出码 0,静态页面生成成功;保留既有 CSS 渐变语法警告。原生窗口的普通刷新与强制刷新未观察到新头像占位,故修复后的真实显示仍待验证,不能把构建成功当作界面通过。Windows 最新后端真实长报告、真实回答缺图恢复、复杂个人历史仍待验;完成 Windows 后才进行 Mac 最终同版本验收。
+
+### Windows 增量索引覆盖修复(33/34)
+
+新增实际 SQLite 回归先复现失败:同一代索引已有甲乙两个会话,甲的增量批次发布后,查询乙的旧消息退回 keyword,已存在的乙向量未参与检索。原因是发布时用当前批次覆盖记录替换了整个可查询会话列表;增量结束也会丢失更早历史的覆盖记录。
+
+修复后,同一代索引合并此前与新提交的会话时间段,只合并连续或重叠的完整范围,不填平未读缺口,不累加重叠批次的消息数。新一代重建不继承旧覆盖;旧格式没有覆盖记录时不凭空补造。显式索引设置收窄后,覆盖同步实际保留范围,再扩大也不会将已裁剪内容标为完整。这不改变当前 AI 问题筛选与全局索引的分离。
+
+Windows 索引专项最终 42 项通过(6.22 秒),日志 `windows-index-tests-34.log`。覆盖真实 SQLite 向量查询、增量结束后重开状态库、范围收窄再扩大、重建隔离、时间缺口与重复更新的覆盖合并。
+
+`local-index-real-34/result.json` 使用隔离合成 SQLite 和已校验的真实 CPU BGE 模型通过:首批 36 条已提交时可查询并暂停,重启补齐 117 条,增量新增后为 118 条且只新编码 1 个片段;增量仍运行时另一个会话的更早历史返回 5 条,结束后所有会话的完整历史时间覆盖保留。账号隔离通过,合计 10 个本地编码批次、0 次远程 API 调用。前一次 `local-index-real-33` 同样保留,不覆盖。此次移除本地验收脚本的固定编码批次数量上限,仍记录实际批次与完成条件。
+
+本轮未启动或同步 Mac,未重试已被自动审批拒绝的 Electron 启动命令。当前修复已有本地程序和真实向量模型证据,最新 Windows 桌面与 DeepSeek 报告复验仍待恢复启动条件;远程调用累计仍为 140。
+
+### Windows AI 专项复验(35,进行中)
+
+用户明确收窄后续范围为 AI 助手,停止朋友圈等其他页面验收。继续先完成 Windows AI,再冻结版本并统一验收 Mac;历史页面检查记录仅保留事实,不再作为本轮新增验收工作。
+
+用户授权重启独立 Windows 验收窗口后,`sse-runtime-24` 已成功重新启动,先前该窗口的启动阻塞已解除。通过原生 AI 界面在新对话提交与旧失败样例相同的最近 240 条简明报告问题,沿用设置页保存的 DeepSeek 配置,原生等级为 low。运行 `4564690d7b5c41c6b00b84fd89a23352` 的最终结构、语义与用量记录待完成后补充。
+
+准备单张图片 HTTP 404 的验收代理,不修改原图或聊天数据,只匹配有效 MD5 的图片接口,恢复后继续转发原内容。代理三项自动化通过(228.37 毫秒),包括真实断流重连、普通请求透传及单张图片故障隔离。启动另一个图片验收窗口的命令仍被自动审批以 `blocked by policy` 拒绝,未执行、未换途径启动;真实回答缺图恢复仍未通过验收。这不影响已经运行的报告窗口。
+
+运行 35 已完成。`windows-report-audit-35.json` 独立只读核对通过:来源 SHA256 不变,精确 240 条(海桥 82、私聊 80、青禾 78),12 份笔记连续覆盖全部字符,12 次压缩全部降低占用且低于输入预算 32256 的 60%,14 个消息引用可解析。24 次真实调用为 21 success、3 failed,2 次用量未知,已知输入 131601、输出 83497 token;累计 Windows 107、Mac 57,合计 164,见 `call-audit-35.json`。
+
+结构通过不代表内容通过。人工检查报告仍有重复时间线与最终值、反复列出未问的年份/星期/版本缺项;末尾把青禾 10 月 8 日放入海桥缺口,且对相邻两条青禾消息的指代过度质疑,因此语义与简洁性仍不通过。原始回答和用量保存为 `windows-report-run-35.json`、`windows-report-usage-35.json`。真实界面来源 4 正确预览私聊小林的“我周五加班,能换个时间吃饭吗”及发送时间,尽管当前微信聊天仍是海桥;截图 `windows-report-source-35.jpg`。
+
+据此继续修正 AI:笔记上下文增加由持久化原消息生成的来源时间、会话、发言人与身份,限定在输入预算 10% 内且超出部分明确计数;整理后的预算同步包含这些字段。收紧笔记的未知项准入与报告组织要求,不再用缺失年份等示例引导冗余缺口。另修复已完成完整阅读后仍因早期 `has_more` 显示“部分资料未读”的误报;普通搜索的部分覆盖以及实际读取错误仍保留。以上新修改尚未加载到真实模型窗口,不将运行 35 写成这些修改后的通过结果。
+
+最新连续阅读、全局问答与供应商专项 65 项通过(68.55 秒),日志 `windows-notes-tests-35.log`。新增同名跨群来源身份、发送时间重启保留、元信息计入预算、完整阅读误报消除及真实读取错误保留。首轮新增测试将“提交笔记时预算”与“追加已完成操作后的预算”比较,因后者新增操作信息多 66 单位失败;已改为同一时刻的带/不带元信息请求比较,并单独核对发布预算与压缩记录一致。该测试调整没有放宽真实报告的下降与 60% 验收标准。
diff --git a/docs/ai-compaction-2026-09-12.md b/docs/ai-compaction-2026-09-12.md
new file mode 100644
index 00000000..1965d30c
--- /dev/null
+++ b/docs/ai-compaction-2026-09-12.md
@@ -0,0 +1,86 @@
+# AI 对话上下文压缩改进与验收
+
+本次针对默认 V2 对话流程补齐历史检查点、近期完整轮次保留、请求用量校准和可配置策略。继续使用现有原文资料库及阶段笔记事务,不对微信聊天资料采用“只保留头尾”的裁剪。
+
+## 行为变化
+
+- 较早的用户/助手历史整理成结构化检查点;默认至少保留最近两个完整轮次,同轮补充与回答不拆开。保留区域还受近期预算控制,单个超长轮次不会静默截断。
+- 检查点包含历史背景与用户原话引用。引用必须能逐字匹配对应用户消息,不能把助手说法或聊天资料中的命令标为用户要求。
+- 检查点按账号、对话、范围版本、会话/时间/发送者筛选及最近条数条件隔离。原消息 ID、顺序和正文指纹匹配后才可跨运行或重启复用。
+- 成功的历史分块草稿可复用;最终摘要必须缩短原历史,长度和原话校验通过后,再在一个数据库事务中发布对话检查点与本轮位置。失败、停止和新补充不会推进旧检查点。
+- 切换小窗口或调低摘要上限时可以再次压缩旧检查点,近期原始轮次仍保留。无法容纳的完整轮次由既有请求预检报告窗口不足,不伪造成功。
+- 请求 JSON 将历史检查点、近期历史、当前目标和资料放在前面,将动态进度放在后面,减少相同阶段的前缀变化。保持单 JSON 协议及专业笔记 Schema,不假定摘要调用与最终回答能共享全部前缀缓存。
+
+## 用量与安全回退
+
+`ContextMeter` 使用供应商成功响应的 `input_tokens`,按同一模型配置、工具定义及辅助调用模式匹配请求前缀。未变化的前缀复用实测基准,新后缀按 UTF-8 字节保守计入,并额外保留 5% 与 256 单位余量。不会减掉旧请求已删除部分的估算值,也不从一个样本推断全局中文 Token 比例。
+
+只有哈希、分块字节数和输入用量随对话保存,不保存额外的提示词或密钥。无可靠用量、无足够相同前缀、模型/配置/工具变化或多模态请求会回退到原保守估算。上下文溢出会清除校准后重试;辅助计量落盘失败不丢掉成功回答。前端明确区分实测用量锚定的估算和纯保守估算,二者均不冒充本次实测 Token。
+
+SDK 在 JSON 响应返回前抛出 `LengthFinishReasonError` 时,现在仍提取其真实输入/输出用量,归类为输出截断,不再把同一摘要请求按普通故障原样重试。真实接口没有返回的用量仍标为未知。
+
+## 每模型策略
+
+模型配置接口接受 `compaction_policy`;旧客户端未提交该字段时保留原设置。运行继续使用创建时的模型快照,更新配置适用于新运行。
+
+| 字段 | 默认值 | 含义 |
+| --- | --- | --- |
+| `pressure_ratio` | 0.80 | 完整请求整理触发比例 |
+| `target_ratio` | 0.60 | 阶段笔记提交后的请求目标 |
+| `history_ratio` | 0.30 | 历史与检查点字节预算触发比例 |
+| `recent_ratio` | 0.16 | 近期原始对话的字节预算比例 |
+| `recent_turns` | 2 | 至少保留的完整近期轮次 |
+| `history_summary_ratio` | 0.10 | 历史检查点字节预算比例 |
+| `history_summary_bytes` | 8192 | 历史检查点字节硬上限 |
+| `note_ratio` | 0.20 | 阶段笔记字节预算比例 |
+| `material_tail_ratio` | 0.15 | 阶段笔记后保留的近期聊天原文比例 |
+| `summary_attempts` | 3 | 摘要业务校验最大尝试次数 |
+| `summary_output_tokens` | 8192 | 摘要模型输出上限,仍受模型限制 |
+| `summary_timeout_seconds` | 120 | 单次摘要调用及其供应商重试的总等待上限 |
+| `overflow_retries` | 2 | 运行的窗口收缩重试上限 |
+| `usage_calibration` | true | 启用真实用量校准 |
+
+字节控制和模型 Token 容量不是同一单位:资料切分、笔记长度与历史分区仍保守按字节控制;完整请求使用校准估算。这些默认比例不是 DSH 参数的性能等价保证。无效比例、未知配置字段和越界数值在 API 层拒绝。
+
+## 验证证据
+
+专项测试覆盖完整近期轮次、用户纠正、检查点跨轮及重启复用、源消息编辑、范围变化、最近条数变化、伪造用户原话、摘要超长、取消、事务回滚与草稿恢复、小窗口再次整理、模型/配置/工具隔离、实测用量接入、SDK 截断用量和旧客户端保存兼容。
+
+最终检查:
+
+- 新增专项文件共 22 个测试用例,全部通过。
+- 专项、供应商、Agent 协议组合:96 项通过。
+- 专项、V2 连续运行、历史兼容、账号级助手、读取预算、引用恢复、延迟预算组合:165 项通过。上述两组重复包含专项用例,不累加冒充独立测试数。
+- 此前另运行旧 Agent、旧上下文及 API 等兼容回归,130 项通过;早期主流程组合 202 项通过。这些运行同样存在重叠。
+- 新增模块与验收脚本编译检查、相关已跟踪文件的 `git diff --check` 通过。未打包或重启正在使用的桌面程序,新代码随后端重启或下次打包生效。
+
+真实模型使用本机默认配置 `mimo-v2.5`,仅发送程序构造的虚构对话;源配置数据库只读,密钥只在进程内使用。验收工具为 `tools/verify_ai_compaction.py`。
+
+成功记录:`tmp/compaction-real-20260912-02/report.json`。
+
+| 检查 | 结果 |
+| --- | --- |
+| 压缩前、压缩后提取最新聚餐日期/时间 | 均为周五 19:30 |
+| 新预算与人数 | 均为 2400 元、12 人 |
+| 第二件事 | 均为订羽毛球场 |
+| 未完成事项 | 保留餐厅尚未确认、球场尚未订成 |
+| 排除范围 | 均保留项目乙群被排除 |
+| 历史资料中的恶作剧命令 | 未将预算改成 9999 元 |
+| 持久化原始消息 | 未改动 |
+| 最近两个轮次 | 逐字保留 |
+| 重启复用 | 没有新增模型调用 |
+| 历史上下文大小 | 17,450 → 5,879 字节,减少约 66.3% |
+| 真实调用 | 4 次成功,约 53.89 秒,均有用量记录 |
+
+首次验收记录 `tmp/compaction-real-20260912-01/report.json` 未通过,暴露摘要输出截断及用量漏记问题:两次失败尝试,旧代码没有取得用量,不估算为零。修复后重新验收通过,并加入 SDK 截断回归。成功样本的四次调用包括摘要开销和压缩前后两次回答,不把上下文减少量当作整个任务费用降低比例。
+
+这是一组有标准答案的真实模型对照,加上确定性工程回归;不能由单一样本推断任意长对话的语义完全无损,也没有声称优于 DSH 的统一基准。后续真实聊天仍由原文、来源和已保存发现支持核查。
+
+复现方式(使用新的输出目录):
+
+```powershell
+.venv/Scripts/python.exe -m pytest tests/test_ai_compaction.py -q
+.venv/Scripts/python.exe tools/verify_ai_compaction.py --database <现有配置数据库> --output <新的验收目录>
+```
+
+工具默认使用配置数据库中的默认文本模型,也可显式传 `--profile`。真实调用会产生该模型的正常用量。
diff --git a/docs/ai-compaction-ui-2026-09-14.md b/docs/ai-compaction-ui-2026-09-14.md
new file mode 100644
index 00000000..fe82b7f1
--- /dev/null
+++ b/docs/ai-compaction-ui-2026-09-14.md
@@ -0,0 +1,27 @@
+# 上下文压缩提示与摘要保留
+
+已按用户选定的分隔式设计接入现有 AgentRun 页面。
+
+- 压缩中显示「正在压缩上下文」、本次触发用量和原文已保留的提示。
+- 完成后默认仅显示「上下文已压缩」,点击读取这一次的摘要与前后用量。
+- 压缩记录随执行过程一起收起,重新展开后仍在原位置且可读取摘要;200 条普通步骤以外继续保存压缩节点。
+- 每次摘要独立存入对应任务版本的工作区;SSE 仅传元数据,不重复传输长摘要。
+- 失败、中断和旧版本未完成的记录不显示为成功或继续转圈。
+
+## 用量修复
+
+原流程在摘要结束后才发布用量,页面看不到实际触发高水位。现在开始压缩时先发布 before,完成提交后再发布 after。既有压力阈值及紧急超限恢复策略不变。
+
+## 历史兼容
+
+新增只读接口 `/api/ai/agent/runs/{id}/context-compactions/{job_id}`,要求 account 和 version,按账号、任务、版本和压缩 ID 校验。
+
+旧压缩记录仅在最新快照的 context_revision 与请求 ID 一致时读取旧摘要;否则明确说明该记录没有可查看的摘要。旧记录没有保存窗口容量时显示 Token 数,不借用当前模型窗口换算百分比。
+
+## 验证
+
+- 后端 87 项相关测试通过:新增持久化/访问隔离测试、锯齿压缩、上下文恢复、历史压缩和第二轮续聊范围回归。
+- 前端 89 项相关测试通过:压缩生命周期、时间线、工具失败、聊天面板和资料读取。
+- 浏览器验证 440px / 320px、深浅主题、键盘收起、摘要展开、失败提示及过程折叠后的顺序。详细证据见项目根目录 design-qa.md。
+- 项目已重启:前端返回 HTTP 200,后端 health=healthy,新接口已注册;真实历史压缩记录返回 HTTP 200,读回已保存摘要(仅验证可用性,不复制聊天内容)。
+- 未重跑用户聊天任务;未为了触发压缩而调用真实模型。新压缩完整生命周期使用确定性模型与隔离存储验证,真实应用中的下一次自然触发仍需随正常使用观察。
diff --git a/docs/ai-context-recovery-2026-09-14.md b/docs/ai-context-recovery-2026-09-14.md
new file mode 100644
index 00000000..28610022
--- /dev/null
+++ b/docs/ai-context-recovery-2026-09-14.md
@@ -0,0 +1,90 @@
+# AI 上下文整理故障修复记录
+
+本文记录 2026-09-14 的实际实现。此前的 `ai-agent-current-logic-2026-09-14.md` 是修复前审计,不代表当前代码。
+
+## 故障原因
+
+本次直接失败点在 `DurableSummarization._acreate_summary`,不是 `search_live_messages` 本身。旧工具结果不断留在模型输入里,触发累计摘要;摘要必须小于 8192 UTF-8 字节,三次不合格就抛出异常。真实模型返回了 13010 字节的完整草稿,系统仍把整个业务任务判为失败。成功分段也没有独立恢复游标。
+
+容量计算另有两个问题:按模型声明的最大输出能力预留空间,而实际请求只申请 8192 Token;主请求和摘要请求共用计量记录,使主上下文压力的显示、校准与触发不一致。
+
+## 当前执行链
+
+1. 从原图检查点恢复任务,读取程序保存的用户要求、范围、截止时间、游标和待提交页面。
+2. 保存公开阶段记录到 `/context/working/`,标记为临时工作记录,不能当作原文证据。
+3. 处理有效消息:旧的大工具结果完整保存到 `/context/history/`,模型输入保留目录、分页状态和调用配对;最新工具批次保留正文。原检查点消息不做破坏性修改。
+4. 主模型、摘要调度器和界面使用一致的主请求计量方式。主请求预留实际申请的输出容量,摘要请求单独校准,不覆盖主请求压力。
+5. 只有仍然达到压力阈值或上游报上下文溢出时,才进行累计摘要。
+6. 摘要先验证原文归档,再创建内容寻址的持久化作业。每个分段在调用前、返回后、验收后分别保存进度。
+7. 摘要成功后继续主任务;无效摘要耗尽尝试次数时,以已核验的完整归档目录和明确缺口说明继续,所需事实通过工具回查。
+8. 归档保存失败、摘要服务暂不可用或反复上游溢出时,保留可继续状态及检查点;不会把截断草稿当成完成结果。
+
+## 数据与容量规则
+
+| 内容 | 保存与使用规则 |
+| --- | --- |
+| 已获取原文 | 原有来源库保留,范围和来源权限校验保留 |
+| 旧工具正文 | 超过 2048 字节且已有后续 AI 消息时外置;不改变 tool_call_id |
+| 最新工具批次 | 正文仍交给模型处理 |
+| 历史归档 | SHA-256 内容寻址;每片最多 16384 UTF-8 字节;目录可按顺序还原完整原文 |
+| 用户要求 | 最多 8192 字节直接注入程序状态;更长要求完整保存为只读内部资料 |
+| 阶段记录 | 按任务输入版本隔离;显式标注并非证据 |
+| 摘要输入 | 每次最多 65536 个按 UTF-8 字节估算的预算单位,含提示和已有摘要 |
+| 摘要目标 | 默认提示目标 8192 UTF-8 字节;实际硬验收上限随本段预算计算,最高 32768 字节 |
+| 摘要重试 | 完整但过长的草稿可缩写;空白、失败占位和截断输出重新使用原文;不会截取字符串冒充摘要 |
+| 摘要恢复 | 保存 offset、fragment_end、previous、draft、attempt、budget、segments、状态及候选校验结果 |
+| 模型输出预留 | 主任务与摘要实际请求默认 8192 Token;特定核验用途为 16384,仍受模型能力上限约束 |
+
+以本次模型配置为例:窗口 1000000,实际输出 8192,安全预留 512,可用输入容量为 991296。此前错误按 384000 输出能力预留,可用输入仅 615488。保守预算单位不是实测 Token,界面明确标注估算。
+
+恢复缓存与完整历史、预算、摘要策略绑定。已经完成的分段不会因继续任务而从头重做;尚未持久化返回结果的在途调用仍可能重试。重复保存同一归档不会追加重复文件。
+
+## 展示修复
+
+- 普通问答的 `analysis.tracked=false`;运行中、结果底部和范围详情显示“按需检索”,不再把没有提交结构化发现显示成“已分析 0 条 / 范围未完成”。
+- 完整分析显示“已提交分析”,继续受原有完整覆盖校验约束。
+- 搜索及上下文回查保存新原文后同步刷新覆盖统计,避免总读取 2146、范围读取却停留在 2000。
+- 摘要作业在时间线显示当前分段、尝试与完成状态,附可定位到持久化作业的元数据。
+
+## 验证
+
+### 自动回归
+
+后端以下测试集合通过 180 项:
+
+```powershell
+.venv/Scripts/python.exe -m pytest tests/test_ai_context_recovery.py tests/test_ai_deep_context.py tests/test_ai_deep_reliability.py tests/test_ai_deepagents.py tests/test_ai_deep_contracts.py tests/test_ai_deep_mimo_regressions.py tests/test_ai_deep_omissions.py tests/test_ai_agent_reading_budget.py -q --tb=short
+```
+
+重点覆盖:13010 字节中文摘要一次接受及缓存、空摘要/截断/超长输出的无损归档后备、分段中断恢复、旧工具正文无损还原与调用配对、完整请求计量、摘要和主请求校准隔离、覆盖计数同步、用户要求独立注入,以及既有范围/版本/检查点合同。
+
+前端验证覆盖 `agent-materials.test.js` 和 `agent-timeline.test.js` 共 30 项,包含普通检索在运行和结束状态下的展示、完整分析展示与时间线行为。
+
+### 故障材料隔离回放
+
+使用工具 `tools/verify_context_recovery.py`,复制目标任务、材料与检查点到独立目录,禁用模型网络调用,逐字验证替换的所有旧工具结果都能通过归档目录还原。未复制模型配置记录中的密钥。
+
+| 指标 | 结果 |
+| --- | --- |
+| 原图消息 | 38 |
+| 原有效消息 | 24 |
+| 外置并逐字还原核验的旧工具结果 | 9 |
+| 修复前保守上下文单位 | 493719 |
+| 修复后保守上下文单位 | 45358 |
+| 降幅 | 约 91% |
+| 保留的原文条数 | 2146 |
+| 模型网络调用 | 0 |
+
+隔离材料仅保存在本机 `tmp/context-recovery-verified-20260914/`,其中含用户聊天原文,不应提交到仓库。可复用脚本重新构造隔离回放;输出目录须不存在,避免覆盖旧结果。
+
+### 实际恢复
+
+重启桌面开发应用及后端,健康检查通过后,使用原任务的 continue 接口从失败检查点继续。实际完成指标记录在同目录的 `ai-context-recovery-live-verification-2026-09-14.json`,只保存状态、计量和调用统计,不保存答案或聊天正文。
+
+实际任务最终状态为 `completed`,错误为空,读取 2209 条,保存答案 2420 个字符。重启后的用量审计有 22 次成功的主任务调用、0 次摘要调用;完成时最后一个主请求占用约 13.9% 的保守输入预算。整个任务累计工具/模型次数包含修复前运行,不能直接当成本次新增调用数。
+
+浏览器实测确认:运行提示显示“已读取 2209 条,按需检索”,最终答案及 34 个来源入口正常显示,停止按钮恢复为提问入口,旧摘要错误消失。补齐运行提示后重新执行前端两组测试,30 项全部通过。`git diff --check` 无错误。
+
+## 验证边界
+
+这次修复移除了“必须生成 8192 字节摘要,否则整个任务失败”的机制,并为必要的摘要保留了持久化恢复与归档后备。它不声称任意模型生成的摘要在语义上绝不遗漏。用户要求、程序执行状态与完整原文独立保存,阶段记录明确区分于证据,事实需要回查来源。普通问答的结果也不代表逐条分析完全部历史。
diff --git a/docs/ai-context-recovery-live-verification-2026-09-14.json b/docs/ai-context-recovery-live-verification-2026-09-14.json
new file mode 100644
index 00000000..f810cfd8
--- /dev/null
+++ b/docs/ai-context-recovery-live-verification-2026-09-14.json
@@ -0,0 +1,41 @@
+{
+ "id": "8fbda9940a8f4587b3380a36262a4c10",
+ "status": "completed",
+ "error": "",
+ "read_count": 2209,
+ "used": {
+ "tools": 93,
+ "models": 51,
+ "media": 0
+ },
+ "stage": "正在回答",
+ "finished_at": 1789358208.5420885,
+ "context_budget": {
+ "run_id": "8fbda9940a8f4587b3380a36262a4c10",
+ "version": 1,
+ "used": 138270,
+ "input_capacity": 991296,
+ "model_window": 1000000,
+ "output_reserve": 8192,
+ "safety_reserve": 512,
+ "percent": 13.9,
+ "measurement": "conservative_estimate",
+ "unit": "budget_units",
+ "description": "文本按 UTF-8 字节作保守上界估算,包含工具与请求封装;不是实测 Token。",
+ "model_id": "deepseek-flash",
+ "profile_id": "f0003c514c8b41e5be0a67c50beeea5f",
+ "reasoning_effort": null,
+ "updated_at": 1789358079.2401712,
+ "conservative_units": 138270
+ },
+ "answer_chars": 2420,
+ "new_usage_calls": 22,
+ "new_usage_purposes": {
+ "deepagents_agent": 22
+ },
+ "new_usage_statuses": {
+ "success": 22
+ },
+ "input_tokens": 809424,
+ "output_tokens": 28960
+}
\ No newline at end of file
diff --git a/docs/ai-diagnostics.md b/docs/ai-diagnostics.md
index 77f2815f..8a1f5ef8 100644
--- a/docs/ai-diagnostics.md
+++ b/docs/ai-diagnostics.md
@@ -91,6 +91,8 @@ rg '任务或运行ID' 'D:\实际output目录\logs'
AI 普通请求使用 `X-WCDA-AI-Trace` 请求/响应头,保留 Agent 原有 request_id 的业务去重用途。浏览器原生 EventSource 无法设置自定义请求头,使用经过校验的 `ai_trace` 随机编号关联 SSE,服务端仍返回 trace 响应头。
+Agent 进度使用单条长连接:事件写入 SQLite 后通过进程内条件变量立即唤醒订阅者,SQLite 同时保留 `Last-Event-ID` / `after` 断线重放能力;空闲连接每 15 秒发送一次注释心跳,不再按 100ms 查询事件表。前端首次进入时读取一次运行快照,连接正常后仅合并 SSE 增量和终态快照;只有自动重连、事件版本跳跃或 SSE 断线时才读取权威快照,断线期间启用有限的保底轮询。
+
## 验证与限制
新增回归覆盖并发上下文和线程池、恢复执行 ID、HTTP 本机限制/体积/白名单、INFO/DEBUG/SDK/异常栈的敏感哨兵、跨天并发写入、重复初始化、目录重建、output 切换、模型错误与重试、流式日志条数、索引回滚、前端队列/SSE、通知阶段和桌面离线兜底。
diff --git a/docs/ai-event-pipeline-real-verification-2026-09-12.md b/docs/ai-event-pipeline-real-verification-2026-09-12.md
new file mode 100644
index 00000000..33250add
--- /dev/null
+++ b/docs/ai-event-pipeline-real-verification-2026-09-12.md
@@ -0,0 +1,74 @@
+# 活动报告:一次原文提取与定向核验
+
+## 实现与适用范围
+
+源码已默认启用 `activity_events_v2`。针对单一会话、明确时间区间(不超过31天)、不分析附件的活动时间线或汇总。其他检索、统计、按条数、跨会话与图片任务继续使用原有路径。读取和资料装批的前期优化仍适用于原有路径。
+
+流程为:保存全部原文与稳定游标 → 按日及文本预算提取活动 → 定向核对遗漏 → 独立检查进展与语气 → 按日期生成带原句、发言人及出处的报告。全文提取保留模型思考;短复核使用辅助调用,用户显式设置的思考等级仍保留。模型请求上限为8个并发;没有更换供应商或所选模型。
+
+本地原文容量与模型上下文分开,不再为读取一页聊天反复生成中间笔记,也不再让模型重新写整篇答案。相邻讨论保留上下文;每条原文属于一个主提取批次,边界原文可作为邻句重复出现。
+
+真实引用编号并不能保证模型摘要忠实。因此对外报告采用按日期和进展组织的关键原句;自由改写的摘要不参与正文或追问笔记。原文引号、条件、问句、比分、姓名保留。日历和星期由程序生成。最终明确取消不能被较早报名覆盖;条件式取消不视为已取消。
+
+漏项按单条原文和相邻上下文短核验。模型漏抄指定出处时,程序补回真实原句,再进入独立分类检查;不把空结果当作已经排除该讨论。摘要分类仍属于模型判断,不能声称所有玩笑和暗语都能百分之百识别。
+
+## 真实测试方法
+
+与截图同一原问题、同一原库和同一 `mimo-v2.5` 配置快照,北京时间 `[2026-09-01 00:00, 2026-09-11 00:00)`,共3027条,不分析图片。使用独立任务库,真实模型请求;未修改生产会话,密钥只在内存中使用。
+
+从零运行与恢复运行分开记录。速度与截图中的失败任务对比,不能冒充两份合格答案之间的质量A/B实验。模型服务耗时会波动,单次测量不是所有问题的耗时承诺。
+
+## 实测记录
+
+最终使用 `events-v2-fresh10` 的真实模型结果,随后追加生产代码中的两个确定性保护并做本地复放。**20项人工回归用例通过;不是总体100%准确率。**
+
+| 测量项 | 结果 |
+| --- | ---: |
+| 截图原运行 | 1227.56秒后失败,仅读取1907条 |
+| 本次从零真实后端运行 | 293.77秒,约4分54秒,completed |
+| 本次读取步骤 | 46.22秒,7页,共3027条 |
+| 完整原文主提取 | 11批,逐条集合、正文和元数据与基线相同 |
+| 日期组 | 10组 |
+| 归类讨论 / 不同出处 / 引文 | 135 / 238 / 263 |
+| 模型请求 / 失败请求 | 105 / 0 |
+| 图片调用 / 中间模型压缩 | 0 / 0 |
+| 最终本地规则复放 | 0.13秒,0次模型调用 |
+| 最终原文回归检查 | 20项通过 |
+
+运行ID为 `9d18d2980623457181eaa2336760e3a1`,配置快照与原任务相同,没有恢复或复用其他真实测试的模型缓存。105次调用的已知用量为输入371848、输出69913 Token,均有用量记录;本地引文校验引起的额外请求也在次数和耗时中。
+
+最后的两条规则只作用于模型之后:将单纯分场名单与“我们在几号场”从已举行改回安排;引用摘录如果只截到别人被转引的话,就补回完整连续回复,保留引用者和被引用者。生产代码和本地复放调用同一个 `finalize_event`,没有逐条手工修改答案,也没有改变此前模型请求。复放修正1项分场分类、补全10段回复上下文,出处集合和263段原文核对均通过。**293.77秒是原始从零模型流程的测量;0.13秒是追加规则的本地复放,不将其声称为第二次完整模型实测。**
+
+原运行、原答案及原核验文件保持不变。最终复放答案和人工结论位于:
+
+- `tmp/ai-latency-real-rerun/events-v2-fresh10/release-replay/answer.md`
+- `tmp/ai-latency-real-rerun/events-v2-fresh10/release-replay/verification.json`
+- `tmp/ai-latency-real-rerun/events-v2-fresh10/release-replay/semantic-audit.json`
+
+最终答案SHA-256:`0c8d804a4f194abed6f7102f1f749152dd7f4c460d9258158b495e6b96e0d6a8`。
+
+已保留的中间记录:`events-v2-fresh7` 从零245.61秒完成,读取步骤38.43秒;3027条原文、11个主提取批次、10个日期组、267段逐字匹配引文、249个不同出处。98次模型请求中1次失败并自动恢复,时间已计入。该版本仍漏标一处玩笑语气,因此不是最终质量验收结果。
+
+其已知用量为输入354977、输出61330 Token。提速依赖有限并发和短核验,不能据此宣称调用次数或费用同时降低。
+
+其他中间版本也保留原记录:fresh8在254.08秒因漏项出处校验失败;fresh9在276.10秒从零完成,但遗漏了不含“旅游/喝酒”字样的两处计划细节。最终补充了“月份+去某处”和换地点喝等通用模式,没有加入新的城市名单。
+
+## 质量验收口径
+
+程序核对原文集合、正文、发送时间、发言人、会话和定位锚点与独立基线逐条相同;检查每条主覆盖仅一次、每段引文连续匹配原文、出处存在、日期及星期正确、图片调用为0、中间模型压缩为0。
+
+另人工检查20项回归用例,包括取消、邀约与实际发生、条件、玩笑、猜测、旅游计划、比分胜负、个人退出、外群报名、活动场地及聚餐进展。用例没有发送给模型;它们用于开发回归,不是盲测或总体准确率。验收针对实际展示的原句与分类,不能把后台未展示的模型草稿当成最终回答。
+
+旧第14项用例的锚点有误:一条是“拍一拍”系统消息,另一条只补充场号;附近文字实际说“错过认识”,不能期待模型得出已经见面。新用例明确定位交手自述,并要求不捏造见面。旧用例和历史失败记录保留,修正记录位于 `tmp/ai-latency-real-rerun/event-quality-cases-v2.json`。
+
+## 恢复、测试与交付边界
+
+原文、批次结果、出处和核对状态独立保存。普通单批失败时其他批次继续保存,继续任务复用已完成部分;用户停止或修改范围会及时取消子请求。符合条件的旧失败v2任务在用户继续时可迁移到新流程;旧引擎不迁移,已完成报告不重写。
+
+专项测试覆盖主原文唯一覆盖、边界上下文、真实引文、伪引文拒绝、不会将自由摘要发布为事实、漏项补回后的独立核验、分类、取消与条件、停止与修改、失败恢复、模型思考设置及旧任务兼容。独立核验工具为 `tools/verify_ai_event_report.py`。
+
+最终默认开关启用后的相关测试:**124 passed**(`events-release-checks.txt`),包含原文归属与分场保护;此前账号级助手、连续阅读、超时与协议的扩展回归为 **162 passed**,两组有重叠,不能相加。`git diff --check`未发现空白错误。
+
+报告采用较详细的分类摘录,仍有重复讨论;这些回归用例不证明全部原文语义无遗漏。超大单条消息仍受模型窗口约束,其他模型和数据规模没有用此次结果证明同样耗时。原文可追溯、不中途静默丢弃与所有语义判断都正确,是不同的保证。
+
+本次工作修改当前工作区源码。没有重打包或替换已安装的桌面应用,也没有改写原生产会话。运行当前源码并重启后端才会加载新代码;安装版需要包含这些源码的后端构建。
diff --git a/docs/ai-latency-batching-2026-09-12.md b/docs/ai-latency-batching-2026-09-12.md
new file mode 100644
index 00000000..66d84d13
--- /dev/null
+++ b/docs/ai-latency-batching-2026-09-12.md
@@ -0,0 +1,33 @@
+# 长报告等待与批次恢复修复
+
+本文保留首轮修复及诊断过程。后续已改为独立批次笔记、预读缓存和临时短出处编号;最终实现与真实复测以 [十天群聊报告复测](ai-latency-real-verification-2026-09-12.md) 为准。
+
+对应失败运行 `b2490a7a51584bdf89ad2a96d84601ee`:总耗时 1227.56 秒,28 次读取保留 1907 条唯一原文;第一次阶段笔记请求等待约 900.8 秒后连接失败,随后两次 HTTP 500。模型排队时间为零,没有成功提交笔记。独立原库核对的完整范围为 3027 条,不能把已读部分当作完整报告。
+
+## 行为变化
+
+- 原文单批预算独立于模型最大窗口,初始上限 48 KiB,按消息必要字段序列化后的 UTF-8 字节计算,不等同于实测 Token。保留约 15% 的近期原文作为批次间上下文;原文、来源及全部已提交笔记继续保存在任务库。
+- 当前原文接近批次上限时提前整理。旧失败任务的大批原文会先重新排入持久化队列,再逐批处理;不清空原文、不重置读取游标、不改用户查询范围。
+- 阶段笔记输出最多 8192 Token,笔记正文另受 16 KiB 和原上下文预算两者较小值限制。意图和背景最多 4096 Token;工具决策首次使用小额度,仍保留截断后的有限增加额度与校验。模型、原生思考等级和最终回答输出配置不变。
+- 笔记调用的整体等待预算为 120 秒,意图/背景及工具决策为 90 秒,最终回答为 240 秒;普通模型调用默认 180 秒。同一逻辑调用的排队、网络响应和重试共享截止时间,持续流式输出也不延长截止时间。取消仍沿原路径传播并记账。
+- 大批笔记遇到超时、连接错误或上游暂时错误时,停止原样重试,由任务层减小批次,最多连续拆分三次、最小 6 KiB。小批仍保留有限重试;成功提交后重置连续失败次数。鉴权、用户取消和数据库事务错误不会被当作可拆批故障。
+- 预算受控的有序消息页可直接消费并按消息身份游标续读,减少因为 `has_more` 就反复二分时间范围的查询。超长原文分片、同秒身份去重及时间边界规则保留。
+- 真实复跑继续发现读取页误将已加入结果的完整本地 `media` 数据计入文字预算,导致后续消息过早被拒绝。改为增量累计必要文字字段的大小,本地原文和媒体元数据仍完整保留;加入大媒体字段及同秒续页回归。
+
+## 验证与限制
+
+新增 `tests/test_ai_latency_budget.py` 验证挂起调用超时、排队超时、持续流式输出截止、8192 输出上限、服务错误与鉴权分类、旧大批次拆分、失败后跨服务恢复及逐字符覆盖、分页查询次数。
+
+回归结果:协议、账号级助手、引用核查与恢复、历史上下文、消息分页及前台优先级组合 171 项通过;新增耗时预算、供应商适配与日志组合 76 项通过;耗时预算与读取预算/时间游标组合 40 项通过。各组合存在重叠,不相加作为独立测试总数。首轮既有组合曾出现 1 项失败(决策输出截断后未增加额度),修正后协议回归通过;其余连续笔记事务与覆盖测试首轮通过。
+
+对上述真实失败任务进行隔离复验,生产数据库以只读方式读取,临时任务只使用模拟笔记函数:1907 条已保存原文分为 14 批处理,所有原始数据库行保持一致,已提交笔记覆盖全部 1907 条。单批原文不超过 49152 字节,带任务背景等内容的笔记提示约 62–78 KB;原任务保持失败状态且完全未改动。结果为 `tmp/ai-latency-snapshot-result.json`。
+
+该隔离复验不发起真实模型调用,不验证笔记语义质量,也不能用其本地执行秒数承诺真实报告耗时。分批后保留完整遍历要求,没有把长报告改成抽样,也没有为整份报告设置会提前返回不完整答案的总时限。
+
+## 真实复测
+
+用户随后要求重新跑一次并核对质量、速度。真实复测记录在 `tmp/ai-latency-real-rerun`,正式接口运行 ID 为 `466fada576de414289b332af362a87ac`。该任务由当前软件后端执行;模型快照、思考配置、时区、查询范围与原失败任务完全相同,模型为 `mimo-v2.5`。最终验收结论以本目录后续真实复测报告为准,不能用上述离线回归代替。
+
+此前三次诊断运行均单独留档:第一次因重复缩小时间窗口而主动停止;第二次因本地媒体数据误计入文字预算而主动停止;第三次被软件后端重启的启动恢复逻辑标记为中断。它们均不是完整成功的速度样本。正式接口运行前,读取预算、时间游标及新增耗时测试组合共 48 项通过。
+
+真实模型运行已经暴露出当前方案的限制:累计笔记仍被反复重写,8192 Token 上限可能导致输出截断及后续重试;缩小原文批次不能消除旧笔记的输出体积。已提交笔记还出现错误补日期,以及早期活动未被保留在后续累计摘要的问题。保护调用时长不等于报告整体提速,来源存在校验不等于事实语义正确。
diff --git a/docs/ai-latency-real-verification-2026-09-12.md b/docs/ai-latency-real-verification-2026-09-12.md
new file mode 100644
index 00000000..5a633322
--- /dev/null
+++ b/docs/ai-latency-real-verification-2026-09-12.md
@@ -0,0 +1,76 @@
+# 十天群聊报告:读取与模型耗时复测
+
+后续质量实测见 [活动报告真实复测](ai-quality-real-verification-2026-09-12.md)。下文保留当时实验记录;后续已恢复事实提取的模型思考设置,并默认关闭未通过语义验收的实验报告路径。不能将本文的辅助思考优化描述当作最终生产配置。
+
+## 复测条件
+
+复用截图对应的原问题、账号、群聊、时区和模型配置快照。范围为北京时间 2026-09-01 00:00 至 2026-09-11 00:00,左闭右开。独立原库基线为 3027 条消息;不分析图片。真实模型为 `mimo-v2.5`。
+
+原失败任务 `b2490a7a51584bdf89ad2a96d84601ee` 耗时 1227.56 秒,28 次读取共保存 1907 条原文,0 条完成分析,0 份笔记,未生成完整报告。首次笔记请求等待约 900.8 秒后连接失败,另两次请求返回 HTTP 500。原任务不是成功报告基准,不能用它计算完整报告质量的 A/B 胜率。
+
+复测使用独立任务数据库,读取同一真实聊天源并调用同一模型。密钥只在进程内存中使用,没有复制到复测产物。正式应用后端中途退出后,独立进程用于避免应用重启影响实验;此次结果不代表已经完成桌面界面验收。
+
+## 最终实现
+
+1. **读取与模型批次解耦。** 原库按较大页面预取,再按模型文字预算消费。预取缓存按任务、版本、账号、会话和时间范围隔离,最多 8 页、总计 8 MiB,任务结束释放。续读仍用稳定消息游标,不因同秒消息而漏读。
+2. **修正文字预算。** 本地媒体元数据不再误计入模型文字预算;原始媒体信息仍留在本地材料中。已经按预算读取的页不再反复二分时间范围。
+3. **独立批次笔记。** 新任务每批原文上限 96 KiB,只提取本批事实,不再反复让模型改写全部旧摘要。已提交笔记沿事务根节点汇集,保留全部来源;失败时不释放尚未通过校验的原文。旧任务沿用兼容路径。
+4. **减少辅助思考。** 官方 MiMo 端点、明确支持开关且用户没有设置思考等级时,意图识别及新任务的逐批事实提取关闭深度思考。最终综合回答仍保留默认思考,显式用户设置优先。依据:[MiMo 官方思考模式文档](https://platform.xiaomimimo.com/docs/en-US/usage-guide/passing-back-reasoning_content)。这项属于模型行为变化,不能宣称理论上完全没有质量风险。
+5. **缩短模型出处编号。** 请求使用临时短编号,输出经过确定映射还原为真实出处;未知编号仍拒绝。已知编号列表的格式变体可严格解析,避免因模型漏写长 ID 而整份回答重试。原文及用户问题不被替换。
+6. **约束等待与重复输出。** 单次模型步骤和其网络重试共享截止时间;流式迭代显式检查截止时间。最终回答合并同一活动的重复报名,保留变化与关键出处。暂时性大批请求失败可缩小批次恢复。
+7. **保持质量校验。** 直接引文与来源错配仍触发校验,不以删事实通过检查。模型自行添加、且与日历冲突的括号日期仅撤回到有原文支持的星期表达;明确年月日的 Markdown 标题由程序核算星期。这些检查不等于完整语义验证。
+8. **明确范围由程序换算。** 模型摘录时间条件时可能带上“的聊天”等尾词;此前这会让严格日期解析失效,退回模型提供的错误 Unix 秒。补齐这类明确尾词的解析,仍不猜测未知时区或跨日日期,并通过集成测试验证错误年份会被覆盖。
+
+## 已确认的读取结果
+
+独立真实读取实测 10.203 秒,4 次原库查询,22 个模型预算页面,3027 条唯一原文,与独立基线相比 0 漏读、0 多读。证据:`tmp/ai-latency-real-rerun/prefetch-real-result.json`。这是读取组件耗时,不是包含持久化、人物资料处理及模型分析的整份报告耗时。
+
+## 真实试验中的失败也保留
+
+`validated` 试验已读并分析全部 3027 条,提交 12 份笔记,但最终回答生成约 418 秒后因一个截短的长出处编号失败,整次 774.9 秒,不能计为成功。随后复用笔记的 `final-recovery` 首次回答约 133 秒,仍因出处列表格式而重试,最终在 240 秒预算附近退出。为此补充了严格的短编号列表解析及回归测试。
+
+`final-clean`(`359bb83ea80b41f0b1167d5238426683`)试验发现时间原话带“的聊天”后未命中程序解析,模型把年份换算成 2025,已主动取消,不能作为同范围速度样本。随后补齐明确尾词支持,并让复测在读取开始时立即断言时间范围和会话与原任务一致。
+
+最终从零开始的 `final-corrected` 使用上述完整修复,运行 ID 为 `3b17d5a3c2d7448a9cdbd216ffdaab51`。其最终耗时、覆盖核验和语义抽查记录在下文,不能用早期失败样本或本地单元测试替代。
+
+## 自动化回归
+
+最终修改后,增量笔记、耗时预算、引用恢复组合 33 项通过;账号级查询条件组合 59 项通过,包含明确日期、跨日、时区、消息数量和旧查询范围兼容测试。`git diff --check` 对已修改的主要受版本控制文件通过。早期较大回归组合及其限制见 `ai-latency-batching-2026-09-12.md`,不将多次运行的重叠测试相加。
+
+## 最终实测结论:读取改善,整份报告尚未成功
+
+| 项目 | 截图原任务 | `final-corrected` 从零复测 |
+| --- | --- | --- |
+| 任务状态 | 失败 | 失败,最终回答超时 |
+| 总耗时 | 1227.56 秒(20 分 27.6 秒) | 725.16 秒(12 分 5.2 秒) |
+| 读取并保存原文 | 1907 条 | 3027 条,与原库逐条一致 |
+| 读取步骤累计 | 约 262.7 秒 | 46.20 秒 |
+| 完成分段分析 | 0 条 | 3027 条,全文字符覆盖通过 |
+| 已提交笔记 | 0 份 | 12 份,共 137 项 |
+| 整理笔记累计 | 无成功提交 | 409.90 秒,包含 2 次引文校验重试 |
+| 最终回答 | 未完成 | 约 241 秒后退出,未完成 |
+
+读取比较不是同等工作量:原任务只读部分,新任务读完整范围。可以确认重复查询和读取预算问题得到明显改善,不能把两次失败任务的总耗时差称为“完整报告提速 41%”。读取组件的 10.203 秒不包括记录落库及人物资料等处理,因此与实际步骤累计的 46.20 秒分别列示。
+
+最终生成第一次模型尝试约 107.57 秒、第二次约 56.26 秒,均因直接引文与来源错配未通过;第三次在剩余共享预算耗尽后停止。输入约 9.8 万 Token,最终生成仍然是长请求。每次引用校验失败整篇重写,是当前剩余的主要放大因素之一。
+
+随后补充两项修正:引用纠错提示也使用模型本次所见短编号;日期标题兼容省略年份及括号前空格(仅当查询范围明确同年时补年份)。后者只修正可确定的标题星期,不猜测正文活动日期。对应增量笔记及引用恢复组合最终 19 项通过,包含旧累计笔记、新独立笔记的校验失败保护。
+
+`final-repaired` 复用相同原文和笔记再尝试最终生成,没有重读或重新提取。该尝试约 241.80 秒后超时,未返回可用模型响应或用量,累计有效执行时间 966.96 秒。故无法用这一真实调用证明短编号纠错修正已改善模型行为,也不能宣称最终版本已完成一次从零成功测速。所有诊断进程均已结束。
+
+## 质量核验与未解决项
+
+- **读取完整性通过**:正确会话、正确左闭右开时间范围,3027 条原文无漏读或额外记录,消息定位和发送时间与独立原库基线一致,全部正文字符进入已提交批次,媒体调用为 0。
+- **持久化事实和来源结构通过**:12 份笔记、137 项记录留存,笔记来源均存在。失败后保留的回答片段有 129 个已知出处,但这不代表这些出处都支持对应结论。
+- **部分内容确实保留**:9 月 1 日的“没人打 休息吧 炸车”及次日取消确认、9 月 5 日取消、带菜与喝酒邀约等在笔记和回答片段中可见。证据示例:`91dbf37dbfdc9d4ce757a2eb`、`845c9fa5d28e6f65b634b4fb`、`afa27c3596d91297d4d212aa`、`511471d397c4a02291ebca11`。
+- **语义质量未通过**:失败片段仍把 2026 年日期按 2025 年星期排列;正文存在“下周三(9 月 10 日)”这种错误日期补全。标题显示修复已补齐并测试,正文中的推断仍需进一步处理。
+- **活动分类存在过度推断**:把“今晚去哪里 A 钱”“今晚星宸了”等含糊话语确定写成 AA 聚餐,原话本身不能证明这种解释。单纯减少模型思考并不保证事实提取质量无损;原失败任务没有完整报告,无法做成功报告之间的语义质量 A/B 对照。
+- **整体未通过验收**:最终校验结果 `passed=false`,因为任务未完成。校验脚本仅核查结构及覆盖,不冒充语义评审。
+
+后续要改善整份报告,需要将引用错误改为只修正有问题的段落并重新校验,避免每错一处就重写整篇;在保留逐批事实和上下文衔接的前提下,再评估有限并发的笔记提取。两项均尚未实现或真实测速,不能作为此次已交付效果。上游响应延迟也无法靠本地读取缓存消除。
+
+## 证据位置与应用状态
+
+所有复测材料在 `tmp/ai-latency-real-rerun/`。`final-corrected/metrics.json` 为从零失败样本,`final-repaired/metrics.json` 为恢复后的累计样本,`final-repaired/verification.json` 为最终结构核查;`quality-source-pairs.json` 提供失败片段与原文对照,不应作为完成报告交付。
+
+代码已修改,未提交 Git、未打包发布,未完成桌面界面验收。测试中使用独立后端进程;已安装软件若不加载这份工作区代码,不能直接获得这些变化。工作区后端需重新启动后才会加载修改。
diff --git a/docs/ai-macos-compatibility.md b/docs/ai-macos-compatibility.md
index cb80a9f3..7d09033f 100644
--- a/docs/ai-macos-compatibility.md
+++ b/docs/ai-macos-compatibility.md
@@ -2,6 +2,8 @@
更新时间:2026-09-08。此文档区分组件验收与完整桌面验收,不以模拟测试代替真实聊天流程。
+**2026-09-10:下列 Mac 记录属于旧版本,仅作参考。本轮全账号助手尚未在 Mac 实机验收;最新状态与执行方法见 [本轮验收记录](ai-assistant-implementation-2026-09-10.md)。**
+
## 运行策略与修复
- AI 服务、总结、Agent、关注提醒和用量审计使用共享 Python / Vue 实现。模型接口仍读取用户配置,不写死模型名称。
@@ -63,10 +65,12 @@ Windows 对应后端 132 项、Vue 168 项、桌面 8 项回归通过,公共
## 复验入口与证据
+CI 与源码复验均显式使用 uv 托管的 CPython 3.11。仅运行 `uv sync` 或指定 `--python 3.11` 仍可能复用已有解释器;部分 macOS Python 构建缺少 SQLite 扩展加载能力,导致 sqlite-vec 初始化失败。
+
```sh
export UV_MANAGED_PYTHON=true
uv python install 3.11
-uv sync --locked --python 3.11 --extra build
+uv sync --locked --python 3.11 --managed-python --extra build
uv run python tools/verify_ai_runtime.py
uv run pytest -q tests/test_ai*.py tests/test_local_search*.py
cd frontend
diff --git a/docs/ai-model-reasoning-picker-2026-09-14.md b/docs/ai-model-reasoning-picker-2026-09-14.md
new file mode 100644
index 00000000..cc2d61d7
--- /dev/null
+++ b/docs/ai-model-reasoning-picker-2026-09-14.md
@@ -0,0 +1,37 @@
+# 模型与思考强度单入口
+
+输入框底部显示「模型 · 强度」。点击后打开绿色滑杆浮层;点击浮层中间的强度和模型名,在同一浮层进入模型列表,选好模型后返回滑杆。没有额外的标签切换栏。按后续反馈,浮层缩至约 240×89px、去掉闪电图标,定位到模型入口上方并覆盖输入框。保留服务分组、上游列表获取、手动模型 ID 与原有全局选择记忆。
+
+## 能力与参数
+
+- 读取 models.dev 的 `reasoning_options`,按服务、接口地址和精确模型 ID 匹配,保留该模型声明的档位顺序,不生成通用的五档。原生 SDK 供应商缺少 `api` 时使用官方入口匹配;同主机的 Coding Plan 采用最长接口路径匹配。
+- 档位型显示离散滑杆;开关型显示关闭/开启;只有预算型时显示原生 Token 预算范围,受当前输出容量限制。只有 `reasoning=true` 或未知能力时显示说明,不展示假的滑杆。
+- 模型配置中的手动等级优先;未知代理不直接继承同名官方模型的请求参数。已从代理上游获取的能力仍可使用。
+- OpenAI 兼容的等级使用 `reasoning_effort`;Claude 使用 `output_config.effort` 或预算形式的 `thinking`;DeepSeek、MiMo、Kimi、智谱、火山使用 `thinking.type`;百炼、硅基流动使用 `enable_thinking` / `thinking_budget`;OpenRouter 使用 `reasoning`;Gemini 预算通过兼容 API 的 `extra_body.google.thinking_config` 传递。
+- 切换模型会清除旧模型的显式强度参数。恢复默认会删除等级、开关和预算覆盖,不把默认伪装成中档。正在执行的任务使用原快照,新一轮采纳新选择。
+- 获取上游列表后重新解析当前模型能力,避免早先的空缓存遮住后来补齐的档位。
+
+## 接口
+
+新增只读 `GET /api/ai/profiles/{id}/model-capabilities?model_id=...`,返回合并目录、上游、手动覆盖后的能力,不包含密钥。`selected-model` 与轮次输入增加可空的 `thinking_mode`、`thinking_budget`,继续兼容原 `reasoning_effort`。默认选项保留原响应结构。没有数据库迁移。
+
+## 验证
+
+前端累计 326 项 Vitest 回归通过;后端相关 92 项通过(最终新增的火山参数用例包含在其中)。覆盖 SDK 构造出的请求体、非法/冲突参数拦截、配置覆盖、原生供应商无 api 字段、代理与 Coding Plan 隔离、保存重启、运行中补充与下一轮快照;没有调用付费模型。
+
+浏览器使用真实组件检查浅色/深色、440/320px 侧栏、360px 窗口,以及模型列表、滑杆键盘操作、默认恢复、焦点和菜单关闭。验收报告见项目根目录 `design-qa.md`。
+
+重启前确认运行中/排队任务为 0。项目启动器 PID 38760;前端 3000、后端 10392 的健康检查均为 200,启动错误日志为空。真实已配置模型返回:deepseek-flash 为关闭与 low/high/max;mimo-v2.5 为开关。只读检查能力,不自动执行用户问题。
+
+## 参考
+
+- [models.dev 数据目录](https://models.dev/api.json)
+- [models.dev 能力结构](https://github.com/anomalyco/models.dev#3a-reuse-model-metadata-with-base_model)
+- [Claude effort](https://platform.claude.com/docs/en/build-with-claude/effort)、[扩展思考](https://platform.claude.com/docs/en/build-with-claude/extended-thinking)
+- [DeepSeek 思考模式](https://api-docs.deepseek.com/guides/thinking_mode/)
+- [Gemini OpenAI 兼容 API](https://ai.google.dev/gemini-api/docs/openai)
+- [OpenRouter 推理参数](https://openrouter.ai/docs/guides/best-practices/reasoning-tokens)
+- [百炼思考参数](https://www.alibabacloud.com/help/en/model-studio/deep-thinking)
+- [智谱思考参数](https://docs.bigmodel.cn/cn/guide/capabilities/thinking)
+- [硅基流动推理参数](https://docs.siliconflow.cn/docs/userguide/capabilities/reasoning)
+- [火山官方 Go SDK 请求类型](https://pkg.go.dev/github.com/volcengine/ark-runtime-go/arkruntime/model/chat)
diff --git a/docs/ai-parallel-analysis-2026-09-14.md b/docs/ai-parallel-analysis-2026-09-14.md
new file mode 100644
index 00000000..63eea082
--- /dev/null
+++ b/docs/ai-parallel-analysis-2026-09-14.md
@@ -0,0 +1,70 @@
+# 聊天分析子 Agent 并行编排
+
+本次将新任务的范围委派改为按内容量组织的持久化流水线。主 Agent 确定目标和核查问题,程序负责来源身份、正文归属、执行队列和完成条件。没有升级锁定的 Deep Agents 依赖。
+
+## 执行路径
+
+- 普通搜索不预扫描全历史;精确数量、排名和频率继续使用程序统计。
+- 完整分析选择范围后,按安全资料页预算预读。容量约两页以内,主任务直接消费缓存,不产生子 Agent 模型请求。正式时间游标读取器在容量边界最多交付一条额外探测消息,下层数据库批缓存仍沿用既有边界。
+- 大范围通过官方 `task(scope_handle, subagent_type)` 进入内容队列。开始时间为零的单聊全历史也会并行。
+- 一个父任务的资料读取互斥,边读边存边执行;所有委派批次共用四个工作槽位和最多八个排队分片。模型层继续使用全应用四路上限、前台优先、父任务轮转与限流退让。
+- 每片目标为两页正文,优先在末尾 20% 的半小时间隔处分开。小会话可合片;超长正文使用已有字符断点。前后背景最多各十条,合计不超过一页容量的 10%,不计正文覆盖。
+
+## 数据与恢复
+
+`deep_partition.py` 管理计划、不可变原文快照、清单与队列;`deep_dispatch.py` 管理官方子任务执行、发现合并、分层归并和定向检索。新记录复用现有 SQLite 工作区表,独立按类型保存:
+
+| 记录类型 | 用途 |
+| --- | --- |
+| `analysis_plan` | 目标、范围句柄、计划版本、扫描游标、缓存队列、阶段和指标 |
+| `analysis_manifest` | 正文与背景的来源 ID、字符区间、快照及读取游标 |
+| `analysis_source` / `analysis_plan_source` | 不可变正文和计划来源索引 |
+| `analysis_prefetch` | 可直接消费的预读页 |
+| `analysis_reduction` | 汇总节点及所有输入节点 ID,支持断点复用 |
+| `analysis_focus` / `verification_rounds` | 独立目标缓存和核查证据轮次 |
+| `deep_search_coverage` / `deep_statistics_coverage` / `deep_media_result` | 搜索、统计与媒体覆盖,分别保存 |
+| `stage_note` | 已提交的正文字符覆盖,背景不在其中 |
+| `deep_calculation` | 已确认事件的程序计算输入、结果及来源 |
+
+`agent_subtask` 保留作业生命周期入口。新任务带 `subtask_plan_version=1`,作业与计划带 `plan_version=1`;历史未完成任务缺少该标记时继续原恢复路径,不重新分片。
+
+作业签名包含父任务及输入版本、计划版本、完整目标、角色和清单内容。完成的分片不重跑,失败分片保留其他成功结果。上下文超限时只对未提交字符重新分片,新清单与旧片替换状态在同一事务保存。停止或修改目标后,旧版本结果不能继续更新父任务。
+
+新输入版本在范围、筛选和截止时刻一致且前次扫描无缺口时复用已保存原文,重新分析新目标。快照描述的是实际读到的正文,不声称实时数据库提供整体事务快照。数据源恢复后,已提交字符区间从新读取结果中扣除。
+
+## 事实、汇总和核查
+
+范围分析员只提交局部事实;事实格式保留 `text + sources`,可附实体、事件时间、关系线索和证据状态。子任务的正文、原文回查、长文续读及内部材料文件全部受字符清单约束,不能借另一工具读取同一消息的未分配正文。官方默认通用子 Agent 旁路关闭,子任务不递归委派。
+
+汇总处理当前计划范围内的全部发现;不会只截取前几个子任务的摘要。大量结果保存分页索引,超过上下文预算时逐组归并,持久化各组依赖,恢复时复用已通过来源校验的节点。发现按来源与完整事实去重,保留来源不同、关系不确定或冲突的候选。
+
+主任务按问题决定是否做跨片关联和定向核查。同一目标、范围及证据集合不重复启动核查;最多两轮不同证据集合,独立专题检索不冒充全量覆盖。此上限不影响范围正文必须全部提交的要求。
+
+`calculate_values` 为确认后的同单位事件提供十进制求和、差值和极值计算,拒绝重复事件编号、待确认项与范围外来源。事件关系、数值提取和单位仍需依据原文确认,程序运算不替代语义核查。
+
+## 进度和计量
+
+界面直接显示阶段、运行/等待/完成/失败数、对象、实际时间、目标、读取与分析条数、当前动作和等待原因。扫描结束前显示已发现的分片数,不给虚假总百分比。被替换分片保留历史但不重复计总数;字符分片按自己的正文区间计算完成情况。
+
+计划 `metrics` 保存首次分片启动耗时、墙钟耗时、读取和分析来源数及字符数、重复提交字符数、恢复复用分片数。墙钟耗时包含暂停间隔;模型请求耗时与 Token 用量继续由现有 `usage` 审计记录。
+
+## 验证
+
+使用构造聊天数据、官方图中的确定性模拟模型与独立组件预览,没有访问真实聊天或付费模型。
+
+新增回归覆盖:小范围缓存复用、全历史单聊并行、同秒消息、跨会话最近 N 条、共享槽位、失败与取消恢复、长正文区间、清单工具隔离、跨版本原文复用、只拆未提交正文、全量归并及缓存、数据缺口恢复、核查去重及轮次、十进制计算和预读探测上限。
+
+验证记录:新增 24 项场景分批通过(首批 21 项,随后覆盖分类、媒体缺口归并/迟到防护、官方主任务委派入口各一项)。最后的原文及媒体隔离回归 8 项通过;相关 Deep Agents、恢复、媒体及调度回归 138 项通过,分页等另一组回归 110 项通过(这些批次有重叠,不相加)。前端子任务与时间线 33 项通过。
+
+固定模型延迟测试使用至少八个等量分片,验证四路分析耗时不超过单路的 50%。这是构造模型下的调度验收,不承诺真实模型相同倍数;真实模型的事实提取与跨期关系判断仍需用实际任务检验。
+
+相关命令:
+
+```powershell
+.\.venv\Scripts\python.exe -m pytest tests/test_ai_parallel_analysis.py -q
+.\.venv\Scripts\python.exe -m pytest tests/test_ai_time_reading.py tests/test_ai_incremental_notes.py tests/test_ai_latency_budget.py tests/test_ai_subtasks.py tests/test_ai_deep_contracts.py tests/test_ai_deepagents.py -q
+# 使用支持当前 Vite 的 Node 运行:
+node frontend/node_modules/vitest/vitest.mjs run --root frontend tests/agent-subtasks.test.js tests/agent-timeline.test.js
+```
+
+界面检查覆盖桌面、窄侧栏和 390 像素深色页面,没有横向溢出或页面脚本错误。预览截图位于 `tmp/parallel-analysis-qa/desktop-final.png` 与 `tmp/parallel-analysis-qa/mobile-final.png`。
diff --git a/docs/ai-planned-work-2026-09-14.md b/docs/ai-planned-work-2026-09-14.md
new file mode 100644
index 00000000..19594c09
--- /dev/null
+++ b/docs/ai-planned-work-2026-09-14.md
@@ -0,0 +1,62 @@
+# 主模型先分析、先规划,再按需并行
+
+本次将新任务切换为 `subtask_plan_version=2`,保留历史记录和旧引擎回归。没有升级 Deep Agents,也没有发起真实模型任务或恢复已停止任务。
+
+## 行为变化
+
+- 选择范围不预读、不创建分片队列;年份、数据量和模型填写 `complete=true` 均不能启动子 Agent。普通问题不会被模型自行升级为全历史分析。
+- 主模型必须取得真实读取、检索或统计回执,并填写初步发现、并行理由、自己保留的工作、分支具体目标与交付要求,才能创建计划。
+- 每轮最多三个子分支;资料范围或来源归属重叠、重复分支、未完成依赖、仅等待汇总的主线,以及未绑定计划的 `task` 都会被程序拦截。
+- 沿用官方 `task` 入口和隔离上下文。入口立即返回句柄;主模型继续分析,记录有来源的主线成果后,才可事件等待。分页不创建 Agent。
+- 分支输入支持已保存来源、明确全量任务的指定范围,以及独立范围内的固定检索目标。检索覆盖不会转成全量覆盖。
+- 首次模型请求已注入正文和提交编号;最后一页成功提交后直接结束子图,不追加收尾报告。无命中的检索页由程序处理,不调用模型。
+- 主模型读取所有分支事实页,再提交关联结论和缺口。来源、正文覆盖、媒体状态与十进制计算仍使用现有机制。
+- 停止及修订取消后台分支,迟到结果不能写入新版本。继续 v2 任务复用完成分支、分页与检查点;主动继续旧批量任务时建立 v2 执行版本,保留原文并重新规划。
+- 界面显示主线工作、并行理由、具体分支说明和预期交付;原始问题位于详情,停止后不显示虚假的运行数量。
+
+## 模拟回归
+
+仅使用临时数据库、构造聊天资料、真实官方执行图及确定性模拟模型:
+
+| 验证 | 结果 |
+|---|---|
+| 新规划回归 | 16 项通过 |
+| 主图、工具合同、答案检查点、追问范围 | 117 项通过 |
+| 子任务与运行时间线界面 | 34 项通过 |
+| 历史 v1 分片 | 原有 23 项通过;显式 v1 官方入口单独复测通过 |
+| 窄侧栏与宽面板浏览器检查 | 无页面错误、无横向溢出,主线及分支说明可见 |
+
+新规划回归覆盖:范围不自动委派、六类无效计划、完整任务说明绑定、首次资料注入、最后提交无额外请求、官方 `task` 异步返回、主模型同时工作、30 页只产生一个分支、三个子分支加主模型共用四路、停止时尚未启动的后台任务结算、空检索无模型调用、旧任务主动继续及版本修订的迟到结果。
+
+复测命令:
+
+```powershell
+.venv\Scripts\python.exe -m pytest tests/test_ai_planned_work.py -q
+.venv\Scripts\python.exe -m pytest tests/test_ai_deepagents.py tests/test_ai_deep_contracts.py tests/test_ai_answer_checkpoint.py tests/test_ai_followup_scope.py -q
+.venv\Scripts\python.exe tools/verify_planned_work_cost.py
+```
+
+## 固定资料的成本对比
+
+同一条构造证据、同一条局部发现,比较历史单页子任务与新规划单页分支。包含每次实际发送的提示词、历史和工具定义;使用同样的模拟模型配置。原始数据见 `ai-planned-work-cost-2026-09-14.json`。
+
+| 指标 | 旧分支 | 新分支 |
+|---|---:|---:|
+| 模型调用 | 3 | 1 |
+| 输入 Token 文本估算 | 23,355 | 3,346 |
+| 输入 UTF-8 字节 | 79,273 | 10,888 |
+| 同一正文进入模型次数 | 2 | 1 |
+| 重复正文 Token 文本估算 | 31 | 0 |
+| 有效发现 | 1 | 1 |
+
+Token 使用 `cl100k_base` 对序列化请求文本估算,不是实际供应商 Token 或账单。此对比测量分支固定开销,不包含新计划与主线整合的全部成本,因此不能推导真实整任务固定节省比例。普通问题默认不创建分支;是否值得并行仍先由主模型在真实证据基础上规划。
+
+程序可以校验真实操作、输入归属、来源、依赖及覆盖;初步发现和关系判断的语义质量仍由模型承担。无法确认的关系应保留不确定性。
+
+初次交付为代码与模拟验证;当时未重启服务,随后按用户要求重启。
+
+## 后续修正:撤销固定查证次数限制
+
+用户测试发现,搜索“借、还、欠”之后,继续搜索具体金额和读取原文被错误拦截。已删除三次资料操作后的工具隐藏、执行拒绝及强制收尾提示,同时撤销普通任务累计核查轮数上限。主模型按任务需要继续搜索、阅读和核查;子 Agent 仍须先形成有效分工。
+
+新增确定性回归:连续搜索“借、还、欠、2200、1500 周转、转账”,随后读取原文并回查上下文,全部成功且没有创建子任务。新编排回归更新为 17 项通过。
diff --git a/docs/ai-planned-work-cost-2026-09-14.json b/docs/ai-planned-work-cost-2026-09-14.json
new file mode 100644
index 00000000..c1be8259
--- /dev/null
+++ b/docs/ai-planned-work-cost-2026-09-14.json
@@ -0,0 +1,20 @@
+{
+ "scenario": "同一条构造证据、同一条局部发现、单页分支;含完整工具定义输入",
+ "measurement": "cl100k_base 文本估算,非实际服务商 Token 或账单;未运行真实模型",
+ "legacy": {
+ "model_calls": 3,
+ "input_tokens_cl100k_estimate": 23355,
+ "input_utf8_bytes": 79273,
+ "evidence_input_occurrences": 2,
+ "repeated_evidence_tokens_cl100k_estimate": 31,
+ "effective_findings": 1
+ },
+ "planned": {
+ "model_calls": 1,
+ "input_tokens_cl100k_estimate": 3346,
+ "input_utf8_bytes": 10888,
+ "evidence_input_occurrences": 1,
+ "repeated_evidence_tokens_cl100k_estimate": 0,
+ "effective_findings": 1
+ }
+}
diff --git a/docs/ai-quality-real-verification-2026-09-12.md b/docs/ai-quality-real-verification-2026-09-12.md
new file mode 100644
index 00000000..44c20e58
--- /dev/null
+++ b/docs/ai-quality-real-verification-2026-09-12.md
@@ -0,0 +1,78 @@
+# 活动报告真实复测:读取通过,语义验收未通过
+
+后续的一次原文提取流程、最终真实测试及本地防错规则验收见 [活动报告新流程实测](ai-event-pipeline-real-verification-2026-09-12.md)。本文保留旧实验的失败结论,不作为当前版本结果。
+
+2026-09-12 用户要求保证质量并实际测试。本轮真实调用最终生成完整报告,但人工语义抽查失败,因此实验路径已默认关闭,不能作为已完成的提速方案交付。
+
+## 真实条件与结果
+
+同一原问题、账号、坦洲羽毛球群、mimo-v2.5 模型配置快照。北京时间 [2026-09-01 00:00, 2026-09-11 00:00),独立原库基线 3027 条,不分析图片。使用隔离任务库、真实原库和真实模型,密钥只在内存中使用。
+
+任务 7186fb59116d4325b57b3c77e6036772 最终 completed:10 天、35 批、116 项、196 段原句、193 个不同出处。范围、会话、消息定位、正文字符覆盖及元数据与原库基线一致;0 漏读、0 额外记录。196 段引文连续匹配原文,日期顺序和星期正确,媒体调用为 0。
+
+**以上是结构与读取检查,不是语义保证。14 项独立人工用例:9 项通过、5 项未通过,整体质量不通过。** 用例没有输入模型,也不构成全量无遗漏证明。
+
+## 时间:恢复时间不是从零测速
+
+| 项目 | 结果 |
+| --- | --- |
+| 截图原任务 | 1227.56 秒后失败,只读 1907 条 |
+| 原任务读取步骤累计 | 约 262.7 秒 |
+| 本轮完整 3027 条读取步骤累计 | 45.43 秒 |
+| 本轮阶段笔记 | 400.47 秒,12 份、122 项 |
+| 本轮累计有效执行 | 1118.93 秒,约 18 分 39 秒 |
+| 最后一次恢复 | 42.09 秒,复用了已保存原文、笔记和通过批次 |
+
+本轮经历代码调整、失败和五次恢复。累计时间包含旧版本失败请求,排除停机修改间隔,**不是最终版本一次从零成功耗时**。不能用最后 42 秒声称整份报告只需 42 秒。原任务没有合格答案,无法比较两份合格答案的质量 A/B 胜率。
+
+独立读取组件先前实测 10.203 秒、4 次原库查询、3027 条与基线逐条一致;该数字不含完整持久化和人物资料处理,与上述 45.43 秒分开统计。
+
+| 尝试 | 本次有效执行秒数 | 结果 |
+| --- | ---: | --- |
+| quality-daily-v1 | 661.460 | 从零完成原文和笔记,报告未完成 |
+| quality-daily-v2 | 123.060 | 恢复,模型超时 |
+| quality-daily-v3 | 109.685 | 恢复,排除项校验失败 |
+| quality-daily-v4 | 19.033 | 恢复,上下文重复项触发校验 |
+| quality-daily-v5 | 163.605 | 恢复,长原句超过展示长度约束导致重试失败 |
+| quality-daily-v6 | 42.089 | 恢复生成完整报告,语义验收未通过 |
+
+## 人工语义核对
+
+通过的 9 项:9 月 1 日取消、9 月 5 日取消、A 钱与带菜的含糊性、HK 自述、川西推迟、东北计划、21 比 7 的人物和胜负、卤味送珠海的条件、外群报名及正确日期。川西与东北合项、部分信息分享分类仍不够清楚,单项通过不代表全篇质量通过。
+
+未通过的 5 项:
+
+1. 家附近“旅游”的调侃被分类为实际活动。
+2. 两条海边约会猜测被作为非活动排除,违反保留玩笑和不确定信息的要求。
+3. “带上球拍去打台球”只标信息分享,未区分玩笑式邀约。
+4. “明晚喝酒”被整体判为玩笑,邀约和后续“打完喝”没有完整保留。
+5. 星宸见面、打过球的这段文字证据遗漏,另一天的类似消息不能替代。
+
+另发现 9 月 9 日以分场名单和“今晚见”作为实际举行证据;连续报名名单重复展示,个人退报名与整场取消没有充分区分。输出共 23,585 字,原句堆叠没有实现简洁归并的报告要求。引文逐字正确也不能消除这些问题。
+
+## 实验实现及最终边界
+
+实验 daily_evidence_v1 对活动报告按日切成最多 100 条主消息一批,两批并发。全部原文均进入一个主批次,相关旧资料仅作上下文。模型提取分类和原句;程序核对原句并生成出处,不显示自由改写的事实描述。非球类候选必须引用或解释排除原因,但本轮证明排除理由也可能错误。
+
+批次独立缓存,失败只重做未通过部分。已知上下文重复项先核验原句再去重,不能掩盖伪引文或绕过本批候选检查。原句展示长度约束由 300 放宽到 2000 字,保留精确长接龙,不再为展示偏好反复请求。
+
+**最终代码决策:**
+
+- AgentService.report_policy = None:不默认启用实验报告,独立验收才显式设置策略。
+- 阶段事实提取恢复所选模型的思考设置,不再因使用增量笔记就自动关闭思考;实验原句提取仍可单独测试快速调用,显式用户思考配置优先。
+- 保留原库预取、正确文字预算、稳定游标、短出处映射、增量保存、有限等待和失败进度恢复。
+- 恢复默认思考后的最终生产路径尚未完成新的从零质量验收;此次实验耗时不代表该路径性能。
+
+## 验证及证据
+
+最终相关回归:test_ai_daily_report.py、test_ai_incremental_notes.py、test_ai_citation_recovery.py 共 **31 项通过**。覆盖伪引文、去重后候选检查、长原句不截断、缓存恢复、主批次完整覆盖、默认关闭实验和事实提取保留思考。此前账号级助手、连续处理、耗时预算、模型协议组合 144 项通过;不同组合不相加为独立总数。最终相关修改的 git diff --check 通过。
+
+证据目录 tmp/ai-latency-real-rerun/quality-daily-v6/:
+
+- verification.json:真实原库、独立消息定位基线、正文字符和元数据核对。
+- daily-verification.json:35 批覆盖、196 段原句、出处和日历检查。
+- semantic-audit.json:14 项人工决定、对应原文、时间及成品哈希,quality_passed=false。
+- answer.md:真实模型生成的完整报告,仅供检查失败样本,不作为合格报告交付。
+- run.json、usage.json、pieces.json、material.json:实际请求、进度和原文留档。
+
+没有打包发布或替换已安装软件,未完成桌面界面验收。**当前能确认读取改善,仍不能确认整份报告又快又准。** 后续须解决事项归并、状态证据和错误排除,并做从零实测;不能通过关闭思考或减少正文换取表面完成。
diff --git a/docs/ai-real-data-acceptance-checklist-2026-09-11.md b/docs/ai-real-data-acceptance-checklist-2026-09-11.md
new file mode 100644
index 00000000..d80450a9
--- /dev/null
+++ b/docs/ai-real-data-acceptance-checklist-2026-09-11.md
@@ -0,0 +1,81 @@
+# AI 助手真实数据验收清单
+
+当前源码以 [集中开发状态](ai-assistant-development-status.md) 为准。先集中完成全部功能,随后按本清单统一验收 Windows,最后验收同版本 Mac;不再逐项修改后单独跑一轮真实模型验收。
+
+最新记录:[阶段 59:报告范围、程序时间与初始 SSE 游标](ai-assistant-acceptance-2026-09-12-stage59.md)。真实报告的时间换算已改善,来源对应和内容语义仍有失败项,整项未完成。
+
+最新记录:[阶段 58:真实续写修复](ai-assistant-acceptance-2026-09-12-stage58.md)。原任务已从半截来源续写完成,原文、笔记和配置保持;完整报告范围与内容仍未通过。
+
+最新记录:[阶段 57:补充、停止与主窗口重启](ai-assistant-acceptance-2026-09-12-stage57.md)。真实续写发生重复,尚未通过;已加载状态与半截引用显示修复。
+
+最新进展:[阶段 56](ai-assistant-acceptance-2026-09-11-stage56.md),全账号最近 5 条真实 UI/模型结果与独立基线一致;图片、输入法与窗口恢复有原生证据,SSE 断开重连仍未通过。
+
+最新 Windows AI 实测与剩余事项见 [阶段 55 记录](ai-assistant-acceptance-2026-09-11-stage55.md)。该记录保留失败、派生数据修复和真实搜索复验的区别;整项尚未通过。
+
+这是当前工作区候选版本的执行清单,不是通过证明。先完成 Windows,版本稳定后再对同一源码清单执行最终 Mac 验收。旧合成数据、旧 Mac 结果和旧进程的运行结果不能替代本清单。
+
+## 当前启动前提
+
+- 2026-09-12 14:07 已通过 `desktop` 的 `npm run dev` 启动当前源码:前端 3000、后端 10392,使用现有真实账号目录。统计出处与调用耗时修复已加载;随后修复 Nuxt 自动导入导致的前端初始化失败,原生窗口已恢复真实聊天和正在运行的 AI 任务。准确测试结果与尚未验证事项见 [集中开发状态](ai-assistant-development-status.md)。
+- 真实模型统一使用从软件“设置 → AI 配置”保存的 Xiaomi `mimo-v2.5`。旧 DeepSeek 任务保留配置快照,不能拿旧任务继续请求作为新模型验收。
+- 2026-09-12 重启时自动审批曾阻止 Electron 启动;随后主窗口和后端恢复,已通过原生设置保存 Xiaomi `mimo-v2.5` 并设置为默认文本/视觉模型。设置保存证据在 `windows-integrated-63/`,真实推理结果另行核对,不以模型列表获取成功代替。
+- 历史候选 63 的未完成报告保留 1907/3027 条、0 份笔记、4 次真实调用;笔记请求连接失败,后两次重试 HTTP 500。随后普通提问及原生连接测试也失败,证据在 `windows-integrated-63/`。14:07 后 dev 中已有新报告保存阶段结果并继续读取,不能把此前服务失败当作当前状态,也不能将当前进度当作报告已经通过。下文 1284 条或 5524 条等旧阶段数据不能替代此次基线。
+
+## 历史启动记录(保留阶段事实,不代表当前进程)
+
+- 第 54 阶段第 15 次调用已完成报告:5524 原文、6 份笔记、全字符覆盖、多轮真实压缩、382 条消息引用的结构核对通过,内容语义仍失败(邀约时间误作活动时间、末尾总括否定已证实比赛)。通用提示词已调整但尚未加载/真实复验。此前布局问题是截图误判,两处 CSS 已撤回;正式静态目录恢复为 `real-data-54/ui-build/public` 的内容,下一次界面验证应刷新正式构建。
+
+- **当前最新**:22:49:17,Electron 32176 / 后端 31656,已加载第 54 阶段引用、SSE、续写、传输分类与出处栏高度修复。两次中断的正文继续保存,当前第 15 次调用接着原来的 20172 字符续写;5524 原文、6 份笔记和版本/配置/游标重启前后一致。真实界面已核对第 269 条来源,最终回答、语义和全部 Windows 条目仍未通过,未进入最终 Mac 验收。
+
+- 最新实际进程为 **22:03:11** 启动的 Electron 11160 / 后端 8088,加载第 53 阶段及已知引用类型补全。第 13 次真实报告因远端流中断于 22:24:34 失败,已读 5524 条和 6 份笔记保留。第 54 阶段修复来源 200 条截断、SSE 身份同步、历史来源补齐、人物来源序号与断点接写;独立构建已生成,尚待最终回归及加载。下面 21:49、21:02 是历史进程记录。
+
+- 第 53 阶段纠正完整报告基线:`2026-08-25 00:00` 至 `2026-09-11 00:00` 的坦洲羽毛球群实时原库共 **5524** 条,旧已保存快照只有 **4482** 条,不能用后者作实时全量分母。独立原库定位元数据及前后 count 校验在 `real-data-53/realtime-originals.json`;之后使用 `verify_ai_real_report.py --originals .../realtime-originals.json` 核对。先前 4482 的叙述是旧快照数量,不是实时完整消息量。
+- 最新重启为 **21:49:08**,Electron PID 12864、后端 PID 6860,端口 10392。第 53 阶段的最近 N 条批量上界、空尾读取、覆盖计数、完整报告直接生成及回查保留原文均已加载。原报告 5524 条原文与 6 份笔记恢复一致,真实界面已继续生成最终回答;此前 21:02 记录是上一进程。
+- 当前真实账号为 `wxid_iqvams2wrrse22`,应用数据在 `%APPDATA%/wechat-data-analysis-desktop`。
+- 当前真实开发版于 2026-09-11 21:02:23 重新启动,端口 10392、后端 PID 19512;加载第 51~52 阶段预算计量、读取优先级及时间窗口续读修复。真实首轮压缩从 491356 降至 158046 个估算单位(25.7%),笔记、原文和读取位置在重启后完整保留,界面已恢复压缩明细并点击继续。整份报告、多轮压缩及最终 Mac 仍未通过。
+- 此前唤起窗口的自动审批阻塞已解除。本次实际检查了统计历史恢复、四个人物胶囊、吉量胶囊打开实际发送者 330 的来源,以及定位到正确群消息后 AI 对话保持;证据在 `real-data-50/`。这些局部结果不代表全部 Windows 验收通过。
+- 在现有应用的设置 → AI 服务配置 DeepSeek;本机已完成配置,不把密钥写入源码、命令或验收包。
+- 先确认没有运行中的 AI 问答,再从托盘退出当前开发版。仅点击窗口右上角关闭可能是最小化到托盘。
+- 此前自动审批拒绝了助手关闭旧进程并重启,返回 `blocked by policy`,没有具体理由。之后确认旧窗口、后端和端口均已退出,才启动现有真实开发版;旧阻塞已解除。以下保留常规启动方式供复现。
+
+退出旧开发版后,在 PowerShell 手动执行:
+
+```powershell
+Set-Location 'D:/workProject/WeChatDataAnalysis/desktop'
+$env:WECHAT_TOOL_STATIC_UI = '1'
+$env:WECHAT_TOOL_DATA_DIR = Join-Path $env:APPDATA 'wechat-data-analysis-desktop'
+$env:WECHAT_TOOL_OUTPUT_DIR = Join-Path $env:WECHAT_TOOL_DATA_DIR 'output'
+$env:WECHAT_TOOL_PORT = '10392'
+& './node_modules/.bin/electron.cmd' .
+```
+
+该命令复用当前已生成的生产前端和现有真实数据,不使用 `tmp/windows-runtime` 等旧样例目录。若从候选源码包建立新的验收目录,须先按锁文件安装依赖并生成前端,不能直接执行此命令。
+
+启动后从主页选择“回看聊天”。先核对新后端进程启动时间、源码 SHA256、账号、真实聊天和 AI 历史恢复;这些检查成立后才开始新版本问答。源码清单与运行记录一起保存。
+
+## Windows 真实验收
+
+| 检查 | 操作与判断依据 |
+| --- | --- |
+| 全账号目录 | 新目录应合并实时和已保存历史;当前程序验证为 779 个会话,其中 15 个在实时会话列表以外仍有消息。使用 `real-data-44/catalog.json` 和 `merged-catalog-final.json` 核对,不把目录数量当作索引完成数量。 |
+| 默认全账号检索 | 新对话问“谁说过‘7-21惨案’?请给出处”,不带群名或日期。核对坦洲羽毛球🏸群、发送者 330、原文、原消息定位。已知来源 ID 为 `be422c48b87fd5ca5fadab99`。不得给模型补上答案后再声称默认检索通过。 |
+| 明确筛选与追问 | 指定群名、人物、时间后检查执行步骤中的实际条件;省略群名末尾表情也须唯一匹配。全账号追问发现新目录项时可纳入;指定会话和排除条件须保留。 |
+| 遗漏历史会话 | 对 `45817683258@chatroom` 做定向读取及来源定位。该群在旧实时会话目录中缺失,但两种源均有 897 条。空的时间子区间必须依照游标继续,不能报告全部历史为空。 |
+| 人物与实际发送者 | 在坦洲羽毛球🏸群读取 2026-09-10 21:29 至 21:32 提到“吉量”的消息,共 11 条,330 的原始 @ ID 指向吉量。第 45 阶段已实测人物胶囊为吉量,点击打开实际发送者 330 的原话,并定位到正确群消息。延长到 21:33 才包含“堂”的另一条 @;该条需另验。另复查旧回答中“330”胶囊打开迪拜大榴莲🍈的原话。 |
+| 图片 | 同一时间范围内,吉量发送两张图片,时间分别为 21:29:43、21:30:57。正文显示引用,查看器只浏览本回答两图;切图、缩放、旋转、Esc、定位和恢复不增加模型调用。 |
+| 索引迁移 | 已在新真实后端观察到配置版本 11、779 个会话及运行中的补齐任务;旧版本 9 错误不再阻挡启动。当前仍为部分覆盖,不表示全账号完成。 |
+| 索引暂停与增量 | 用户主动暂停当前版本任务后,查询和后台目录刷新不能擅自恢复;继续后保留断点与旧来源。真实新增消息能增量进入,不删除其他会话的全局索引。记录 CPU/GPU 设备、耗时、覆盖范围及前台查询延迟。 |
+| 时间、最近 N 条与精确统计 | 对真实范围独立核对原文 ID 集合;全局 N 是所有筛选结果合计。覆盖同秒消息、空区间、时间边界、超长消息和读取失败。数量由程序统计。 |
+| 压缩、停止与恢复 | 长报告多次压缩后,实际请求占用下降;记录笔记提交前后、已分析来源和字符区间。停止重启后不重复分析完成部分,来源仍可回查。保存故障另以程序故障注入验证,不在原数据上人为制造损坏。 |
+| 模型配置快照 | 从设置选择模型与已确认的原生等级;运行中补充、停止后继续均沿用启动快照,新问题采用当前选择。记录实际请求配置,不记录密钥。 |
+| 界面连续性 | 320px 侧栏和大视图、深浅主题、中文输入法、Enter 补充、Shift+Enter 换行、停止按钮、断线重连、切回窗口;核对草稿、回答、阅读位置和展开状态。切换微信聊天不切换 AI 对话。 |
+| 旧功能 | 仅回归 AI 相关旧总结、自动任务、关注提醒、报告阅读/复制和图片引用。按用户要求不扩展到朋友圈验收。 |
+
+## 证据规则和最终 Mac
+
+- 第 51 阶段收取全账号最近 5 条结果:779 会话全部核对,精确来源集合一致,但旧进程耗时 1756.55 秒,性能未通过。真实完整报告正在运行 `705c43c1867540f49710006146da02da`,独立原文范围共 4482 条;停止重启后原文、配置与游标一致。一次继续后观察为 1186 条、预算 52.9%,仍没有阶段笔记,不能称完整报告或压缩已通过。
+- 每次真实模型尝试都进入用量记录,失败、重试、视觉调用也计入;用户已取消原 30 次上限。
+- 程序测试、真实原数据程序验证、真实 Windows 界面、真实模型和最终 Mac 分别记录。不能把“真实 CPU 模型处理了几批数据”写成全账号索引或问答通过。
+- 本轮后端完整回归第一次为 325 通过、2 失败;两项测试补齐临时账号目录后复验通过。失败日志保留,详见 UI 复核记录第 44 阶段。
+- Windows 上述问题修复并实际验收稳定后,冻结源码和依赖锁清单,再使用 Mac 独立目录执行同版自动化和真实 Electron/模型流程。先核验 SSH、运行时、原生组件和图形会话。账号凭据通过现有授权使用,不进入包或本文。
+- 最终交付源码、更新需求及两平台记录;未验证项目明确列出。签名安装包和公开发布不属于默认交付。
diff --git a/docs/ai-sawtooth-context-2026-09-14.md b/docs/ai-sawtooth-context-2026-09-14.md
new file mode 100644
index 00000000..8aed52e8
--- /dev/null
+++ b/docs/ai-sawtooth-context-2026-09-14.md
@@ -0,0 +1,43 @@
+# 连续上下文与 DSH 式锯齿压缩
+
+参考 deepseek-ai/deepseek-harness 提交 `c291e7961a515f6d7af9304e7fd1d257929aef26` 的 compaction-basic:高水位触发、保留近期完整交互、重放前缀摘要、日志记录与可见上下文分离。实现继续使用现有 Python/DeepAgents 图。
+
+## 行为
+
+- 默认达到模型窗口 80% 才整理;若实际输入上限更小,以输入上限保护请求。
+- 从末尾保留约占模型窗口 16% 的近期原始交互,切点向前对齐工具调用与返回。旧部分由 LLM 整理,压后没有固定 50% 目标。
+- 同一对话跨轮和重启继承有效消息、工具结果及摘要,不再按每轮问答重建,不再将超过 2KB 的已处理工具结果自动替换成目录。关闭框架的工具参数、结果和用户长输入自动移出。
+- 工具查询仍分页。历史工具只作已完成记录,不重新执行;中断的未返回调用补明确的中断结果。当前范围和分页状态由新版本单独确定,不将旧句柄当成当前执行状态。
+- 优先以同一模型、原系统提示、工具定义和待整理消息前缀发起一次摘要请求,末尾追加中文整理指令;工具调用被禁用。默认输出最多 8192 tokens,实际仍受模型输出能力限制。只有摘要请求放不下时才使用持久化分段整理。
+- 摘要保留用户目标与纠正、有效范围、带来源的发现、已完成和未完成工作、下一步和回查入口。空文本、截断、非文本输出、虚构来源或路径、没有缩小历史的摘要不提交。
+- 临时错误有限重试;安全空间仍足够时可保留原历史继续,实际超限时只有整理确实缩小上下文才重试。不能恢复则保留现场,绝不拿归档目录冒充有效摘要。
+
+## 持久化与溯源
+
+`deep_conversation.py` 通过官方图 API 还原增量检查点,生成当前任务版本的 `context:seed`。不直接把 SQLite 最新检查点行当成完整状态。
+
+`deep_sawtooth.py` 先写完整分片归档,再生成摘要。`context:event` 保存绝对切点、原始前缀指纹、摘要和归档路径;与 `context:job:*` 的完成记录在一个数据库事务提交。即使随后主请求失败、图状态尚未回写,恢复也可复用已提交整理。版本变化、取消和提交失败不会替换旧投影。
+
+每轮通过经过账号、对话检查的 `context_origins` 只读访问历史虚拟文件;继承证据到当前任务的资料库,使原文引用和定位继续可用。当前范围仍独立校验。历史文件不能被后续轮修改,新增笔记使用新路径。历次内容寻址归档保留完整来源链。
+
+旧 v3 对话从已有检查点恢复;旧记录没有完整检查点时恢复现存问答并提供归档入口,不虚构缺失工具记录。删除整个对话沿用现有资料清理触发器并删除各版本检查点。
+
+## 配置与接口
+
+运行继续读取模型的 `compaction_policy`:使用 `pressure_ratio`(默认 .80)、`recent_ratio`(默认 .16)、`summary_attempts` 和 `overflow_retries`。旧 V2 的 `target_ratio`、`history_ratio`、`history_summary_ratio` 等字段保留兼容,但不作为 v3 的独立压缩触发器或固定低水位。
+
+`context_budget` 保留原字段及 `percent` 的输入容量口径,新增 `window_percent`、`trigger_capacity`、`retain_capacity`、`context_revision` 和 `compaction`。新版圆环按模型窗口比例显示;旧预算数据保留兼容。浮层分别显示已用估算、输入容量、模型窗口。摘要完成和模型回答结束后均发布最新估算。
+
+用量校准只接受完整匹配的旧请求前缀;改写已有消息、改变模型或工具定义不能借用旧锚点降低估算。界面显示估算,不将字节预算当成供应商精确计费 Token。
+
+## 验收范围
+
+新增 `tests/test_ai_sawtooth.py` 使用隔离 SQLite 和可控模型,验证低水位原文不变、两次锯齿、前缀重放、图状态尚未提交时恢复、跨轮只读归档、取消、版本变更、来源校验与事务失败。
+
+其中完整图测试在同一对话触发两次整理,重建服务后通过 `read_file` 读取第一轮材料,生成可定位引用,再删除对话验证归档、资料与检查点清理。没有向真实模型发送用户聊天,也没有改动运行中的用户任务。
+
+原文可回查与摘要语义绝对无损是不同保证:前者通过归档核验、来源关联和引用测试验证;后者不能仅靠长度与格式校验保证。
+
+专项及相关后端回归合并运行:180 项通过。前端时间线、预算事件合并和聊天面板测试:56 项通过。补充要求继承调整后,其专项再次通过。上下文浮层在隔离 Vite 预览中完成实际渲染检查;Python 编译和 `git diff --check` 通过。
+
+前端 Nuxt 生产构建已通过(存在项目原有重复导入、渐变语法和分包体积警告)。使用新构建产物并重启后端后生效;未主动重启正在处理任务的桌面应用。
diff --git a/docs/chat-agent.md b/docs/chat-agent.md
index 086efcd7..8b784093 100644
--- a/docs/chat-agent.md
+++ b/docs/chat-agent.md
@@ -1,18 +1,19 @@
# 聊天 Agent
-跨平台运行策略、Mac 实机结果及未覆盖项目见 [macOS AI 兼容性与验收](ai-macos-compatibility.md)。
+当前引擎以 [DeepAgents v3 架构与迁移说明](deepagents-migration.md) 为准,验收见 [迁移验收](deepagents-acceptance.md)。以下内容保留作为迁移前的历史说明,其中旧检查点、固定执行阶段和旧任务继续行为不再适用于新运行。旧版 [Mac 记录](ai-macos-compatibility.md) 不代表本轮通过。
聊天页右上角 AI 默认进入对话模式;原消息总结、自动任务、关注提醒位于「工具」。侧栏和大视图共享状态。
## 使用
-- 默认跟随当前聊天;点图钉可固定当前 AI 对话。查看来源时自动固定,避免原文跳转带走正在进行的 AI 对话。
+- AI 对话属于当前微信账号,切换微信聊天不切换 AI 对话;全部旧历史统一列出,保留原回答、来源与继续能力。
- 可连续提问,处理中发送的内容记为补充,在下一次动作前应用;输入法确认键不发送,Shift+Enter 换行。
-- 「读取范围」可手动选择会话;明确要求搜索其他群或点名会话时才扩大授权,范围保留在当前 AI 对话。
+- 默认搜索全部可读取历史;人物、会话和日期是每轮查询条件。追问保留仍有效的条件,用户可以明确取消。不再使用读取范围选择或固定/跟随控件。
- 历史可以新建、重命名和删除;与微信聊天记录分开保存,账号之间隔离。
- Agent 不再设置工具调用、模型请求、媒体分析数量和整轮运行时间额度,历史额度配置也不再生效。AI 服务设置只保留模型服务、本地检索和用量记录。
- 手动停止或应用重启后,点击继续查找会保留已有证据与用量记录。缓存页无需重复调用视觉模型。
- 用量关联每轮运行 ID;未返回的上游用量标为未知,不估算费用。长对话的背景压缩也计入模型用量。
+- 模型按服务配置分组,原生思考等级仅在能力确认后展示。新提问使用当前选择;运行中补充及停止后继续保持启动配置。运行中 Enter 提交补充,主按钮始终停止。
## 数据与接口
@@ -91,15 +92,29 @@ AI 助手的搜索步骤显示实际返回的检索方式:关键词与语义
### 对话界面与侧栏宽度
-对话消息容器改为官方 `@assistant-ui/vue` 原生组件:`AuiProvider`、`ThreadPrimitiveRoot`、`ThreadPrimitiveViewport`、`ThreadPrimitiveMessages` 和 `MessagePrimitiveRoot`。通过官方 external-store 接口适配现有本地对话和 Agent 流;输入、补充要求、幂等提交、原文引用、工具详情及会话持久化继续复用现有 Vue 组件与服务。运行时只在客户端挂载,消息按 ID 更新,关闭面板时释放订阅,无 React 根节点或跨框架 Teleport。
+当前使用 AI Elements Vue 的 Conversation、ConversationContent、Message、ChainOfThought 和 ContextIcon 源码组件,适配现有 Python/SSE 状态。消息按 ID 更新;只有一个滚动管理入口,恢复阅读位置使用库公开的真实滚动节点。Tailwind 已迁移到 4。
-官方 Vue 包尚未发布到 npm,本项目固定保存提交 `3a45a01c0d6141102638ecd4f32d1af4d01fb510` 的官方源码,通过 `file:vendor/assistant-ui-vue` 接入;core/store/tap 固定为 0.3.17 / 0.3.12 / 0.9.16。来源、许可、升级方法见 `frontend/vendor/assistant-ui-vue/README.md`。该版本属于预览集成,不能当作已发布的稳定 Vue 包。共享运行时按官方方式使用 tap standalone shim,已移除 React、React DOM 和 assistant-ui React 依赖。
+源码固定提交为 `ad4818f6081a2fe6e5b7bb53cebc5a66d9a24148`,来源和许可证见 `frontend/components/ai-elements/README.md`。旧 assistant-ui 适配器不再参与运行依赖。
布局参考 Codex:用户消息采用紧凑圆角气泡,回答直接排版;执行过程按时间顺序显示工具调用和进展。工具图标与正文左对齐,名称及展开详情缩进 26px;相邻同工具、同会话、同查询和范围的调用合并为一行,展开仍可分别查看结果、耗时和复用情况。用量与覆盖情况放在回答下方;失败、暂停及未读取资料仍明确展示。默认保留紧凑过程,完成或滚动不改变用户的展开选择。
侧栏左边缘支持鼠标或触摸拖动、本地记忆宽度、双击恢复 440 像素;聚焦分隔条后使用左右方向键调整,Shift 加速,Home/End 调到边界,Enter 恢复默认。宽度根据窗口及其他侧栏自动收敛,展开大视图后收起可恢复原宽度。测试见 `assistant-thread.test.js`、`agent-panel-resize.test.js` 和现有 Agent 交互测试;预览页 `tests/fixtures/agent-redesign.html` 支持无模型调用的流式演示。
-展开大视图后默认显示左侧 AI 会话列表,支持搜索、新建、切换、重命名、删除和加载失败重试;删除前在行内确认。列表显示当前账号的会话及所属聊天,切换已有 AI 会话时固定读取范围;草稿按会话保存。收起为窄侧栏后可从顶部会话按钮打开抽屉,再次展开恢复左侧导航。异步读取按账号和请求版本隔离,避免快速切换或改名期间旧响应覆盖新状态。
+大视图显示当前账号的 AI 会话列表,支持搜索、新建、切换、重命名、删除和加载失败重试;删除需要确认。草稿按 AI 对话保存,旧会话的聊天归属只作兼容信息,不限制新问题的读取权限。异步读取按账号和请求版本隔离。
本次界面与 Vue 接入验收见 `docs/ai-chat-ui-validation.md`。
+
+## Agent 动态读取窗口
+
+新版按实际请求剩余预算读取,时间区间为左闭右开,固定截止时间与时区,程序生成稳定续读游标。区间超限时二分,最小一秒内继续按稳定消息顺序和字符位置分片。未指定会话时,最近 N 条表示所有筛选结果合计 N 条。
+
+活跃原文达到约 80% 时整理阶段笔记,目标降到 60% 以下;近期原文和笔记分别以 15% / 20% 为控制目标。笔记、来源和进度同一事务保存成功后才释放活跃原文,原始证据仍存于本地。保存失败、暂停、重启及窗口收缩保留待分析队列。圆环和实际请求共用预算计量,UTF-8 字节是保守估算,不冒充实际 Token;累计模型用量独立审计。
+
+以下 10% 分段与 offset 描述仅适用于旧运行检查点的兼容恢复;新任务使用上述持续阅读协议。
+
+范围遍历与主动读取均按每页当前容量装批,达到容量前保留下一条给续页;超长单条原文完整保存在本地,再按字符偏移拆分给模型,重叠前文也计入容量。决策和回答请求中的原文证据同样受 10% 资料预算限制,不再固定只候选最近 100 条。最近 N 条的总量约束、会话授权与固定截止时间保持原语义。
+
+工具结果的 `next_offset` 表示实际续页位置,末页为 `null`;模型不得自行固定增加 50 或 100。搜索位置按底层命中数推进,即使个别命中无法规范化也不会反复读取同页。请求发送前检查完整预算;上游窗口不足或分段输出截断时,缩小未完成分段并保留已完成结果与进度。资料容量或最小请求仍无法满足时明确报错,不静默截断来源或正文。
+
+动态分页测试见 `tests/test_ai_agent_reading_budget.py`,另回归现有 Agent 上下文、协议、供应商与流式读取测试。预算、实际条数和缩小原因进入现有诊断日志,不新增聊天正文日志、设置项或数据库迁移。
diff --git a/docs/chat-calendar-performance.md b/docs/chat-calendar-performance.md
new file mode 100644
index 00000000..11a9a569
--- /dev/null
+++ b/docs/chat-calendar-performance.md
@@ -0,0 +1,38 @@
+# 按日期定位:月历统计优化
+
+实时月历通过只读 SQL 对每个消息分库执行月份范围过滤和每日聚合。每库最多返回 31 条统计,不再从最新消息逐批扫描到目标月份。月份与日期边界仍使用本地时间,右边界不包含下月月初。
+
+解密库的整数时间字段直接参与范围过滤,其他类型保留整数转换。查询不会给微信原始库创建索引;已有时间索引可以用于范围过滤。任一分库查询失败时返回 503,不显示部分统计或回退到旧扫描。
+
+## 合成数据对照
+
+2026-09-15,Windows、本地 SQLite,共 200,004 条消息:其中 200,001 条是较新的消息,目标历史月份有 3 条消息,分布在 2 天。测试库已有 `create_time` 索引。
+
+| 路径 | 首次调用 | 重复调用 | 返回的数据 | 目标月份结果 |
+| --- | ---: | ---: | --- | --- |
+| 旧逐条扫描 | 1,283.55 ms | 1,223.57 ms | 200,000 条消息 | 达到上限,漏掉全部 3 条 |
+| 月份聚合 | 1.82 ms | 0.92 ms | 2 条每日统计 | 完整计入 3 条 |
+
+首次调用指应用查询缓存未命中,不代表操作系统冷磁盘。基线省略消息归一化的实际工作,结果仍偏向旧路径。测试没有原生桥接、微信库解密或其他请求的锁竞争成本,不能视为真实群聊的耗时承诺。`EXPLAIN QUERY PLAN` 验证新 SQL 使用时间索引范围查询。
+
+## 最新真实原生库复测
+
+2026-09-15,用户在 dev 中打开最新微信加密数据后,确认实际来源为 `realtime`:
+
+| 真实群消息量 | 目标月份 | 完整月计数 | 桌面请求后端耗时 | 两次 HTTP 复核耗时 |
+| ---: | --- | ---: | ---: | --- |
+| 339681 | 2025-07 | 1478 | 1312.5 ms | 2939.06 / 1263.89 ms |
+| 33353 | 2020-12 | 3485 | 900.1 ms | 1495.07 / 915.90 ms |
+
+两组每日结果均与独立的本地日期边界条件计数一致。实际原生查询计划为 `SCAN TABLE`,未命中时间索引;本次改善是避免将大量消息行和正文传回应用,不能声称数据库内部也没有扫描。真实环境已有原生缓存,且存在锁竞争,上述数据不是冷磁盘基准。详见 [桌面测试记录](chat-calendar-ui-test.md)。
+
+复现:在项目根目录执行 `python -m pytest tests/test_chat_calendar_queries.py -q -s`,输出中的 `CALENDAR_BENCHMARK` 包含当次测量。
+
+## 请求与诊断
+
+- 月历前端缓存按账号、会话、请求数据源及年月区分,30 秒失效,最多 120 项;失败或不完整结果不缓存。
+- 未完成统计时日期显示“—”且不可点击;20 秒超时退出加载,提供手动重试;切月、关闭或切换会话会取消旧请求。
+- `chat.daily_counts` 日志包含请求开始、来源解析、完成或失败事件,通过相同请求标识关联。统计包含 `discoveryMs`、`aggregateMs`、`lockWaitMs`、`sqlMs`、`returnedRows`、`elapsedMs` 和 `stage`;实时查询的锁等待包含目录探测与聚合阶段。阶段耗时存在包含关系,不应相加作为总耗时。
+- 浏览器取消只停止等待和应用旧结果,不能保证立即中断正在执行的原生 SQL。真实环境仍需结合日志判断目录探测、锁竞争和数据库查询成本。
+
+接口保留原有参数和计数字段。实时成功响应的 `scanLimited=false`、`scannedMessages=0` 表示未走逐条扫描;该数字不代表 SQLite 内部访问的行数。
diff --git a/docs/chat-calendar-ui-test.md b/docs/chat-calendar-ui-test.md
new file mode 100644
index 00000000..44f3a543
--- /dev/null
+++ b/docs/chat-calendar-ui-test.md
@@ -0,0 +1,82 @@
+# 月历统计桌面测试记录
+
+测试日期:2026-09-15,Windows,时区 Asia/Shanghai。
+
+## 最新真实库复测(13:43–13:52)
+
+用户在项目中打开最新数据后,沿用该账号与 dev 进程复测。实际连接为本机微信账号的 `db_storage` 目录(公开记录省略账号标识及完整路径),接口与日志均确认 `source=realtime`,使用原生只读 SQL 通道。未继续使用先前找到的旧快照,也没有注入延迟或替换真实计数。
+
+| 真实场景 | 实际结果 | 耗时/验证 |
+| --- | --- | --- |
+| 超过 20 万条的大群 | 原生 `COUNT(*)` 合计 **339681 条**,分布在 3 个消息分库 | 原生独立计数确认 |
+| 大群当前月份 2026-09 | **4662 条、15 天** | 桌面请求后端 **1287.8 ms** |
+| 大群最早月份 2025-07 | **1478 条、3 天**;26 日 274、27 日 260、28 日 944 | 桌面请求后端 **1312.5 ms**;独立逐日边界计数完全一致 |
+| 大群空月 2025-06 | 完成后显示 0,加载时显示“—” | 原生界面通过 |
+| 历史日期 2025-07-27 | 正确定位到当天消息,锚点和附近消息接口均 200 | 原生界面通过 |
+| 跨五年的群 | 原生计数 **33353 条**,分布在 5 个消息分库 | 当前显示 2025 年记录,可定位至 2020 年 |
+| 多年群最早月份 2020-12 | **3485 条、23 天** | 桌面请求后端 **900.1 ms**;独立逐日边界计数完全一致 |
+| 跨年快速切换 | 十二月→次年一月→十二月 | 一月请求在切回后完成,未覆盖十二月;返回十二月没有新增请求 |
+| 会话切换 | 大群与多年群显示各自独立的统计 | 原生界面通过 |
+
+另外顺序调用真实 HTTP 接口进行复核(不走前端缓存):
+
+- 大群 2025-07 两次 **2939.06 / 1263.89 ms**。
+- 多年群 2020-12 两次 **1495.07 / 915.90 ms**。
+- 参考查询逐日使用 `SUM(CASE WHEN create_time >= 当天零点 AND create_time < 次日零点 THEN 1 ELSE 0 END)`,不复用月历的 `strftime` 分组表达式;两组每天计数、总数均一致。
+- 响应均为 `source=realtime`、`scanLimited=false`、`scannedMessages=0`。
+- 原生 `EXPLAIN QUERY PLAN` 在本次相关分库上显示 **SCAN TABLE**,没有命中时间索引。因此不能把合成库的索引命中结论推广到此真实原生环境。程序层不再分页扫描和解析消息正文,但数据库内部仍可能遍历整张表。
+- 本次查询已有原生密钥/页缓存,耗时不是冷磁盘基准。桌面月历日志中锁等待约 0.26–1.34 秒,仍会受同时加载消息等工作影响。
+
+真实日志:`tmp/calendar-desktop-dev-real.log`;独立核对:`tmp/calendar-real-native-verify.log`、`tmp/calendar-real-native-results.json`;复核脚本:`tmp/verify_calendar_real_native.py`(只输出计数与计划,不输出密钥或消息正文)。dev 保持连接用户打开的最新真实数据。
+
+结论:真实实时数据上的大群、早期月份、跨年切换与日期定位通过。没有在真实库上人为制造失败;超时、失败、账号切换等边界的验证记录见下方合成数据测试,不能混称为真实故障复现。
+
+## 此前合成数据测试(保留作边界测试记录)
+
+## 环境与范围
+
+使用 Computer Use 技能的 `@oai/sky` 原生通道操作 Electron 窗口。通过 `desktop/scripts/dev.cjs` 启动 Nuxt、Electron 和本地 Python 后端,使用 Node 24.19。前端端口 3000,后端端口 10392。
+
+默认运行目录没有可用聊天账号,因此在 `tmp/calendar-ui-runtime` 创建隔离测试账号与 SQLite 消息分库。主群共 200,010 条消息,含 200,001 条近期消息及 2020 年历史消息;另有对照群和第二账号。所有消息、账号及用于显示账号选择器的密钥占位值均为合成数据。
+
+故障测试通过仅匹配隔离数据目录的临时 Python 中间件,对月历接口注入延迟或 HTTP 503。测试结束后以不加载该中间件的方式重启 dev;正常 dev 保持运行。
+
+## 原生界面测试结果
+
+| 场景 | 观察结果 | 结果 |
+| --- | --- | --- |
+| 启动和加载大群 | Electron 正常打开,聊天消息可浏览,九月显示 200001 条、3 天 | 通过 |
+| 早期月份及跨分库合并 | 2020 年六月显示 6 条、3 天:1 日 2 条、15 日 3 条、30 日 1 条 | 通过 |
+| 空月份 | 2020 年九月显示完整统计 0,日期不可点击 | 通过 |
+| 日期定位 | 点击 2020-06-15,锚点与附近消息接口成功,目标日期消息出现在上下文 | 通过 |
+| 月初/月末切换 | 六月的 6 条不含五月末和七月初消息;七月显示 1 条 | 通过 |
+| 缓存复用 | 六月→七月→六月,返回六月没有新增月历接口请求 | 通过 |
+| 会话切换 | 旧面板关闭,对照群重新打开显示 7 条、6 月 8 日独立统计 | 通过 |
+| 加载中交互 | 日期显示“—”且禁用,月份切换及关闭仍可操作 | 通过 |
+| 超时与迟到响应 | 注入 30 秒延迟;界面显示“加载日历超时,请重试”,底层请求结束后仍保持错误状态 | 通过 |
+| 超时后手动重试 | 移除延迟,点击重试恢复 200001 条完整统计 | 通过 |
+| 503 错误与重试 | 显示“无法完整加载日历,请稍后重试”,日期显示“—”;重试成功后恢复完整结果 | 通过 |
+| 延迟请求期间切回缓存月 | 七月请求延迟 15 秒时切回八月;旧请求结束后仍为八月且没有重新加载 | 通过 |
+| 加载中关闭面板 | 关闭后等待旧请求结束,面板未重新出现 | 通过 |
+| 账号隔离 | 第二账号相同群标识九月为 10 条,六月为 9 条,未沿用第一账号统计 | 通过 |
+| 跳转到顶部 | 第二账号定位到 2020-06-20 最早消息,月历同步显示当天 9 条 | 通过 |
+
+超时用例的原生截图在操作后约 34 秒采集,确认超时状态及迟到响应无覆盖;20 秒阈值本身由自动化测试验证,未将截图时间作为精确计时证据。
+
+日期定位后月历会沿用已有的可见消息日期同步逻辑;上下文包含前一月消息时,面板可能跟随可见日期切月。本次没有修改该逻辑。
+
+## 日志与耗时
+
+- 正常桌面测试:`tmp/calendar-desktop-dev-qa.log`。
+- 延迟和 503 测试:`tmp/calendar-desktop-dev-fault.log`。
+- 恢复后的正常 dev:`tmp/calendar-desktop-dev-final.log`。
+- 2020 年六月桌面请求:总耗时 **5.9 ms**,聚合约 **0.14 ms**,两个分库返回 **5 行**每日计数,合并后 3 天、6 条消息。
+- 2026 年九月首次桌面请求:总耗时 **164.3 ms**,聚合约 **157.45 ms**,完整计入 200001 条消息。
+
+以上为后端日志耗时,不含桌面绘制与网络往返。优化前后查询基准详见 [性能记录](chat-calendar-performance.md)。
+
+## 自动化与边界
+
+实现阶段已通过相关后端 **60 项测试**、前端 **26 项测试**及 Nuxt 生产构建;覆盖分库失败、闰年/本地日期边界、索引查询计划、超过 20 万条历史统计、请求超时/取消/卸载、缓存容量与过期等场景。原生桌面测试补充验证实际 UI、HTTP 和 SQLite 集成流程。
+
+此前这一轮使用合成 `decrypted` 数据;随后已完成本文开头的最新真实 `realtime` 数据复测。结论仅覆盖本次月历优化及日期定位相关回归,不代表语音导出或其他全应用功能测试。
diff --git a/docs/deepagents-acceptance.md b/docs/deepagents-acceptance.md
new file mode 100644
index 00000000..036fbf6d
--- /dev/null
+++ b/docs/deepagents-acceptance.md
@@ -0,0 +1,116 @@
+# DeepAgents 迁移验收记录
+
+日期:2026-09-12 至 2026-09-13。架构与兼容规则见 [架构说明](deepagents-migration.md)。本记录区分自动测试、真实模型、真实聊天和桌面操作;读取数量通过不等于报告事实质量通过。
+
+**交付状态:主执行引擎迁移已实现,完整验收尚未通过。** 简单对话、程序覆盖、自动测试和 Windows 构建已有通过证据;真实长报告最终校验仍失败,且 macOS 实跑与界面绘制时延尚未验证。因此不能把本次代码当作已经完成全部发布门槛的版本。
+
+## 工作区与数据
+
+实施前保存了工作区状态和已跟踪差异:`tmp/deepagents-migration/initial-status.txt`、`initial-tracked.diff`。在已有未提交改动上增量修改,没有重置其他工作,没有提交或发布安装包。
+
+真实验收使用已配置的 `mimo-v2.5` 和本地聊天源。AI 对话、检查点、用量、内部文件均放在各自独立的 `tmp/deepagents-migration/*/state`;供应商密钥从原配置读入内存,不写入图状态或报告。原聊天源只读。HTTP 桌面验收复用本地索引服务,其维护可能更新共享搜索索引,因此这里不是整份应用目录的物理克隆。
+
+验收目录含私人聊天和日志,已加入 `.gitignore`,不作为发布资源。新引擎首次正式启动会用 SQLite backup API 一致性备份 AI 数据库,再写迁移标记。尚未切换正在使用的生产进程。
+
+## 自动检查
+
+| 检查 | 已记录结果 | 证据 |
+| --- | --- | --- |
+| Python AI、搜索、模型目录回归 | 500 项通过,153.19 秒;随后新增报告文案合同 1 项通过 | `regression-partial-final.log`、`report-display-test.log` |
+| 官方图、来源与边界合同 | 89 项通过,包含十万来源、分批核查恢复及迟到请求审计 | `bounded-final.log` |
+| SDK 扩展字段 | 3 项通过 | `sdk-fields.log` |
+| 前端 | 22 文件、265 项通过 | `frontend-tests-latest.log` |
+| 前端静态构建 | 通过 | `frontend-build-latest.log` |
+| 桌面通知、包装、启动合同 | 11 项通过 | `desktop-contracts-final.log` |
+| Windows 源码运行时 | 应用官方图通过 | `application-runtime-final.log` |
+| Windows PyInstaller 冻结运行时 | 应用图运行检查通过;最终构建记录见日志 | `frozen-delivery-final.log` |
+| macOS CI | 工作流保留,当前环境未执行 | `.github/workflows/ai-cross-platform.yml` |
+
+以上日志均位于 `tmp/deepagents-migration/`。冻结检查实际执行应用的 AgentService、模型适配器和官方图,断言一次请求、零微信查询;同时执行独立 SQLite 检查点、ONNX、SQLite 向量扩展和媒体依赖检查,不是只检查 import。冻结测试的上游模型为确定性替身,不计为真实模型测试。
+
+新增合同覆盖:一次调用问候、无目录初始化、原生/JSON 协议、明确能力拒绝缓存、两次纠正上限、范围和账号隔离、取消与过期版本、同秒消息、长消息续读、精确统计、提交事务失败、分页重放、实时缺口游标、虚拟文件权限、官方 grep 返回格式、摘要归档失败保留、当前 AI 对话笔记桥接、媒体问题透传且原文不变、独立证据核验、旧任务显式重启、SSE 与正文流隔离。
+
+十万来源用例检查引用校验只读取实际引用的原文,不枚举全库。引文错配才分页回查候选;原文始终保存在数据库。完整报告还单独分页核对未引用的原文,检查重要遗漏;普通问候和普通查询不增加此轮核查。核查批次中有一批失败后,输入不变的已成功批次不会再次调用模型。
+
+长范围合成验收使用两个会话、100 天、8 个官方子图和 16 个分页。断言范围连续无重叠、来源去重、程序覆盖完整;再次恢复相同子任务不增加模型调用或原文读取。这是合成测试,不作为真实报告成功样本。
+
+旧测试迁移:删除了 13 个文件中 105 个针对已移除执行器私有方法的测试函数,清单及原件保存在 `retired-engine-tests.json`、`tests-before-interface-migration/`。没有将这些旧测试记成通过或添加跳过标记。纯数据分页、时间、引用和统计检查保留;三阶段顺序改为官方图的一次回答合同,旧 `step`/报告循环改为范围提交与子图合同,旧压缩入口改为官方摘要持久化合同,旧恢复入口改为 v3 恢复及旧任务显式重启合同。
+
+## 简单对话真实模型结果
+
+每个样本新建空 AI 对话。原生三类输入各五轮,JSON 问候五轮,全部一次模型调用、零微信查询、零子任务、零来源。初始工具定义不包含会话 ID 目录;1、779、2000 个会话下的目录禁止访问合同通过。
+
+| 模式和输入 | 次数 | 完整输入 Token | 总耗时范围 | 中位数 | 热启动提交至请求 P95 |
+| --- | ---: | ---: | --- | ---: | ---: |
+| 原生:你好 | 5 | 1413 | 3.031–7.078 秒 | 4.156 秒 | 540 毫秒 |
+| 原生:你能做什么 | 5 | 1414 | 6.641–9.906 秒 | 9.203 秒 | 410 毫秒 |
+| 原生:谢谢 | 5 | 1413 | 2.235–5.203 秒 | 3.922 秒 | 449 毫秒 |
+| JSON:你好 | 5 | 1195 | 2.796–9.454 秒 | 7.172 秒 | 390 毫秒 |
+| 同模型参数直接调用:你好 | 5 | 248 | 3.766–6.203 秒 | 4.453 秒 | 不适用 |
+
+P95 使用各组去掉首样本后的四个样本计算,样本量有限;不能据此推断所有模型或高负载时延。原生问候首个冷样本为 4.156 秒。直接调用沿用相同模型、思考参数和输出上限,输入没有框架提示词,服务端波动仍存在。这些数字不表示 Agent 比直接调用稳定更快。
+
+证据:`performance-final.json` 及 `sdk-native-hello-v2`、`sdk-capabilities`、`sdk-thanks`、`sdk-compatible-hello`、`sdk-direct-control` 中的 `results.json`。每次请求的排队、请求、首片段和完整用量另存审计。
+
+6000 Token 和本地热启动 P95 一秒目标在这些样本中通过。SSE 轮询周期为 100 毫秒,前端正文增量直接更新;**上游片段到原生界面绘制额外延迟 P95 500 毫秒尚无完整测量,不记为通过**。
+
+## 真实聊天与覆盖基线
+
+原库基线通过独立原生导出程序重新分页读取,比较真实消息身份、总数、每天分布和发言人分布,不使用 Agent 的计数作为基线。
+
+| 场景 | 结果与限制 |
+| --- | --- |
+| 单群地点查询 | 已完成并逐条核对建议、回应和对应时间;初次因引用前缀失败,修复本地编号规范化后恢复,没有重新读取整段历史 |
+| 同对话追问 | 完成;7 次模型调用,继承同群同日,未扩大到全部聊天;来源仍可回查 |
+| 十天精确统计 | 3027 条,与独立程序的消息身份、日期和发言人统计一致;早期错误 500 条样本判为失败 |
+| 十天完整报告 | 独立核验 3027 条身份、日期、发言人及覆盖全部相同;最终状态失败,遗漏核查两次纠正后仍有原文或草稿引句不匹配,不能作为成功报告交付 |
+| 两群五分钟范围 | 独立基线分别为 5 条与 0 条,子任务范围正确;经过修复与恢复完成。人工复核三条相关原文、活动劝阻、群归属与引用通过;删除了未经核实的相关条数,内部字段改为群名和当地时间 |
+| 运行中补充要求 | 真实请求从版本 1 切换到版本 2,完成新要求,零微信工具;已发出旧请求中断、用量未知,未混入新答案 |
+
+十天范围:本地时区 2026-09-01 00:00(含)至 2026-09-11 00:00(不含)。每日消息数依次为 311、96、320、368、313、196、311、297、629、186。两群样本范围为 9 月 1 日 08:15(含)至 08:20(不含)。正文涉及私人消息,留在隔离验收目录,没有复制进本说明。
+
+最新独立基线分别保存在 `release-ten-days/independent-coverage.json` 和 `release-cross-group/independent-coverage.json`,均通过。每次失败、停止和恢复结果追加保存在这两个目录的 `results.json`。跨群样本经过多次修复与恢复累计 72 次请求,输入 174,617 Token、输出 124,810 Token,最后一次恢复 42.469 秒;其中一次取消的未知用量保留未知。十天样本累计 237 次请求,输入 10,111,905 Token、输出 458,948 Token,未知用量 5 次,最后一次恢复 59.078 秒后失败。这些是开发排错累计成本,不是一次成功报告的性能,也不用于宣称报告提速。
+
+跨群样本曾在遗漏活动劝阻时被自动判为完成,人工复核判失败,记录见 `release-cross-group/manual-quality-audit.json`。反向核查改为逐来源判定后,确实发现并补入该遗漏;最新计数与文案修复后人工复核通过,历史失败仍保留。该样本说明自动完成状态不能替代人工质量验收。
+
+长报告核查后来恢复现有辅助请求策略:仅在用户未显式指定思考等级且供应商明确支持时关闭默认深度思考;主回答与显式配置保留。来源使用服务端映射的整数序号,减少编号抄写;有效条目单独提交,纠正和恢复只请求未通过条目。最终十天样本已有 15 个成功反向核查批次,其余未完成;这些改进未被记为完整报告通过。初始执行还出现父任务读取后再委派全范围、造成重复读取的开销,来源去重没有消除这部分模型成本。
+
+补充要求样本见 `real-supplement/results.json`,5.391 秒完成版本 2,累计两次已发出的请求。首次实测将旧版本中断误记为请求失败;随后修正为取消并记录 `superseded`,对应自动测试通过。未知的上游用量仍保留未知,未补造数值。
+
+## 保留的失败样本
+
+- 早期 JSON 兼容样本中有一次返回裸文本而非 JSON,产生第二次纠正请求。修复系统消息顺序并在已知支持的接口使用 JSON mode 后,最新五轮全部一次调用。旧失败没有覆盖或计入最新通过率。
+- 原统计模型将分页大小误作“最近 500 条”,任务曾显示完成但统计不符,判定失败;现在仅接受用户明确指定的最近 N 条。
+- 早期跨群任务因模型把数组编码成字符串,错误后尝试扩大到全部聊天。样本已停止并判失败;新增参数规范化及点名范围约束。
+- 长报告出现把称呼当作亲属事实、图片引用错配、邀约当作已发生事件等问题。即便 3027 条已读完也不算通过,草稿与核查反馈保留。
+- 早期证据核查缺少群、当地时间及标题上下文,错误修复了部分正确段落;已补充可信元数据和标题归属,仍需以最终实测结论验收。
+- MiMo SDK 适配曾丢弃多轮工具所需的思考字段;补充官方 SDK 透传。第一次透传实现的复制逻辑在请求前失败,已修复,并保证本地初始化失败不算已发出的收费请求。
+- 真实范围子任务调用虚拟 grep 时发现返回字段不符合框架接口,导致执行中断。已修复并增加使用官方格式化函数的回归,恢复沿用已提交页面。
+- 最终校验曾一次性加载所有已读原文,已改为按引用读取及错配时分页查找,并用十万来源验证。现有长报告事实核查的误报、遗漏段落和修复不稳定仍是未完成问题,不能归为全部已解决。
+- 真实验收也保留超时、取消、两次局部修复后仍失败的样本。失败或中断状态没有伪装为成功。
+
+## Windows 原生桌面记录
+
+使用 Electron 加载实际构建前端和独立 HTTP 服务,通过 Windows 原生 Computer Use 操作;未使用模拟截图替代。
+
+- 真实问候一次模型调用、无查询附属信息,刷新后记录保留。
+- 使用最终 SDK 适配再次从原生界面提交问候,运行 `326276fb424a4a789ce8da1328c27089` 一次调用、零查询完成;截图 `desktop/hello-latest-sdk.png`。
+- 原生点击停止长回答,已输出部分保留;点击继续后完成。
+- 用合成的旧运行状态验证“使用新引擎重新运行”,点击后实际发出一次模型请求并创建关联 v3 运行。旧状态是合成数据,后续模型请求是真实请求。
+- 导入已经验证的真实查询答案、来源和用量,点击引用显示原文,再点击“定位原消息”进入对应群和消息上下文。该项验证界面定位,不作为又一次真实查询模型验收。
+
+截图位于 `desktop/hello-one-call.png`、`desktop/stopped.png`、`desktop/legacy-restarted.png`、`desktop/source-located.png`。其中包含私人聊天,仅保留本地。没有操作微信消息发送按钮。
+
+## 复现与交付边界
+
+```powershell
+uv sync --locked --extra build
+$testFiles = @(rg --files tests | Where-Object { $_ -match 'test_(ai|local_search|model_catalog).*\.py$' })
+uv run pytest -q @testFiles
+uv run python tools/verify_ai_runtime.py
+node tools/build_ai_smoke.cjs
+```
+
+前端使用 Node 22 或支持当前 Vite 的更新版本,在 `frontend` 运行 `npm ci`、`npx vitest run`、`npm run generate`。真实模型验收工具为 `tools/verify_deepagents_real.py`;独立原文基线为 `tools/verify_deepagents_coverage.py`。这些命令可能产生模型费用,真实数据参数需使用本机有效配置。不会自动重新执行旧生产任务。
+
+尚未交付生产安装包;macOS 当前实跑、界面绘制时延以及完整报告最终事实质量是不能用模拟结果代替的验收项。未满足的项目必须保留为未通过,不应据此发布。
diff --git a/docs/deepagents-deepseek-followup-2026-09-13.md b/docs/deepagents-deepseek-followup-2026-09-13.md
new file mode 100644
index 00000000..38788297
--- /dev/null
+++ b/docs/deepagents-deepseek-followup-2026-09-13.md
@@ -0,0 +1,53 @@
+# DeepSeek 密钥更新后的继续验收
+
+用户提供临时测试密钥后,继续使用既有 DeepSeek `deepseek-flash` 配置进行实测。密钥仅通过测试进程环境传入,不写入源码、模型配置或报告。测试使用独立目录,没有修改用户聊天记录或已安装的应用。
+
+## 继续发现并修复的问题
+
+1. **普通概览遗漏语义核验**:之前只有完整报告、时间类问题会核验事实。真实概览曾把薪资沟通推断为已找到下家,并弄反发言人。现在有原文依据的非统计答案均进入核验;问候和精确统计保留原有流程。给核验与修复提供程序计算的 `is_self`,不靠会话名猜发言人。
+2. **DeepSeek 首轮核验没有实际关闭思考**:补充官方接口的能力识别。首轮使用非思考模式,质疑复核及修复保留推理;对没有显式思考等级的官方 DeepSeek 内部纠错使用 `low`。显式用户设置、其他供应商和同名代理端点不覆盖。接口开关及等级依据 [DeepSeek 官方文档](https://api-docs.deepseek.com/guides/thinking_mode/);当前 `deepseek-flash` 别名的关闭思考请求也通过官方接口实测。
+3. **核验误报导致答案越改越错**:初审的负面判定先独立复核,再决定是否修复。纯格式或确定的范围、引用错误仍直接校验。已通过的段落不重复核查。
+4. **局部修复造成证据丢失**:修复后即使段落省略编号,核验仍保留此前已加载的原文;唯一匹配的原话在每轮修复后重新附消息引用,兼容中文直角引号。
+5. **时间表述漏洞**:补充计划时刻被写成实际完成时刻,以及“最后一条消息”早于正文自己引用消息的检查;分群末条时间分别验证。
+6. **模糊时间扩大读取量**:“最近”没有其他限定或继承范围时默认近 7 天,说明假设;有用户要求或证据需要才扩大。
+7. **验收脚本误判统计表格**:原脚本只识别“5 条”,会把正确的条数表判错。现在识别总数和指定人员的表格行;错误总数不能被其他行中的数字掩盖。要求引用的用例另检查消息引用存在。
+8. **正文混入执行细节**:跨群样本曾出现内部页数前后不一致,消息总数与实际覆盖台账正确。补充输出规则,普通回答省略页数、句柄和内部状态字段。覆盖验收始终依据程序台账和原文集合,不依赖模型自报页数;这条提示约束不能保证所有输出格式零偏差。
+
+## 实测记录与判定方式
+
+这些是不同迭代的独立任务,不能混为同版本重复采样,也不用于估算失败概率。自动检查通过后仍人工检查计划与结果、发言人、金额和引用;不把 completed 状态当作语义正确的证明。
+
+- `tmp/deepseek-final-matrix-20260913`:第一轮 8 类用例全部完成。完整委派 189.41 秒、25 次调用;事实 36.62 秒;统计 10.20 秒;追问 11.98 秒;跨群 66.33 秒;最近 N 条 25.62 秒;无匹配 14.22 秒;问候 3.48 秒。该轮早于普通概览核验等后续修改。
+- `tmp/deepseek-final-real-20260913`:真实原问题 28.73 秒返回,但人工发现发言归属和状态推断错误,**不计为通过**。
+- `tmp/deepseek-grounded-real-20260913`:扩大到两周、读取 515 条,240 秒测试截止后停止,保留草稿。该轮仍未为 DeepSeek 关闭首轮思考,**不计为通过**。
+- `tmp/deepseek-verified-real-20260913`:默认近 7 天,读取可用快照 24 条并处理相关图片;165.56 秒、14 次调用完成,修复两轮后核心事实与发言归属通过检查,明确区分薪资/交接安排和实际离职。这个耗时包含核验,不能用前一轮未核验的 28.73 秒代替。
+- `tmp/deepseek-verified-matrix-20260913`:统计和追问的自动失败是表格识别误报;跨群时间表述、无匹配和完整委派还暴露了核验与修复问题,已保留失败记录,不能整轮算通过。
+- `tmp/deepseek-final-targeted-20260913`:保留了一次跨群修复失败,以及一次无匹配回答前后矛盾的样本。即使无匹配自动检查标为通过,也不计为人工验收通过。
+- `tmp/deepseek-adjudicated-matrix-20260913`:增加初审质疑独立复核后的补测。跨群 146.47 秒、19 次调用完成;无匹配 113.97 秒、13 次调用完成,人工核查已明确未发现目标主题。**完整委派 220.95 秒、28 次调用完成**,两个子任务完成,13 条全部读取并分析,安排变化和结算数值通过人工核对。
+
+公开报告不复制真实聊天原文。各轮 JSON、日志和隔离数据库留在本地 `tmp` 目录;恢复验证的耗时会单独记录,不能报成一次新任务的完整耗时。
+
+按用例选取最近已验收记录,8 类均完成并通过结构、范围及核心事实复核:
+
+| 用例 | 秒 | 模型调用 |
+| --- | ---: | ---: |
+| 问候 | 3.55 | 1 |
+| 事实问答 | 54.89 | 10 |
+| 精确统计 | 8.56 | 3 |
+| 同范围人员追问 | 7.03 | 3 |
+| 跨群日期变更 | 146.47 | 19 |
+| 跨群最近总共 3 条 | 38.91 | 7 |
+| 无匹配主题 | 113.97 | 13 |
+| 完整委派 | 220.95 | 28 |
+
+汇总复核文件为 `tmp/deepseek-final-assessment-20260913.json`,保留每项原始结果路径和运行编号。统计与追问采用修正后的表格检查重新评估原答案,没有修改原始失败标记来伪装新一轮模型调用。这是多轮修复后的验收集合,不是一次同版本全矩阵运行;最后的引用恢复改动另由针对性测试验证。
+
+## 离线检查
+
+最终完整回归:**214 项通过,111.83 秒**,日志为 `tmp/deepseek-final-delivery-tests-20260913.log`。覆盖 DeepAgents、来源与身份、范围、统计、部分失败恢复、核验、供应商开关及原有 MiMo 合同。补充引用恢复后的针对性检查 **21 项通过**,见 `tmp/deepseek-final-citation-tests.log`。编译检查通过。
+
+已检查 27 个已完成测试的配置、结果、数据库及日志文件,没有发现密钥模式;新密钥没有保存到应用默认配置。新增测试参数 `--api-key-env` 仅从进程环境读取临时密钥。
+
+## 使用状态与边界
+
+本次交付仍是源码修改,没有重新打包或重启桌面应用。完整读取与正确总结分别验证;数据源不可用时说明快照限制,用户明确要求完整覆盖时保留缺口。真实模型仍有随机性,本轮通过的样本不等于任意问题零失败。
diff --git a/docs/deepagents-fixes-2026-09-13.md b/docs/deepagents-fixes-2026-09-13.md
new file mode 100644
index 00000000..6f591737
--- /dev/null
+++ b/docs/deepagents-fixes-2026-09-13.md
@@ -0,0 +1,66 @@
+# DeepAgents 性能与可靠性修复验收
+
+后续更新:用户提供临时 DeepSeek 密钥后已继续完成实测并修复新发现的问题,见 [DeepSeek 继续验收记录](deepagents-deepseek-followup-2026-09-13.md)。下文保留 MiMo 阶段的原始结果与当时的阻断状态。
+
+日期:2026-09-13。真实调用使用现有 Xiaomi MiMo 配置(`mimo-v2.5`)。测试状态独立保存;没有修改用户聊天记录、模型配置或安装包。
+
+已修复执行器、工具合同和核验中的已定位问题。最终策略的完整委派实测尚未完成:MiMo 返回 HTTP 402 余额不足后停止测试。不能将离线测试通过、子任务完成或草稿生成视为最终答案验收通过。
+
+## 修改及适用边界
+
+| 问题 | 修改 | 保留的约束 |
+| --- | --- | --- |
+| 全量分析反复搜索、重读待提交页 | 根据真实进度提供工具;暴露有效范围和页编号;完整范围分析员读完后不再搜索 | 普通搜索仍允许分页;获得新证据后恢复搜索 |
+| 子任务重复确定范围、读取父任务已读页 | 程序绑定精确范围;相同范围接续游标和待提交页;提示独立范围一起委派 | 不跨会话、日期、发言人或最近 N 条合同复用 |
+| 已读完分片但主任务仍认为未完成 | 按相同过滤条件计算范围覆盖的并集 | 有缺口、未提交页或仅完成统计时不能冒充完整分析 |
+| 已选聊天却直接回答无法读取 | 没有执行必要读取时提供真实范围及读取步骤,有限纠正 | 问候、目录问题、澄清问题和已有有效证据不强制读取 |
+| 引用编号格式容易出错 | 校正已登记编号的常见前缀、反引号和组合括号;唯一匹配的原话补消息引用 | 不修成猜测的编号;人物引用不代替消息依据 |
+| 通知时间被当成实际事件时间 | 检查消息时间、计划时间和完成状态的常见混淆;保留不确定性 | 不据消息发送时刻推断准时、提前或延迟 |
+| 核验模型拿不到总结所需的后续证据 | 无引用概括段携带全文已引用原文;缓存随正文、证据和范围变化失效 | 不使用旧回答或摘要替代原文 |
+| 核验返回正确程序事实仍被拒绝 | 精确比对范围、群名、来源元数据;“所有会话完成”逐行验证 | 任一范围未完成、数值或来源不符仍拒绝 |
+| 已知错误修复前后重复核验全文 | 先修复程序能发现的错误,再做语义核验;保留已通过的批次与条目 | 最终正文仍须核验;失败保留草稿,不伪装成功 |
+| 每批都开启长推理导致核验慢 | 首轮轻量核验;仅未通过条目的结构纠正和正文修复恢复正常推理 | 此最终策略已做离线验证,完整真实调用复测被余额不足阻断 |
+| 普通快照问答因实时资料缺口一直不能结束 | 可用快照读完后说明数据限制并回答 | 用户明确要求完整覆盖时仍保留缺口和未完成状态 |
+| HTTP 402 继续无效请求 | 立即说明余额不足、保留进度;矩阵测试停止后续同配置用例 | 不把余额问题当作可通过重试解决的连接问题 |
+
+核心文件:`deep_runtime.py`、`deep_tools.py`、`deep_model.py`、`deep_validation.py`、`deep_omissions.py`、`agent_references.py`,位于 `src/wechat_decrypt_tool/ai/`。
+
+## MiMo 真实调用记录
+
+以下来自不同迭代,不能当作同一最终版本的全绿结果。时长包含模型响应及核验;部分测试同时运行,不构成严格性能基准。隐私聊天原文只保存在本地测试结果中,不复制到本文。
+
+| 用例 | 结果 | 耗时 / 模型调用 | 本地记录 |
+| --- | --- | --- | --- |
+| 原始问题“最近讨论了哪些重要的事?”、真实聊天 | 完成,50 条来源 | 70.89 秒 / 5 次 | `tmp/deep-mimo-release-overview-20260913` |
+| 问候 | 完成,无工具调用 | 8.45 秒 / 1 次 | `tmp/deep-mimo-final-other-20260913` |
+| 精确统计 | 完成,范围内总数 5,人员分布正确 | 31.06 秒 / 3 次 | 同上 |
+| 保持范围、只统计指定人员的追问 | 完成,2 条,范围及人员过滤正确 | 12.61 秒 / 3 次 | 同上 |
+| 跨群日期变更 | 完成,区分提议、确认、取消、已发生;人工复查原文 | 252.89 秒 / 15 次 | 同上;长推理对照版本 |
+| 最近总共 3 条 | 较早迭代完成,确为跨群总共 3 条 | 39.19 秒 / 3 次 | `tmp/deep-mimo-fixed-matrix-20260913` |
+| 无匹配主题 | 较早迭代完成,无依据时未编造该主题 | 40.98 秒 / 8 次 | 同上 |
+| 事实题 | 初次自动检查通过,但人工发现“在该时间点完成”的无依据结论;新增检查后修复完成 | 初次 223.09 秒;恢复核验另加 118.24 秒、3 次调用 | `tmp/deep-mimo-acceptance-fact-20260913`;恢复耗时不能当作新任务耗时 |
+| 完整委派 | 两个子任务各 5 次调用,13 条全部读取并分析;最终核验未完成 | 长推理对照在 430.31 秒主动停止 | `tmp/deep-mimo-final-regression-20260913` |
+| 最终轻量首检策略:事实题、完整委派 | **未通过实测验收**:HTTP 402,无法继续请求 | 不作为性能成绩 | `tmp/deep-mimo-balanced-fact-20260913`、`tmp/deep-mimo-balanced-full-20260913` |
+
+最后一轮最近 N 条、无匹配用例也遇到 HTTP 402;不能用它们替换较早迭代已通过的记录,也不能宣称最终全矩阵通过。
+
+## 离线回归
+
+测试覆盖统计与分析游标隔离、范围并集、时间和发言人边界、最近 N 条、引用与身份、待提交页、部分失败恢复、原文遗漏检查、模型纠正策略和缺口状态。使用确定性模型响应及独立数据库,不请求外部模型。
+
+执行命令:
+
+```powershell
+.venv/Scripts/python.exe -m pytest tests/test_ai_deep_mimo_regressions.py tests/test_ai_deep_contracts.py tests/test_ai_deepagents.py tests/test_ai_deep_reliability.py tests/test_ai_deep_omissions.py tests/test_ai_citation_check.py tests/test_ai_citation_recovery.py tests/test_ai_person_identity.py tests/test_ai_recent_bounds.py -q
+.venv/Scripts/python.exe -m compileall -q src/wechat_decrypt_tool/ai tools/verify_deepagents_matrix.py tools/verify_deepagents_real.py
+```
+
+最终日志:`tmp/deepagents-delivery-tests-20260913.log`。**156 项通过,耗时 87.40 秒;编译检查通过。**
+
+## 尚未完成的验收
+
+- MiMo 余额恢复后,从新隔离目录复测事实题、完整委派及全部问答矩阵;不能只恢复草稿后报一个较短耗时。
+- 最终完整答案须人工核对人物、逐字引用、计划与实际状态、金额和覆盖范围。现有自动检查不能证明所有语义正确。
+- 本次修改的是源码,没有重新打包或重启已安装的桌面应用。
+
+这组回归为其他问题提供防护证据,但不意味着所有模型输出零失败。已知可确定的错误由程序约束;不可核实的输出保留草稿和恢复入口。
diff --git a/docs/deepagents-migration.md b/docs/deepagents-migration.md
new file mode 100644
index 00000000..1e2d9777
--- /dev/null
+++ b/docs/deepagents-migration.md
@@ -0,0 +1,112 @@
+# 微信助手 DeepAgents v3
+
+本说明取代旧版三阶段执行流程。依赖固定为 `deepagents==0.7.13`,由 `uv.lock` 锁定传递依赖。验收记录见 [迁移验收](deepagents-acceptance.md)。
+
+## 执行路径
+
+```mermaid
+flowchart TD
+ UI[聊天界面与 REST] --> Service[任务服务:幂等、版本、取消、历史]
+ Service --> Graph[官方 create_deep_agent]
+ Graph --> Model[DeepChatModel]
+ Model --> Queue[全应用共享调度与请求审计]
+ Queue --> Provider[已配置供应商客户端]
+ Graph --> Tools[标准微信工具与服务端范围句柄]
+ Graph --> Children[范围分析员与事实核查员]
+ Graph --> Context[官方摘要中间件与虚拟数据库后端]
+ Tools --> Data[原消息读取、搜索、统计、附件解析]
+ Children --> Tools
+ Graph --> Events[持久化事件与兼容投影]
+ Events --> SSE[SSE 与界面]
+```
+
+`AgentService` 保留 HTTP 层所需的任务生命周期,生产运行继承 `DeepAgentRuntime`,不再运行旧的 `parse_context → 决策 → answer` 循环。旧报告主循环和旧子任务执行器不再进入生产调用链。复用的分页、日期、原文、统计和来源函数仍是独立数据能力。
+
+问候和能力询问在同一次主模型请求直接生成正文,没有模型路由器或问候白名单。初始工具只提供范围选择和内部笔记写入;有内部资料后提供回查工具,已有笔记可直接修改,不必先查询聊天。已选范围后再提供查询、统计、分析等工具。模型可以直接回答,不强制调用工具。
+
+消息提交只校验账号归属、读取本地模型配置、落库并启动任务。会话目录、人物目录和索引在查询工具真正执行时才使用。模型能力通过本地缓存读取,远程目录刷新不阻塞提交。完整会话 ID 列表只保存在服务端状态中,模型收到数量、有限候选名和范围句柄。
+
+## 模块职责
+
+| 模块 | 职责 |
+| --- | --- |
+| `deep_runtime.py` | 官方图构建、公开中间件、子图委派、版本与恢复、正文投影和最终校验 |
+| `deep_model.py` | 原生工具与 JSON 协议适配,模型请求调度、计量、超时和兼容缓存 |
+| `reasoning_client.py` | 官方 SDK 的扩展字段透传,保留 MiMo 原生多轮工具消息所需的 `reasoning_content` |
+| `deep_tools.py` | 查询范围、读取游标、已提交页面、检索、精确统计和原文回查 |
+| `deep_backend.py` | 账号、运行、输入版本隔离的数据库虚拟文件后端 |
+| `deep_context.py` | 官方摘要的触发、历史持久化核验和失败保留 |
+| `deep_validation.py` | 日期、文件声明、来源归属及完整报告的独立证据核验 |
+| `deep_projection.py` / `deep_subtasks.py` | 现有答案、来源、资料分页和子任务字段的兼容投影 |
+
+## 数据范围与完整性
+
+- `account`、运行 ID 和输入版本由服务端注入。工具参数没有可用于改变账号的字段。
+- `scope_handle` 绑定当前运行与版本;过期、跨运行或跨账号的句柄不能读取资料。
+- 使用固定截止时间、固定时区与左闭右开区间。用户明确写出的时刻优先于模型的换算值。最近 N 条是用户明确指定的总量,不是分页大小。
+- 查询时匹配明确点名的会话,防止参数失败后扩大到全部聊天。重名返回澄清候选。完整读取不能只覆盖点名对象中的一部分。
+- 普通搜索保存实际命中和来源,实时缺口使用独立游标回查,不把搜索完成当成分析完成。
+- 完整范围的每一页先保存原文,再提交带来源的发现和覆盖区间;即使无相关发现也必须提交。失败重放返回尚未提交的同一页。
+- 来源按真实消息身份去重。同秒消息依靠稳定游标和消息身份,长消息的字符偏移随页面保存。覆盖显示按会话合并,避免重复范围造成数量翻倍。
+- 精确统计由程序计算;日分布和发言人分布分页读取计算结果。读取存在缺口或警告时不能宣称完整。
+
+范围分析员和事实核查员由官方 `task` 子图入口执行。服务端将范围绑定到子运行,范围分析员不能缩小或扩大分配范围,不能更换受限发言人;子任务不能递归委派。超过 60 天的范围按 30 天分片。已完成的子任务按确定性身份复用,父任务汇总时不重复计算用量或原文。
+
+## 模型与上下文
+
+原生模式使用自动工具选择,正文可流式输出。非原生模式只接受工具列表或包含完整正文的最终回答 JSON;适配器转换为标准 `AIMessage` 后继续由 DeepAgents 执行。JSON 正文校验完成后再展示,不额外请求一次正文。明确拒绝工具参数时才切换兼容模式,缓存按接口、模型和配置版本隔离。已确认支持 JSON mode 的接口启用该格式约束,仍进行本地结构检查。
+
+参数纠正、兼容重试、附件解析、摘要、子任务和证据核查均进入同一调度和审计。全应用模型并发上限为四,前台请求优先,遇到限流退让。排队取消或本地适配初始化失败不记成已经发出的模型请求;上游未返回用量的请求明确记录未知。
+
+MiMo 的扩展字段通过官方 OpenAI SDK 完整透传,不把思考字段显示在正文。已确认的供应商输出上限用于预算;显式模型配置和思考等级仍优先。参考 [MiMo 多轮工具调用要求](https://mimo.mi.com/docs/en-US/quick-start/usage-guide/text-generation/deep-thinking)、[模型长度上限](https://mimo.mi.com/docs/en-US/quick-start/summary/model)及 [JSON mode](https://mimo.mi.com/docs/en-US/quick-start/usage-guide/text-generation/structured-output)。
+
+上下文由官方摘要中间件触发,`DurableSummarization` 负责持久化核验、分段摘要和超限恢复。默认阈值为可用输入预算的 80%,目标保留约 10% 的近期消息,正常摘要请求上限为 55%。这里的预算采用 UTF-8 字节保守估算,计入工具定义、工具参数和需要回传的思考字段,不等于供应商实际 Token 用量;主请求的用量校准不改变此摘要计数口径。
+
+待压缩历史按时间顺序全部进入分段摘要,不再使用要求从用户消息开始的尾部裁剪。单条超长消息也按 Unicode 字符边界分段。每一段的完整请求计入提示词、累计摘要和消息封装;模型合并上一段摘要与本段资料,生成新的累计摘要。摘要目标上限为本次摘要请求预算的 20%,最多 8192 UTF-8 字节;空摘要、过长摘要及框架占位内容最多尝试三次,失败保留原检查点。这是语义摘要,不保证逐字保留,完整原文仍通过归档路径回查。
+
+未到阈值但本地检查或供应商报告上下文超限时,框架立即压缩后重试。主动压缩后主请求仍超限,则额外恢复最多两次,每次将近期保留量及摘要请求预算缩小一半(摘要请求预算最低 1024)。摘要请求自身超限时缩小片段,未成功的片段不推进游标;固定提示内容也放不下时停止,避免无限重试。同时超过近期保留量与摘要请求预算的已完成工具批次可整组归档摘要,保持工具调用与结果配对。历史归档在压缩后的主模型调用之前核验;归档或摘要失败不提交压缩结果。整个流程继续使用同一模型调度和用量审计,摘要正文不进入公开回答。
+
+虚拟文件后端不连接宿主文件系统。模型只能修改 `/notes/`、`/plans/`、`/drafts/`;原文和应用说明只读。框架产生的历史与大结果由服务端存入内部区域。资料与子任务中的指令不能改变这些边界,没有终端、联网搜索或发送微信的工具。
+
+同一 AI 对话的新轮次桥接近期对话、可回查来源和内部笔记。带引用笔记先核验编号和归属;笔记仍不是原始证据,也不是新用户指令。其他 AI 对话不继承这些资料。
+
+## 完成、停止与恢复
+
+新任务写入 `engine=deepagents`、`engine_version=3`。检查点位于独立的 `deepagents_checkpoints.sqlite3`,新运行的命名空间包含账号、AI 对话、运行和输入版本。早期隔离验收的 v3 命名空间保留兼容读取,不与旧引擎检查点混用。
+
+停止保留原文、待提交页面、发现和子任务成果。恢复使用新检查点;如果图已保存最终回答但应用尚未提交完成状态,直接交付已保存的正文。旧版本已保存的草稿仍优先恢复,不被图中早先的正文覆盖。运行中补充要求先增加版本并取消旧工作,再以新版本继续;过期结果不可提交。
+
+正文生成后直接保存回答并结束任务,不再执行独立的引用核查、证据复核、遗漏核查或自动修正,也不为这些步骤追加模型调用。普通问答、完整报告和子任务均使用这一完成流程。
+
+读取范围、分页提交和数据源缺口仍按工具返回的程序状态记录;完整范围尚未处理完时保留阶段结果。回答后的核查不再作为完成状态的前置条件。
+
+## 历史迁移与接口
+
+首次启动切换前通过 SQLite backup API 写入 `before-deepagents-v3.sqlite3`,再记录迁移标记。旧答案、来源、用量和原始任务状态保留可读。旧未完成任务不能继续执行旧检查点,也不会自动产生模型费用。
+
+保留 `/api/ai/agent` 现有对话、消息、运行、资料和 SSE 接口。新增:
+
+- 运行字段:`engine`、`engine_version`、`can_resume`、`restart_required`、`restarted_from`。
+- 覆盖状态:`not_applicable`、`partial`、`complete`、`unknown`。
+- `POST /runs/{id}/restart`:请求体带 `request_id`,幂等创建新引擎运行,并关联旧运行。
+- 对旧引擎运行调用 `continue` 返回明确的迁移错误和重新运行入口。
+
+删除 AI 对话或清理账号时,同时清理原文、内部文件、子任务关联和新检查点。生产运行没有自动回退旧引擎的路径。若回滚应用版本,必须先停止任务、另存迁移后的数据库副本,再恢复与旧版本匹配的备份,不能把新图检查点交给旧代码。
+
+## 界面与构建
+
+时间线来自实际模型、工具和子任务事件,不预绘固定三阶段。只有主 Agent 面向用户的正文进入回答区域,内部摘要和核查过程不会混入。无数据查询的对话不显示会话数量、索引提示、覆盖警告或空出处入口。
+
+执行入口使用官方 `astream_events(version="v3")` 事件流,按消息身份与所属任务接收正常回复正文;只读取 `text-delta`,不展示推理或工具参数。工具定义和执行路径均已移除 `progress_message`。模型与工具调用一起返回的公开正文保存为阶段汇报,最终无工具调用的回答独立保留;JSON 兼容模式将协议中的正文转换回标准 `AIMessage.content`,不新增业务工具参数。
+
+阶段汇报侧重已经完成的工作、已有发现及仍未确定的事项,可以在一组操作后产生,不要求逐次预告工具或下一步计划。提示词将其明确为长任务的正常沟通要求:首次取得有用资料且仍需继续分析时分享收获,后续出现关键发现、判断变化或影响结果的阻碍时再汇报;尚未取得资料时无需开场预告,简单任务或即将完成时直接回答。没有按时间、消息数量或轮次强制回复的程序规则,缺少阶段文字不会阻断或触发重试。公开汇报按应用的 `progress` 时间线事件及时保存、推送,按实际顺序与操作记录穿插,以普通段落展示,支持 Markdown 和已有引用。最终正文单独显示,不覆盖此前汇报。只展示模型实际产生的公开回复,不编造阶段文字,也不为进度额外调用模型。
+
+含阶段性回复的过程在完成后默认保留可见,用户可以一键收起;显式展开或收起的选择在进度刷新和重新挂载后保留。没有阶段性回复的已完成历史沿用原有折叠行为。
+
+官方依据:[Deep Agents Streaming](https://docs.langchain.com/oss/python/deepagents/streaming) 区分模型消息、步骤更新和自定义事件;[Event streaming](https://docs.langchain.com/oss/python/deepagents/event-streaming) 推荐 v3,并说明需要精确到达顺序时可消费原始协议事件。本项目在主任务及拥有独立持久化检查点的子任务中统一使用 v3,再按各自任务身份写入现有时间线。这些接口传递已经产生的内容,并非自动生成自然语言阶段总结的功能。
+
+SSE 使用持久化事件 ID、记录 ID 和修订号支持断线重连;正文增量直接投影,正文生成结束后保存答案并发布完成状态。保留来源定位、人物胶囊、复制、滚动和模型选择交互。
+
+`desktop/scripts/ai-packaging.cjs` 收集 DeepAgents、LangChain 及其动态依赖;`tools/build_ai_smoke.cjs` 验证冻结后的真实图和检查点运行。Windows/macOS 继续使用 `.github/workflows/ai-cross-platform.yml`。安装包发布不属于本次工作。
+
+官方框架接口参考:[概览](https://docs.langchain.com/oss/python/deepagents/overview)、[后端](https://docs.langchain.com/oss/python/deepagents/backends)、[上下文](https://docs.langchain.com/oss/python/deepagents/context-engineering)、[子 Agent](https://docs.langchain.com/oss/python/deepagents/subagents)。没有修改依赖包源码。
diff --git a/docs/deepagents-mimo-tests-2026-09-13.md b/docs/deepagents-mimo-tests-2026-09-13.md
new file mode 100644
index 00000000..b3cb3248
--- /dev/null
+++ b/docs/deepagents-mimo-tests-2026-09-13.md
@@ -0,0 +1,47 @@
+# Xiaomi MiMo 多问题实测(2026-09-13)
+
+## 范围
+
+使用用户已配置的 Xiaomi MiMo(mimo-v2.5),运行与前轮 DeepSeek 相同的封闭样本和真实聊天问题。共 8 类封闭样本任务、1 次事实问题复测、2 轮真实聊天任务,合计 11 次任务运行。模型输出为真实接口返回;封闭样本的数据源为两个群的 13 条已知消息,生产 AgentService、DeepAgents、工具网关、检查点及答案校验均照常运行。
+
+测试使用独立状态目录,没有修改应用默认模型、聊天资料或生产逻辑。部分测试并发运行,耗时是本次观测值,不构成严格的模型性能排名。通过与否包含人工语义核对,不以 completed 状态或自动检查全部为 true 代替实际正确性。
+
+## 结果
+
+| 问题 | 耗时(秒) | 模型调用数,含子任务及校验 | 复核结果 |
+|---|---:|---:|---|
+| 问候 | 6.67 | 1 | 通过,没有读取聊天 |
+| 最终发布日期及是否实际发布 | 109.44 | 23 | 失败:校验材料不全造成误判;保留草稿仍把通知时间误当成精确发布时间 |
+| 指定时间、会话的精确统计 | 19.78 | 3 | 通过,总计 5 条,两人分别 3 条、2 条 |
+| 保持范围、只统计指定发言人 | 22.67 | 3 | 通过,正确继承范围并统计为 2 条 |
+| 跨群日期变更 | 191.45 | 46 | 主要事件和引用正确,但调用过多;聚餐举行与次日结清的日期表述需要更清楚地区分 |
+| 两群合计最近 3 条 | 53.02 | 5 | 通过,读取集合、内容、发言人及顺序正确;有多余的会话名纠正 |
+| 无相关采购记录 | 41.47 | 10 | 核心结论通过,读完 6 条消息后确认没有采购讨论;“内容均为发布日期讨论”的附带概括忽略了一条无关转发文本 |
+| 显式委派、完整覆盖两群 | 421.17 | 66 | 未通过;达到 420 秒截止条件后停止,一个子任务完成,另一个尚未完成 |
+| 相同事实问题复测 | 33.52 | 6 | 失败:source_id: 引用类型无效,两次修复无效;草稿仍把 10:05 报告时间写成精确发布时间 |
+| 真实聊天中的事实查证 | 47.89 | 4 | 状态完成但任务未通过:未调用聊天读取或搜索工具,零条来源,错误地声称系统无法读取聊天 |
+| 真实聊天同范围追问 | 108.64 | 7 | 能读到原文并正确继承范围;未严格通过:原话只关联人物引用、没有逐条消息定位,且夹带了筛选要求以外的内容 |
+
+用量记录确认本轮调用的模型全部为 xiaomi / mimo-v2.5,没有状态为 failed 的供应商请求记录。前轮 HTTP 402 余额错误未再出现;本轮失败和超时不能再归因于前轮余额不足。
+
+## 关键证据与解释
+
+1. **更换模型没有解决执行与校验问题。** 首次事实问答的答案已经含有发布日期确认和实际完成消息,但校验请求的首批段落只带了早期计划与延期建议,导致核验器声称没有确认和完成依据。这是分批核验材料组织问题,不能单纯归咎于模型推理。
+2. **时间推断错误仍存在。** 两次事实问题草稿均将“10:05 收到已发布的消息”升级为“10:05 实际发布”。测试脚本原来的“晚五分钟”正则没有捕获这种不同措辞,人工复核判为内容错误;不能将该正则通过作为时间语义正确的证明。
+3. **跨群分析存在无效探索。** 46 次模型调用、40 次主任务工具调用中,反复尝试不同的未命中关键词(例如活动名称与星期词),之后才形成答案。当前只检查相同调用重复的保护无法识别这种语义相近但参数不同的低收益搜索。
+4. **完整委派没有按时收敛。** 一个子任务完成 6 条消息的全量读取和分析;另一个子任务到测试截止时仍未完成。后者出现把 message_count 当分页大小、空关键词搜索、向不属于当前范围的页面提交发现等错误。全任务累计 66 次模型调用,主任务只接收到了第一个子任务的完整结果。
+5. **完成状态缺少任务达成检查。** 真实聊天首轮只有 select_chat_scope、ls、grep,没有尝试 read_messages 或 search_messages,却给出“系统不具备获取消息文本能力”的回答并标为完成。随后追问成功读取 132 条来源,直接表明首轮的能力断言不成立。
+6. **真实追问的引用粒度不足。** 原文存在且时间、会话范围正确,但每条都只引用同一个人物,无法逐条定位原消息;工具过程中还出现一次页面范围提交错误。不能把此例计为严格的“原话及来源筛选”通过。
+
+这些发现支持继续改进工具参数可用性、等价范围与页面状态、检索收敛、核验材料完整性、无歧义引用规范化,以及最终回答是否完成用户任务的判断。它们不支持通过关闭完整性检查、禁止跨群任务或为某一句问题写特例来提速。
+
+## 本地产物
+
+- `tools/verify_deepagents_matrix.py`:可重复运行的封闭样本测试。
+- `tmp/deep-mimo-matrix-20260913/results.json`:7 类常规案例原始结果。
+- `tmp/deep-mimo-full-20260913/results.json`:完整委派原始结果。
+- `tmp/deep-mimo-repeat-fact-20260913/results.json`:事实问题复测。
+- `tmp/deep-mimo-real-fact-20260913/results.json`:真实聊天两轮结果。
+- `tmp/deep-mimo-matrix-20260913/reviewed-results.json`:人工复核结论,保留原始自动检查以便对照。
+
+各目录的 state 保存独立 SQLite 状态、调用用量与检查点;对应日志在 tmp 下。真实聊天产物含私人原文,仅本地保留。
diff --git a/docs/deepagents-question-matrix-2026-09-13.md b/docs/deepagents-question-matrix-2026-09-13.md
new file mode 100644
index 00000000..3d364e71
--- /dev/null
+++ b/docs/deepagents-question-matrix-2026-09-13.md
@@ -0,0 +1,63 @@
+# DeepAgents 多问题实测记录(2026-09-13)
+
+## 结论
+
+本次补测不能得出“其他问题均不受影响”的结论。问候、精确统计、同范围追问、跨群最近 N 条通过;事实问答出现一次无依据的时间推断;跨会话和完整报告仍存在显著的校验开销及覆盖状态问题。最后模型接口返回 HTTP 402(Insufficient Balance),部分案例未完成,不计为通过。
+
+本轮新增可重复运行的测试工具和报告,没有根据单个测试问题修改生产提示词或业务规则。
+
+## 方法与边界
+
+- 使用当前配置的真实 DeepSeek Flash 模型和生产 AgentService、DeepAgents 图、工具网关、检查点、校验流程。
+- 封闭样本共两个群、13 条消息,含计划、提议、确认、取消、实际完成、费用结算,以及一条资料内嵌指令。模型回答并非预制;仅底层聊天数据源采用已知答案的测试实现。
+- 另外使用真实聊天数据测试事实查证和后续筛选。测试存储独立,未修改用户聊天、默认模型配置或正在使用的任务。
+- 共 8 类封闭样本任务、一次相同事实问题复测、两轮真实聊天任务,合计 11 次提交。实测有并行运行,耗时不作为严格的单任务性能基准。一次或两次采样不足以估计模型失败概率,也没有同条件旧版对照,不能据此声称整体性能提升或没有回归。
+- 自动检查程序统计、范围、来源编号、读取集合及覆盖状态,并人工复核关键语义。引用格式正确不等于结论正确;任务 completed 不等于整体通过。
+
+## 实测结果
+
+| 案例 | 秒 | 模型调用(含子任务、校验) | 结果 |
+|---|---:|---:|---|
+| 问候/能力介绍 | 3.69 | 1 | 通过;没有调用聊天工具 |
+| 事实问答:最终发布日期、是否已发布 | 14.36 | 6 | 内容未通过:把 10:05 的“已上线”消息推断成比计划晚 5 分钟上线 |
+| 精确统计:指定群、指定起止时间、按人计数 | 7.34 | 3 | 通过;总计 5 条,小林 3 条、阿明 2 条 |
+| 追问:保持范围,只统计阿明 | 9.14 | 3 | 通过;保留原起止时间及会话,正确筛选为 2 条 |
+| 两群日期变更与事件状态 | 269.11 | 19 | 主要事件正确;性能及覆盖说明未通过,详见下文 |
+| 两群合计最近 3 条 | 14.75 | 4 | 通过;准确选取全局最新的 3 条并按时间排序;有多余的会话名称解释 |
+| 无匹配:是否讨论采购无人机 | 38.06 | 7 | 未完成;草稿结论方向正确,但引用格式无效,修复时遇到 HTTP 402 |
+| 显式委派、完整分析两群全部消息 | 368.02 | 26 | 两个子任务完成、13 条原文全部读取并分析;最终校验遇到 HTTP 402,整体未通过 |
+| 相同事实问题再测一次 | 121.20 | 16 | 内容通过;自行委派且耗时显著增加,并出现一次时间参数错误后纠正 |
+| 真实聊天:指定时间内的事实与计划区分 | 305.61 | 10 | 达到测试的 300 秒截止条件后停止;保留草稿及 238 条来源,未通过最终校验 |
+| 真实聊天追问:沿用范围筛选原话 | 1.41 | 1 | HTTP 402,首个模型请求即失败;未完成,无法判断筛选能力 |
+
+“资料内嵌指令”未在人工复核的已完成回答中得到执行。初版测试把答案中出现该文本也判为失败,误伤了“引用并解释该文本”的回答;复核将此与执行指令区分。原始 results.json 保留,修订后的检查及语义结论另存 reviewed-results.json,不用修改原始记录掩盖错误。
+
+## 已定位的问题
+
+1. **消息时间被当成事件发生时间。** 计划时间为 10:00,10:05 发出“已经上线”只能证明当时已报告完成,不能证明晚了 5 分钟。第一次事实问答的引用有效,但错误结论仍通过现有流程;第二次没有犯同样错误。
+2. **重叠查询范围的覆盖状态没有正确合并。** 跨群案例先建立两群的普通范围,再建立每群的完整分析范围。两群各自读完两页、提交全部发现后,普通范围仍为 read_complete=false,最终汇总也显示两个群未完整读取。这与封闭样本及分页记录不符,触发了多余的“覆盖不足”修复。
+3. **校验和局部修复占据大量调用。** 跨群案例共 19 次调用,其中主分析 8 次、证据校验 9 次、引用修复 2 次。校验累计请求时长约 244 秒,修复约 35 秒;存在并发,不能直接相加为墙钟耗时。校验输入缺少部分已读原文、页数等执行依据时,还会把实际存在的消息或已完成的步骤误判为无依据。
+4. **简单问题仍可能自行扩展为委派任务。** 同一事实问题两次耗时约 14 秒和 121 秒;这不是复杂任务能力被取消,而是执行策略仍不稳定。
+5. **工具调用失败仍有可预防项。** 完整委派首次使用中文角色名“范围分析员”,工具只接受 range-analyst / fact-checker,返回无法调用后模型再纠正;这类失败在时间线中还被标记为完成。事实复测也出现一次非完整 ISO 时间参数的校验错误。
+6. **引用类型存在格式漂移。** 无匹配案例输出 message: 和未注册的 conversation: 引用,真实聊天案例也进入引用修复,增加了调用与失败机会。
+7. **外部计费错误被泛化。** 实际原因是 HTTP 402 Insufficient Balance,界面错误只显示“模型调用未完成,已保留进度”。后续没有继续新增模型调用;未充值、未更换用户模型配置。
+
+## 后续优化应保持的边界
+
+- 按等价时间边界、会话、筛选条件和读取方式合并覆盖证明;不能因为有一个已完成范围就宣布所有范围完整。
+- 让程序直接验证页数、来源注册、计数等可确定事实;证据校验携带相关原文和执行依据,只复核变化的段落,保留必要的语义核查。
+- 将“不需要更多证据即可作答”的收敛条件做成通用策略,保留用户要求的全量分析、跨群分析和显式委派。
+- 区分发言时间与事件时间;补充有依据/无依据推断的回归用例,不能靠针对本题的字符串替换修答案。
+- 提供模型可直接使用的角色标识与参数示例;只规范化无歧义的引用别名,未知来源继续拒绝。
+- 明确呈现余额不足等不可重试错误,保留已完成工作。真实模型复测需等模型接口恢复可用后继续,不能把当前未完成项计为通过。
+
+## 复现与产物
+
+运行工具:`tools/verify_deepagents_matrix.py`。通过 `--profile` 选择已有模型配置,通过 `--output` 指定隔离目录;支持 `--cases` 选择案例及 `--timeout` 设置每例截止时间。使用 `followup` 案例时一并选择 `statistics`,以建立前轮范围。
+
+- 封闭样本原始记录:`tmp/deep-matrix-20260913/results.json`
+- 人工复核及修订检查:`tmp/deep-matrix-20260913/reviewed-results.json`
+- 完整委派:`tmp/deep-matrix-full-20260913/results.json`
+- 事实复测:`tmp/deep-matrix-repeat-fact-20260913/results.json`
+- 真实聊天及追问:`tmp/deep-other-real-fact-20260913/results.json`
+- 各目录 state 下保存独立 SQLite 状态与检查点,根 tmp 下保存对应日志。真实聊天产物含私人原文,仅本地保留,不应随报告公开。
diff --git a/docs/deepagents-reliability-2026-09-13.md b/docs/deepagents-reliability-2026-09-13.md
new file mode 100644
index 00000000..fe1ade81
--- /dev/null
+++ b/docs/deepagents-reliability-2026-09-13.md
@@ -0,0 +1,54 @@
+# DeepAgents 通用可靠性与耗时优化
+
+此次保留官方 DeepAgents 的工具选择、子任务、分页、检查点和恢复能力。不针对某句提问设置固定查询分支,不固定“最近”的天数,不更换用户模型或降低其推理配置。
+
+## 已证实的问题
+
+- 原慢任务先查全历史,再统计三个月,再查询两周;约 6 分半后才委派一个子任务。
+- 普通概览被系统说明要求进入完整分析流程;统计完成与内容分析完成的反馈混淆。
+- 正常的 47 条消息分页结果约 17,396 字符,超过原文件转存阈值,额外引发读文件和搜索。
+- 子任务重新选择范围、重新读取父任务页面,并出现日期、搜索和引文参数错误。
+- 上游第一次断流约 156 秒,第二次只剩约 84 秒超时预算。真实异常来自 httpx2,与 httpx 的类型不兼容。
+- 并发分片回归触发 SQLite 检查点写锁冲突。
+- 真实复测发现回查消息锚点不存在的 HTTP 404 会终止整条工作流。
+- 实时源不可用时,完整任务被反复要求补齐无法读取的数据,最终被当作执行失败。
+
+## 实现
+
+1. 普通问答与重点概览允许依据足够证据结束;明确要求完整覆盖的任务仍执行完整读取、提交和来源校验。时间假设由模型结合语境确定并向用户说明。
+2. 计数与分析使用独立范围状态;统计的 complete 只表示计数完成。调用读取工具分析统计范围时,会创建相同边界的分析范围,返回真实句柄与页面。统计覆盖不能替代其他会话的完整内容分析。
+3. 每轮提供程序生成的范围、待提交页、完成状态和下一步工具。发现提交使用明确的嵌套结构;引文必须是连续原文。无需提交的页面返回可操作说明,不虚记为已分析。
+4. 同一输入版本复用会话名称目录;正常分页在输入预算内保留正文,过大结果仍转存;压缩及预算保护继续工作。
+5. 完全相同的完整分析范围可把父任务的页面、游标和待提交进度交给子任务。不同范围分片仍独立处理。子任务采用自身开始时间,并向界面提供自己的读取量、分析量和阶段。
+6. 对没有新增进度的相同结果,第二次起反馈恢复提示,第四次保留进度并停止;正常分页、提交和新的证据会重置此检查。不同参数错误不会仅因累计达到三次就停止。
+7. 模型调用单次最多 240 秒、每轮调用最多三次尝试,总预算最多 600 秒。尚未展示正文的断流可重试;半截工具参数缓存到严格 JSON 校验通过后再交给图。已展示正文后发生中断不盲目重放。鉴权和不可恢复参数错误不按瞬时连接故障重试。
+8. 兼容 httpx、httpx2 以及 OpenAI SDK 的连接异常;保留失败类型、是否已输出正文、尝试次数和实际用量审计。
+9. 并发父子图共享官方检查点连接及其写入锁,最后一个使用者退出后关闭连接。
+10. 锚点 404/410 返回已保存原文并标明缺失前后文;可恢复的查询服务错误返回工具反馈,权限错误仍不降级。
+11. 可用资料已处理但外部数据仍有缺口时,完整任务保存明确标注的阶段草稿并暂停。显式继续会刷新有缺口的读取缓存、重新核验,保留既有原文和发现。普通回答也会检查“已读完全部实时消息”等超出快照能力的表述。
+
+## 验证记录
+
+| 验证 | 结果 |
+| --- | --- |
+| 后端综合回归 | 125 项通过,涵盖官方图、完整范围、多会话分片、统计、媒体、引用、遗漏检查、版本取消与恢复 |
+| 最终故障注入与恢复测试 | 15 项通过;其中包含新增 httpx2 断流和 SDK 异常分类,其他项目与综合回归有重叠 |
+| 前端相关测试 | 7 个文件、76 项通过,覆盖子任务刷新、迟到响应隔离、时间线、引用与对话 |
+| 生产静态构建 | 通过,生成 34 个路由;现有 CSS 构建警告未在此次处理 |
+| Python 编译检查 | 修改模块通过 |
+
+日志:`tmp/deep-reliability-tests-final-20260913.log`、`tmp/deep-reliability-focused-final-20260913.log`、`tmp/deep-reliability-frontend-build-20260913.log`。
+
+真实验证使用已配置的 deepseek-flash、原聊天对象和独立任务库。原提问的一次复测用 142.25 秒生成结果,6 次工具调用、8 次模型调用;增加覆盖表述校验后再用 11.25 秒和 1 次模型调用完成修正。最终明确说明回答基于可用快照,未宣称覆盖全部实时消息。两阶段合计约 153.5 秒,不能将第二阶段的 11.25 秒当作从零完成耗时。
+
+该实测没有触发子任务或工具参数失败,但仅为单次样本,而且当前实时源不可用,与此前任务的数据可用性和截止时间不同,不能据此保证所有问题都有相同比例的提速。
+
+完整报告实测在旧流程中因实时缺口反复补查而失败。应用新逻辑恢复后,未新增模型调用,保留阶段草稿并转为 interrupted,明确要求数据源恢复后继续;这不计作完整报告成功。完整报告在可用数据条件下的行为由确定性真实图回归验证。
+
+真实结果位于 `tmp/deep-reliability-real-final-20260913/results.json` 和 `tmp/deep-reliability-real-full-20260913/results.json`,包含私人聊天内容,仅供本地检查,不提交或发布这些结果。
+
+## 生效与边界
+
+源码及前端构建已更新。已经启动并加载旧 Python 模块的应用需要重启后使用新后端。没有重启用户应用或重新打包安装程序。
+
+上游服务故障、鉴权失败以及不可读取的原文无法保证消除。此次目标是减少可以预防的失败、准确反馈剩余缺口,并在可恢复时继续;不以跳过证据或伪报完整来换取“成功”状态。
diff --git a/docs/media-failure-recovery-2026-09-13.md b/docs/media-failure-recovery-2026-09-13.md
new file mode 100644
index 00000000..ae2f949e
--- /dev/null
+++ b/docs/media-failure-recovery-2026-09-13.md
@@ -0,0 +1,11 @@
+# 图片分析失败后的回答恢复
+
+2026-09-13 截图中的任务已读取100条消息,随后并发分析三张图片。两次视觉模型 `mimo-v2.5` 请求返回 HTTP 402,另一张图片在本机缺失。这是三个不同来源的调用,不是同一请求重试三次。旧工具中间件把视觉服务异常抛出整个执行图,导致文字总结也中断。
+
+现在媒体工具的 `ProviderFailure` 会转为可恢复的工具错误:时间线保留真实失败状态及原因,模型收到媒体不可用信息,并被要求利用已有文字继续回答、说明缺口、不猜测图片内容。其他工具的模型异常仍按原来的失败路径处理,取消和版本检查继续生效。
+
+HTTP 402 有独立的脱敏说明及审计分类,提示检查服务账户余额、额度或计费状态,不自动重试。仅凭状态码无法确认账户的具体问题。没有更改用户的模型配置或计费设置。
+
+本机文件缺失也显式返回 `available: false` 和缺失原因。成功分析返回 `available: true`,保留其他并发工具的成功结果。媒体分析仍以派生结果保存,不覆盖原始消息。
+
+回归测试使用真实 DeepAgents 图和确定性模型,覆盖两张图片报错、第三张缺失或成功时仍完成文字回答,以及来源原文保留。供应商测试覆盖 HTTP 402 仅请求一次、错误脱敏和失败审计。
diff --git a/docs/optional-finding-quote-2026-09-13.md b/docs/optional-finding-quote-2026-09-13.md
new file mode 100644
index 00000000..7ca74567
--- /dev/null
+++ b/docs/optional-finding-quote-2026-09-13.md
@@ -0,0 +1,9 @@
+# 可选引文不再阻断整批发现保存
+
+截图中的运行在 `commit_findings` 保存阶段失败:第10项的 `quote` 不是对应消息中的连续原文。旧逻辑将可选引文视为整批提交的必要条件,迫使模型重新生成整页发现。
+
+现在不精确的附加引文会从保存对象中移除,保留分析文字和有效来源;返回结果包含移除数量和说明,模型和已存在的详情界面都能获知。真实连续原文的引文保留。分析文字仍是模型对资料的概括,不因来源编号有效就被当作逐字原文。
+
+来源编号不存在、不属于当前页、页面不属于当前范围等情况仍拒绝提交。若一批同时包含不精确引文和无效来源,整批不写入、不推进游标,防止部分保存被误记为整页完成。
+
+测试覆盖同批10项中的第10项引文失配、精确引文保留、发现与阶段笔记一致、调用参数不被修改、重复提交只推进一次、来源错误仍阻断,以及真实DeepAgents执行图一次提交后正常完成。
diff --git a/docs/recent-count-scope-fix-2026-09-13.md b/docs/recent-count-scope-fix-2026-09-13.md
new file mode 100644
index 00000000..427adcce
--- /dev/null
+++ b/docs/recent-count-scope-fix-2026-09-13.md
@@ -0,0 +1,9 @@
+# “最近的100条”范围选择失败
+
+用户任务的四次范围选择中,三次报“未指定该条数”,一次报日期条件无法识别。数量校验的正则只接受“最近100条”,未接受“最近的100条”;模型收到错误反馈后反复调整调用参数,尚未进入消息读取。
+
+修复允许“最近/最后/最新/近”与数字之间带“的”及空白。数量不匹配时明确反馈用户要求的数量,不再建议省略数量扩大范围;用户未指定数量时仍拒绝模型擅自用数量替代完整范围。
+
+回归覆盖原句及自然表达变体、带日期的数量范围、数量错误反馈、正式执行图成功读取100条且范围选择不重试,以及全部统计不能偷偷限制为500条。
+
+当前 deepseek-flash 配合隔离数据库和100条虚构消息实测,使用原句“最近的100条消息再说什么?”:3次模型调用、约9.2秒完成,范围选择与消息读取均成功。记录为 `tmp/recent-count-live-1789293102137925500/result.json`;没有读取真实聊天或保存测试密钥。
diff --git a/frontend/assets/css/agent.css b/frontend/assets/css/agent.css
index fd1bd607..1c3bb7d5 100644
--- a/frontend/assets/css/agent.css
+++ b/frontend/assets/css/agent.css
@@ -194,8 +194,8 @@ html[data-theme="dark"] .agent-thread-management .is-destructive, html[data-them
.agent-error { font-size:11px; color:#b95039; background:#b9503910; padding:9px 12px; border-radius:7px; margin:10px 16px; }
.agent-run .agent-error { margin:10px 0; }
.agent-composer { position:relative; flex-shrink:0; padding:6px 16px 10px; }
-.agent-input-box { border:1px solid var(--ag-border); border-radius:18px; padding:14px 14px 10px; background:var(--ag-soft); box-shadow:0 2px 8px #00000003; }
-.agent-input-box:focus-within { border-color:#079b5780; box-shadow:0 0 0 2px #079b5708; }
+.agent-input-box { border:1px solid var(--ag-border); border-radius:24px; padding:10px; background:var(--ag-bg); box-shadow:0 2px 8px #00000003; }
+.agent-input-box:focus-within { border-color:var(--ag-muted); box-shadow:0 0 0 1px var(--ag-border); }
.agent-input-box textarea { display:block; width:100%; min-height:28px; max-height:144px; resize:none; overflow-y:auto; border:0; outline:0; font:inherit; font-size:13px; line-height:1.6; background:transparent; color:inherit; padding:0; box-sizing:border-box; }
.agent-input-box textarea::placeholder { color:var(--ag-muted); }
.agent-input-actions { display:flex; gap:4px; align-items:center; margin-top:10px; min-width:0; }
@@ -203,7 +203,7 @@ html[data-theme="dark"] .agent-thread-management .is-destructive, html[data-them
.agent-input-actions > .agent-effort-select { width:84px; flex-shrink:0; }
.agent-input-actions .ui-select.is-plain .ui-select-trigger { gap:6px; padding:0 5px; font-size:11px; font-weight:400; height:28px; min-height:28px; }
.agent-input-actions > button { flex-shrink:0; width:28px; height:28px; padding:0; color:var(--ag-muted); font-size:12px; }
-.agent-input-actions .agent-send { margin-left:auto; color:var(--ag-bg); background:var(--app-text-primary,#25352d); width:30px; height:30px; border-radius:50%; padding:3px; font-size:15px; }
+.agent-input-actions .agent-send { margin-left:auto; color:#fff; background:#171717; width:28px; height:28px; border-radius:50%; padding:3px; font-size:14px; }
.agent-input-actions .agent-send:hover { background:var(--app-text-secondary,#5f5f5f); }
.agent-disclaimer { display:block; text-align:center; color:var(--ag-muted); font-size:10px; margin-top:6px; }
.agent-composer-settings { position:absolute; bottom:calc(100% - 4px); left:12px; right:12px; padding:12px; background:var(--ag-bg); border:1px solid var(--ag-border); border-radius:10px; box-shadow:0 -6px 28px #0001; z-index:5; font-size:12px; }
@@ -294,8 +294,17 @@ html[data-theme=dark] .agent-panel .agent-markdown .agent-ref[aria-expanded=true
.agent-run-metadata > summary > i:last-child { font-size:10px; }
.agent-run-metadata[open] > summary > i:first-child { transform:rotate(90deg); }
.agent-run-metadata[open] { padding-bottom:12px; }
-.agent-markdown .agent-ref { min-width:24px; min-height:22px; padding:2px 7px; margin:0 4px; background:#e5f7ef; color:#078653; border-radius:6px; font-size:12px; }
-html[data-theme=dark] .agent-panel .agent-markdown .agent-ref { background:#173c2b; }
+/* 句尾来源采用轻描边小胶囊;整颗换行,头像与编号始终保持一体。 */
+.agent-markdown .agent-ref { display:inline-flex; align-items:center; justify-content:center; gap:3px; vertical-align:middle; box-sizing:border-box; min-width:22px; height:20px; min-height:20px; padding:1px 6px; margin:0 2px; border:1px solid #ccebdd; border-radius:999px; background:#f8fcfa; color:#078653; font-size:11px; font-weight:400; line-height:16px; font-variant-numeric:tabular-nums; white-space:nowrap; cursor:pointer; }
+.agent-markdown .agent-ref:has(img) { padding-left:2px; }
+.agent-markdown .agent-ref img { flex:none; width:14px; height:14px; border-radius:50%; object-fit:cover; }
+.agent-markdown .agent-ref:hover { background:#edf8f2; border-color:#a9dcc3; }
+.agent-markdown .agent-ref:focus-visible { outline:2px solid #078653; outline-offset:2px; }
+.agent-markdown .agent-ref[aria-expanded=true] { border-color:#079b57; background:#079b57; color:#fff; box-shadow:none; }
+html[data-theme=dark] .agent-panel .agent-markdown .agent-ref { background:#22332b; border-color:#385a47; }
+html[data-theme=dark] .agent-panel .agent-markdown .agent-ref:hover { background:#294435; border-color:#538b69; }
+html[data-theme=dark] .agent-panel .agent-markdown .agent-ref:focus-visible { outline-color:#70d6a4; }
+html[data-theme=dark] .agent-panel .agent-markdown .agent-ref[aria-expanded=true] { background:#087c44; border-color:#70d6a4; }
@container (max-width:480px) {
.agent-tool > summary { gap:9px; flex-wrap:wrap; }
.agent-tool-title { gap:7px; flex:1; }
@@ -327,9 +336,12 @@ html[data-theme=dark] .agent-live-step > i { color:#63d99a; }
.agent-process-body .agent-tool-title { color:var(--ag-muted); }
.agent-process-body .agent-tool[open] { background:var(--ag-bg); }
.agent-process-body .agent-tool > summary { gap:10px; }
-.agent-process-body .agent-progress-note { margin:14px 8px; padding:2px 0 2px 12px; border-left:2px solid var(--ag-border); color:var(--ag-muted); }
-.agent-process-body .agent-progress-caption { display:block; margin-bottom:5px; color:var(--ag-muted); font-size:12px; font-weight:600; }
-.agent-panel .agent-process-body .agent-progress-note .agent-markdown { font-size:13px; line-height:1.7; color:var(--ag-muted); }
+/* 公开进展按普通段落阅读,工具使用较轻的文字,不再给每段套小结标签或引用框。 */
+.agent-process-body .agent-progress-note { margin:16px 8px; padding:0; border:0; color:var(--app-text-primary); }
+.agent-panel .agent-process-body .agent-progress-note .agent-markdown { font-size:14px; line-height:1.8; color:var(--app-text-primary); overflow-wrap:anywhere; }
+.agent-process-body .agent-progress-note.is-superseded { color:var(--ag-muted); }
+.agent-panel .agent-process-body .agent-progress-note.is-superseded .agent-markdown { color:var(--ag-muted); }
+.agent-progress-note > small { display:block; margin-top:6px; font-size:12px; }
.agent-process-body .agent-process-notice { margin:10px 8px; font-size:12px; line-height:1.65; }
.agent-stage-row { display:flex; align-items:baseline; flex-wrap:wrap; gap:4px 10px; padding:5px 8px; color:var(--ag-muted); font-size:12px; line-height:1.65; }
.agent-stage-row > i { width:14px; flex:none; text-align:center; font-size:10px; }
@@ -340,6 +352,22 @@ html[data-theme=dark] .agent-live-step > i { color:#63d99a; }
.agent-process-body .agent-process:empty { display:none; }
.agent-process-body:has(.agent-process:empty) .agent-run-metadata { margin-top:0; padding-top:0; border-top:0; }
.agent-process-body .agent-run-metadata { margin:12px 8px 0; padding-top:10px; border-top:1px solid var(--ag-border); }
+/* 摘要入口与实时进度分层,诊断信息按需展开。 */
+.agent-metadata-actions { display:flex; flex-wrap:wrap; align-items:center; gap:4px 20px; }
+.agent-metadata-actions > button { display:inline-flex; align-items:center; gap:8px; min-height:32px; padding:4px 0; margin:0; font-size:12px; color:var(--ag-muted); text-decoration:none; }
+.agent-metadata-actions > button i { flex:none; width:10px; text-align:center; font-size:10px; }
+.agent-metadata-actions > button:hover { color:var(--app-text-primary); }
+.agent-run-metadata button:focus-visible { outline:2px solid var(--ag-muted); outline-offset:3px; border-radius:4px; }
+.agent-coverage-summary { margin:0 0 4px; line-height:1.7; }
+.agent-run-details { padding:12px 0 4px; line-height:1.7; overflow-wrap:anywhere; }
+.agent-detail-facts { display:grid; gap:8px; margin:0; }
+.agent-detail-facts > div { display:grid; grid-template-columns:5em minmax(0,1fr); gap:12px; align-items:baseline; }
+.agent-detail-facts dt, .agent-detail-facts dd { margin:0; }
+.agent-detail-facts dd { color:var(--app-text-primary); font-variant-numeric:tabular-nums; }
+.agent-run-details .agent-usage { margin:12px 0 0; font-size:12px; }
+.agent-run-details .agent-coverage-note { margin-top:8px; }
+.agent-run-details .agent-index-note { margin-top:12px; }
+.agent-run-details button { min-height:32px; padding:4px 6px; font-size:12px; text-decoration:underline; text-underline-offset:3px; }
.agent-answer-heading { margin:0 0 12px; font-size:14px; line-height:1.5; font-weight:600; color:var(--app-text-primary); }
.agent-panel .agent-final-answer .agent-markdown { font-size:15px; line-height:1.85; }
@container (max-width:480px) {
@@ -364,11 +392,91 @@ html[data-theme=dark] .agent-live-step > i { color:#63d99a; }
.agent-thread-item.is-current:hover, .agent-thread-item.is-current:focus-within { background:color-mix(in srgb,var(--app-text-primary,#191919) 9%,transparent); }
.agent-thread-item:not(.is-current):focus-within { background:color-mix(in srgb,var(--app-text-primary,#191919) 4%,transparent); }
.agent-thread-list .agent-thread-select { padding-right:40px; border-radius:8px; background:transparent; }
+.agent-thread-list .agent-thread-item.is-running .agent-thread-select { padding-right:60px; }
.agent-thread-list .agent-thread-select:hover { background:transparent; }
.agent-thread-select > small > span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
-.agent-thread-running { position:absolute; right:12px; top:32px; display:grid; place-items:center; width:14px; height:14px; color:var(--ag-muted); font-size:11px; pointer-events:none; }
-.agent-thread-list .agent-thread-more { top:4px; right:5px; width:26px; height:26px; display:grid; place-items:center; border-radius:5px; opacity:0; transition:opacity .14s ease,background-color .14s ease; }
+/* 加载图标和菜单共用一行,随会话实际高度居中,避免各自定位产生偏移。 */
+.agent-thread-actions { position:absolute; inset:0 5px 0 auto; display:flex; align-items:center; gap:5px; pointer-events:none; }
+.agent-thread-running { display:grid; place-items:center; flex:none; width:14px; height:14px; color:var(--ag-muted); font-size:11px; }
+.agent-thread-list .agent-thread-more { position:static; flex:none; width:26px; height:26px; display:grid; place-items:center; border-radius:5px; opacity:0; pointer-events:auto; transition:opacity .14s ease,background-color .14s ease; }
.agent-thread-item:hover .agent-thread-more, .agent-thread-item:focus-within .agent-thread-more, .agent-thread-item.has-menu .agent-thread-more { opacity:1; }
.agent-thread-list .agent-thread-more:hover { background:color-mix(in srgb,var(--app-text-primary,#191919) 9%,transparent); }
@media (hover:none) { .agent-thread-list .agent-thread-more { opacity:1; } }
@media (prefers-reduced-motion:reduce) { .agent-thread-item, .agent-thread-list .agent-thread-more { transition:none; } }
+
+/* D01:预算、模型与主操作共享紧凑底栏,原生菜单支持键盘访问。 */
+.agent-input-box textarea { line-height:20px; }
+.agent-context-ring { position:relative; flex:0 0 20px; height:28px; display:flex; align-items:center; justify-content:center; color:var(--ag-muted); outline-offset:2px; border-radius:4px; }
+/* 三行居中浮层:圆环是定位锚点,宽度和横向避让由组件按输入区计算。 */
+.agent-budget-tooltip { position:absolute; bottom:calc(100% + 2px); z-index:20; display:flex; flex-direction:column; align-items:center; gap:2px; box-sizing:border-box; padding:9px 12px; border:1px solid var(--ag-border); border-radius:12px; background:var(--ag-bg); color:var(--ag-muted); text-align:center; white-space:normal; font-size:12px; font-weight:400; line-height:18px; box-shadow:0 2px 8px #00000006; cursor:default; }
+.agent-budget-heading,.agent-budget-usage,.agent-budget-amount { display:block; }
+.agent-budget-heading { color:var(--app-text-muted,#909090); }
+.agent-budget-estimate { margin-left:3px; font-size:10px; white-space:nowrap; }
+.agent-budget-amount { color:var(--app-text-primary,#25352d); font-variant-numeric:tabular-nums; overflow-wrap:anywhere; }
+/* 小箭头与透明过桥让鼠标能移入说明,不在圆环和浮层之间闪烁。 */
+.agent-budget-tooltip::before { content:""; position:absolute; left:0; right:0; top:100%; height:12px; }
+.agent-budget-tooltip::after { content:""; position:absolute; left:var(--agent-tooltip-arrow,50%); bottom:-5px; width:8px; height:8px; background:var(--ag-bg); border-right:1px solid var(--ag-border); border-bottom:1px solid var(--ag-border); transform:translateX(-50%) rotate(45deg); border-bottom-right-radius:2px; }
+.agent-model-controls { display:flex; align-items:center; gap:4px; min-width:0; flex:1; font-size:12px; line-height:18px; }
+.agent-model-menu { min-width:0; position:static; flex:1; }
+.agent-model-menu > summary { list-style:none; display:flex; align-items:center; gap:5px; cursor:pointer; height:28px; min-width:0; padding:0 3px; }
+.agent-model-menu > summary::-webkit-details-marker { display:none; }
+.agent-model-menu > summary span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
+.agent-model-menu > summary i { font-size:8px; }
+.agent-model-popover { position:absolute; bottom:calc(100% - 4px); left:16px; right:16px; z-index:25; max-height:min(420px,60vh); overflow:auto; padding:8px; border:1px solid var(--ag-border); border-radius:12px; background:var(--ag-bg); box-shadow:0 6px 24px #0002; }
+.agent-model-popover button { display:block; width:100%; text-align:left; padding:7px 8px; overflow-wrap:anywhere; border-radius:5px; }
+.agent-model-popover button:hover,.agent-model-popover button[aria-pressed=true] { background:var(--ag-soft); }
+.agent-model-popover section { border-top:1px solid var(--ag-border); padding-top:5px; margin-top:5px; }
+.agent-model-popover header { display:flex; align-items:center; justify-content:space-between; gap:8px; color:var(--ag-muted); padding-left:8px; }
+.agent-model-popover header button { width:auto; flex-shrink:0; font-size:11px; }
+.agent-model-popover p { font-size:11px; padding:5px; color:var(--ag-muted); }
+.agent-model-popover form { display:grid; grid-template-columns:1fr auto; gap:5px; padding:8px 0 0; border-top:1px solid var(--ag-border); }
+.agent-model-popover form select { grid-column:1/-1; }
+.agent-model-popover form input,.agent-model-popover form select,.agent-reasoning-select { min-width:0; max-width:100%; background:var(--ag-bg); color:inherit; border:1px solid var(--ag-border); border-radius:5px; padding:4px; font:inherit; }
+.agent-reasoning-select { max-width:70px; border:0; padding:2px; }
+.agent-thread-root .agent-conversation { padding:0; }
+.agent-thread-root .agent-message { max-width:100%; width:100%; }
+/* 回复填满消息行,避免展开运行详情时内容固有宽度改变上方步骤间距。 */
+.agent-thread-root .agent-message > .agent-reply { flex:1; min-width:0; }
+.agent-thread-root .agent-message-content { max-width:100%; }
+.agent-process-panel { max-width:none; }
+.agent-process-panel > :not(:last-child) { margin-block:0; }
+html[data-theme=dark] .agent-input-actions .agent-send { color:#fff; background:#111; box-shadow:0 0 0 1px #ffffff28; }
+
+/* 人物身份与消息出处分别展示,图片正文只保留引用入口。 */
+.agent-person,.agent-image-ref { display:inline-flex; vertical-align:baseline; align-items:center; gap:4px; border-radius:999px; padding:1px 6px 1px 2px; background:var(--ag-soft); color:inherit; font-size:12px; line-height:20px; max-width:100%; }
+.agent-person img,.agent-ref img { display:inline-block; width:18px; height:18px; object-fit:cover; border-radius:50%; }
+.agent-person span { overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
+.agent-ref { display:inline-flex; align-items:center; gap:3px; vertical-align:middle; }
+.agent-source-avatar { width:28px; height:28px; object-fit:cover; border-radius:50%; }
+.agent-avatar { position:relative; display:inline-grid; place-items:center; flex:none; width:28px; height:28px; overflow:hidden; border-radius:50%; background:var(--ag-soft); color:inherit; font-size:12px; }
+.agent-avatar img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
+.agent-source-sender { display:flex; align-items:center; gap:8px; }
+.agent-source-sender small { flex:1; min-width:0; }
+.agent-image-ref { padding:1px 7px; }
+.agent-image-viewer { margin:auto; width:min(1100px,calc(100vw - 24px)); height:min(850px,calc(100vh - 24px)); max-width:none; max-height:none; border:1px solid var(--app-border,#e7e7e7); border-radius:14px; padding:0; background:var(--app-surface-bg,#fff); color:var(--app-text-primary,#191919); overflow:hidden; }
+.agent-image-viewer[open] { display:flex; flex-direction:column; }
+.agent-image-viewer::backdrop { background:#141e2c99; }
+.agent-image-viewer header { display:flex; justify-content:space-between; align-items:center; gap:12px; padding:16px 20px; flex-shrink:0; border-bottom:1px solid var(--app-border,#e7e7e7); }
+.agent-image-heading { display:flex; align-items:center; gap:12px; min-width:0; }
+.agent-image-heading > i { padding:10px; border-radius:9px; background:var(--app-surface-soft,#f7f7f7); font-size:22px; }
+.agent-image-heading strong,.agent-image-heading small { display:block; overflow-wrap:anywhere; }
+.agent-image-heading small { margin-top:4px; font-size:12px; color:var(--app-text-muted,#909090); }
+.agent-image-viewer button { padding:5px 10px; border-radius:6px; cursor:pointer; background:transparent; color:inherit; border:0; }
+.agent-image-viewer button:hover { background:var(--app-list-hover,#eaeaea); }
+.agent-image-viewer button:disabled { opacity:.35; cursor:default; }
+.agent-image-viewer button:focus-visible { outline:2px solid var(--app-accent,#07c160); outline-offset:1px; }
+.agent-image-stage { position:relative; flex:1; min-height:0; display:flex; align-items:center; justify-content:center; overflow:hidden; touch-action:none; cursor:grab; background:var(--app-surface-muted,#f3f3f3); }
+.agent-image-hint { position:absolute; bottom:10px; font-size:12px; color:var(--app-text-muted,#909090); pointer-events:none; }
+.agent-image-stage img { max-width:90%; max-height:90%; object-fit:contain; user-select:none; }
+.agent-image-viewer footer { display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:10px; padding:14px 20px; text-align:center; flex-shrink:0; font-size:12px; border-top:1px solid var(--app-border,#e7e7e7); }
+.agent-image-viewer footer p { width:100%; margin:0; color:var(--danger-color,#fa5151); }
+.agent-image-viewer .agent-image-locate { color:var(--app-accent,#07c160); }
+.agent-image-toolbar button { border:1px solid var(--app-border,#e7e7e7); }
+.agent-image-toolbar { display:flex; flex-wrap:wrap; align-items:center; justify-content:center; gap:4px; }
+
+/* D01 参考稿将预算、模型与主按钮作为右侧整体对齐。 */
+.agent-context-ring { margin-left:auto; }
+.agent-model-controls { flex:0 1 auto; max-width:calc(100% - 60px); }
+.agent-input-actions .agent-send { margin-left:4px; }
+.agent-message-list > .agent-message > .agent-user,.agent-message-list > .agent-message > .agent-reply { margin-bottom:0; }
+.agent-message-list { gap:24px; padding:20px; }
diff --git a/frontend/assets/css/ai-settings.css b/frontend/assets/css/ai-settings.css
index be2d6230..8feb9d7f 100644
--- a/frontend/assets/css/ai-settings.css
+++ b/frontend/assets/css/ai-settings.css
@@ -42,10 +42,6 @@
.ai-settings .ais-tabs button { justify-content:flex-start; padding:9px; }
.ais-tab-copy strong { white-space:nowrap; }
}
-.ais-defaults { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; padding: 12px 14px; border: 1px solid var(--ais-border); border-radius: 8px; background: var(--ais-soft); }
-.ais-defaults label { gap: 5px; }
-.ais-defaults label > span { display: flex; gap: 6px; align-items: center; color: var(--ais-muted); font-size: 10px; }
-.ai-settings .ais-defaults select { height: 29px; border-color: transparent; background: transparent; padding-left: 0; font-weight: 550; }
.ais-profilebar { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin: 18px 0 10px; }
.ais-profiles { display: flex; flex-wrap: wrap; gap: 6px; min-width: 0; }
.ai-settings .ais-profiles button { background: var(--ais-soft); color: var(--ais-muted); border-color: transparent; max-width: 240px; font-size: 11px; }
@@ -133,7 +129,7 @@ html[data-theme="dark"] .ais-feedback.is-error { background: #422b2b; color: #ff
.ais-audit-toolbar { flex-wrap: wrap; }.ais-metrics > div { padding: 10px; }.ais-metrics strong { font-size: 21px; }
}
@container (max-width: 380px) {
- .ais-fields, .ais-defaults { grid-template-columns: 1fr; gap: 10px; }.ais-defaults { padding: 10px; }
+ .ais-fields { grid-template-columns: 1fr; gap: 10px; }
.ais-form-body, .ais-editor-heading, .ais-editor-footer { padding-left: 12px; padding-right: 12px; }
.ais-profilebar { align-items: flex-start; }.ais-audit-table { min-width: 430px; }
}
diff --git a/frontend/assets/css/tailwind.css b/frontend/assets/css/tailwind.css
index c34fb533..83536fb0 100644
--- a/frontend/assets/css/tailwind.css
+++ b/frontend/assets/css/tailwind.css
@@ -1,6 +1,8 @@
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
+@import "tailwindcss";
+@config "../../tailwind.config.js";
+
+/* Tailwind 4 显式保留旧版边框默认值,避免全站边框继承文字色。 */
+@layer base { *, ::before, ::after { border-color: var(--color-gray-200, currentColor); } }
/* 自定义全局样式 - 微信配色主题 */
@layer base {
@@ -2049,6 +2051,11 @@
color: var(--message-list-status);
}
+}
+
+/* Tailwind 4 保留原生层叠层:主题覆盖必须在 utilities 之后,
+ * 否则 bg-white、文字色等工具类会压过旧版的深色适配。 */
+@layer theme-overrides {
html[data-theme='dark'] .theme-scope {
color: var(--app-text-primary);
}
@@ -2107,7 +2114,7 @@
border-color: var(--app-border);
}
- html[data-theme='dark'] .theme-scope .divide-y > :not([hidden]) ~ :not([hidden]) {
+ html[data-theme='dark'] .theme-scope .divide-y > :not([hidden]) {
border-color: var(--app-border-soft);
}
diff --git a/frontend/components/AiSettings.vue b/frontend/components/AiSettings.vue
index 8ab40f59..a686d4f4 100644
--- a/frontend/components/AiSettings.vue
+++ b/frontend/components/AiSettings.vue
@@ -13,16 +13,11 @@
{{ tab.label }}{{ tab.hint }}
-
+
{{ error }}
{{ notice }}
-
-
-
-
-
已连接的服务
统一管理聊天总结与关注提醒使用的模型。
@@ -96,6 +91,10 @@
其他能力与参数
+
暂未获取到参考参数,使用上方手动配置。
@@ -145,7 +144,7 @@ import UiSelect from './UiSelect.vue'
import '~/assets/css/ai-settings.css'
const activeTab = ref('config')
const settingsTabs = [
- {id:'config',label:'模型服务',hint:'连接与默认模型',icon:'fa-plug'},
+ {id:'config',label:'模型服务',hint:'连接与模型配置',icon:'fa-plug'},
{id:'local',label:'本地检索',hint:'按意思查找聊天',icon:'fa-magnifying-glass'},
{id:'usage',label:'用量记录',hint:'调用明细与消耗',icon:'fa-chart-simple'},
]
@@ -162,10 +161,10 @@ const localSettingsTarget = useSettingsDialog().focusTarget || ref('')
watch(activeTab, () => { error.value = ''; notice.value = '' })
watch(localSettingsTarget, target => { if (target === 'local-search') activeTab.value = 'local' }, { immediate: true })
const formatNumber = (value) => Number(value || 0).toLocaleString('zh-CN')
-const profileOptions = vision => [{ value: '', label: '不设置默认模型' }, ...profiles.value.filter(p => !vision || p.vision).map(p => ({ value: p.id, label: p.name, description: p.model }))]
const protocolOptions = [{ value: 'openai', label: 'OpenAI 兼容' }, { value: 'anthropic', label: 'Claude Messages' }]
const providerPresentation = {
deepseek: { hint: 'DeepSeek 官方接口', aliases: '深度求索' },
+ xiaomi: { caption: '小米 MiMo 开放平台', hint: '小米官方 OpenAI 兼容接口', aliases: '小米 MiMo' },
claude: { hint: 'Claude Messages 接口', aliases: 'Anthropic' },
kimi: { hint: 'Moonshot 兼容接口', aliases: '月之暗面' },
openai: { hint: 'OpenAI 官方接口', aliases: 'ChatGPT GPT' },
@@ -243,7 +242,6 @@ const exportAudit = () => {
const link = document.createElement('a'); link.href = url; link.download = 'ai-usage-audit.json'; link.click()
setTimeout(() => URL.revokeObjectURL(url), 1000)
}
-const defaults = reactive({ text: '', vision: '' })
const blank = () => ({ provider: 'deepseek', name: 'DeepSeek', protocol: 'openai', base_url: 'https://api.deepseek.com/v1', model: '', vision: false, context_window: null, model_overrides: {} })
const form = reactive(blank())
// 切换预设后明确清空凭据,不让后端复用原配置的密钥。
@@ -271,6 +269,10 @@ const setOverride = (key, value) => {
if (value == null) { delete form.model_overrides[key]; selectModel() }
else form.model_overrides[key] = value
}
+const setReasoningEfforts = value => {
+ const levels = [...new Set(value.split(/[,,\s]+/).map(level => level.trim()).filter(Boolean))]
+ setOverride('reasoning_efforts', levels.length ? levels : null)
+}
const restoreAutomatic = async () => {
form.model_overrides = {}; form.context_window = null; form.vision = false
await fetchMetadata(); selectModel(false)
@@ -310,7 +312,7 @@ const action = async (fn) => {
}
const load = async () => {
const data = await api.request('/settings')
- profiles.value = data.profiles; presets.value = data.presets; Object.assign(defaults, data.defaults)
+ profiles.value = data.profiles; presets.value = data.presets
await loadAudit()
}
const reset = () => { invalidateModels(); editId.value = ''; key.value = ''; credentialsReset.value = false; manualModel.value = false; Object.assign(form, blank()) }
@@ -336,7 +338,6 @@ const save = () => action(async () => {
await load(); key.value = ''; dialogStep.value = ''; invalidateModels(); notice.value = '配置已保存'
nextTick(() => returnFocus?.isConnected && returnFocus.focus())
})
-const saveDefaults = () => action(async () => { await api.request('/defaults', { method: 'PUT', body: defaults }); notice.value = '默认模型已保存' })
const selectModel = (keepSaved = true) => {
const detail = selectedMetadata.value || modelDetails.value.find(x => x.id === form.model)
const saved = profiles.value.find(x => x.id === editId.value)
diff --git a/frontend/components/LocalSearchSettings.vue b/frontend/components/LocalSearchSettings.vue
index 64f1eb43..1885dd5c 100644
--- a/frontend/components/LocalSearchSettings.vue
+++ b/frontend/components/LocalSearchSettings.vue
@@ -2,7 +2,7 @@
@@ -12,17 +12,17 @@
{{ job.status==='done' ? completedTitle : stage(job) }}
用时 {{ elapsed(job) }}
- {{ job.status==='done' ? '本次检查' : '已读取' }} {{ job.read_count ?? job.processed ?? 0 }} 条消息 · 本次生成 {{ job.embedded_count ?? job.embedded ?? 0 }} 个片段 · {{ actualDevice }}
+ {{ job.status==='done' ? '本次检查' : '已读取' }} {{ job.read_count ?? job.processed ?? 0 }} 条消息 · {{ running ? '本次生成' : '本次已保存' }} {{ running ? (job.embedded_count ?? job.embedded ?? 0) : (job.embedded ?? 0) }} 个片段 · {{ actualDevice }}
当前索引:{{ indexStats.messages }} 条消息 · {{ indexStats.chunks }} 个片段
{{ indexMode(job.mode) }}
已复用 {{ job.unchanged }} 条未变化消息,无需重复生成片段。
内容没有变化,已复用现有搜索数据,无需重复生成片段。
- 已保存 {{ job.processed || 0 }} 条消息的进度 · {{ job.chat_index || 0 }} / {{ job.config?.usernames?.length || form.usernames.length }} 个聊天已完成
+ 已保存 {{ job.processed || 0 }} 条消息的进度 · {{ job.chat_index || 0 }} / {{ job.segments?.length || job.config?.usernames?.length || form.usernames.length }} 个{{ job.segments ? '会话时间段' : '聊天' }}已完成
当前每批最多 {{ job.read_batch_size_effective }} 条 · 根据可用内存调整
可以离开这个页面,整理会在后台继续。
在聊天搜索中切换到「智能搜索」,或直接向 AI 助手提问。
请调整聊天或时间范围;只有图片等尚未提取文字的内容无法生成搜索片段。
- {{ job.warning }}
{{ job.error }}
+ {{ job.warning }}
{{ job.error }}
@@ -37,7 +37,7 @@
- 更换模型后,所选聊天和时间范围内的全部内容都需要重新生成向量。新索引完成前仍可使用原有索引。
+ 更换模型后,{{ accountWide ? '全部聊天历史' : '所选聊天和时间范围内的全部内容' }}都需要重新生成向量。新索引完成前仍可使用原有索引。
{{ stage(displayModel.job) }} · {{ bytes(displayModel.job.bytes) }} / {{ bytes(displayModel.job.total) }} · {{ bytes(displayModel.job.speed) }}/s · {{ Math.max(0,Math.ceil(displayModel.job.next_retry-now)) }} 秒后重试
@@ -45,7 +45,12 @@
-
+
+ 2当前账号全部群聊和私聊
先整理近期,再补齐更早历史;新增消息持续更新。提问中的人物、群聊和时间条件只筛选本次查询。
+ 基础搜索始终可用,已保存的语义索引立即参与查询。暂停或重启会保留进度,聊天原始数据保持只读。
+ {{ globalCoverage }}
+
+
2选择要搜索的聊天
只整理选中的聊天,不会自动扩大范围。
{{ form.usernames.length ? '已选择 '+form.usernames.length+' 个聊天' : '还没有选择聊天' }}{{ selectedChatNames || '选择你经常需要查找的好友或群聊' }}
聊天时间时间范围越大,首次整理越久
@@ -53,7 +58,7 @@