Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
efae19e
perf(context-os): delay proactive compaction to 75% + align WARN at 8…
jsyqrt Aug 25, 2026
ef42eda
fix: three A2A/composer/store bugs
jsyqrt Aug 26, 2026
060a5c5
feat(models): per-agent default model + agent self-inspection tools + UI
jsyqrt Aug 26, 2026
aa27e0b
fix(web-ui): correct profilePage badge i18n key path, group ungrouped…
jsyqrt Aug 26, 2026
a5349b4
fix(a2a): recipient liveness reporting, wake_recipient, reply_in_sess…
jsyqrt Aug 26, 2026
f9c145a
fix(a2a): recipient liveness uses runtime state, not roster status
jsyqrt Aug 26, 2026
8035fc6
fix(prompt): Team Status reads live agent liveness at prompt tail
jsyqrt Aug 26, 2026
bf31130
fix(web-ui): stop 后重连流写进上一轮气泡导致聊天错序
jsyqrt Aug 26, 2026
d292717
fix(core): 并发版 spawn_subagents 进入默认工具集
jsyqrt Aug 26, 2026
05d6d62
fix(web-ui): 修正工具分组——不再漏进「其他」
jsyqrt Aug 26, 2026
549dc84
feat(browser): 内置浏览器开关——动态路由/配置持久化/设置页UI重构
jsyqrt Aug 27, 2026
a75dc85
fix: move per-turn dynamic context out of system to volatile tail (ca…
jsyqrt Aug 27, 2026
0d44e66
fix(web-ui): remove cache hit rate display from overview page
jsyqrt Aug 27, 2026
f34d2d3
fix(core): provider timeout/circuit hardening for single-provider fau…
jsyqrt Aug 27, 2026
05024fb
docs(ss-1): provider timeout & scheduler-blocking audit reports
jsyqrt Aug 27, 2026
78e2fa4
feat(ss-2): 前端流式/轮询死循环防护 + 断连自动重连
jsyqrt Aug 27, 2026
65a6618
feat(ss-3): 服务进程崩溃归因与自愈(崩溃日志/内存水位/启动看门狗自拉起)
jsyqrt Aug 27, 2026
cca2f48
fix(scheduler): 定时任务在 agent 离线时不投递 + 卡死 in_progress 自动回收
jsyqrt Aug 27, 2026
04c34ec
feat(obs): agent 列表派生运行 phase + 阻塞依赖标题(OB-1 后端)
jsyqrt Aug 27, 2026
43fae7b
feat(obs): 概览页将「思考中」展开为可读运行阶段(OB-1 前端)
jsyqrt Aug 27, 2026
5e83343
docs(obs): O 域反馈逐条标注闭环状态(OB-1 落地)
jsyqrt Aug 27, 2026
d7dad49
style(obs): AgentActivity 用显式 type import 替代内联 import()(修 eslint error)
jsyqrt Aug 27, 2026
f9eeca5
fix(obs): 契约一致性修正(评审)——①AgentRuntimeInfo.lastErrorAt 派生命中赋值;②phase=bl…
jsyqrt Aug 27, 2026
8eb8be9
feat(obs): 无任务「处理中」脏状态自动兜底(OB-3)——检测+周期兜底+可观测+前端提示
jsyqrt Aug 27, 2026
49a9fbb
feat(obs): 疑似卡死定位 agent-stall —— 心跳停滞/依赖已死明确提示非无限转圈(OB-2)
jsyqrt Aug 27, 2026
cb24ea3
Merge OB-3 into feat/context-os (via feat merge 结算)
jsyqrt Aug 27, 2026
d93720f
fix(deps+stream): failed-blocker 级联失败防死锁 + create/update blocker 校验 +…
jsyqrt Aug 28, 2026
5d209e7
fix(web-ui): GFM autolink 吞掉 URL 后跟随的中文/全角字符
jsyqrt Aug 28, 2026
c0f5b5e
fix(core): LLM 重试/退避参数可配置化(FD-2)—— config/env 覆盖,Python 默认
jsyqrt Aug 28, 2026
97ebd7c
docs: 反馈文档状态同步——#9/#11/#12/#13/#15/#26-28/#29 已闭环标记
jsyqrt Aug 28, 2026
05bb53a
fix(web): 任务操作与模型测试报错国际化+友好提示
jsyqrt Aug 28, 2026
7d49594
feat(web): 依赖图中未完成需求强制显示其所有任务
jsyqrt Aug 28, 2026
c51c8aa
feat(config): 临时隐藏编程工具集成(过度工程评估)
jsyqrt Aug 28, 2026
d1117ff
feat(core): Agent Office 生成工具 office_generate(docx/xlsx/pptx/pdf,T6)
jsyqrt Aug 29, 2026
5f7226d
feat(knowledge-base): T1 数据模型扩展 — knowledge_base_paths / source / kno…
jsyqrt Aug 29, 2026
5a0601d
docs: 知识库+Office 产出物调研规划文档(V2 架构) 纳入主仓库 docs/
jsyqrt Aug 29, 2026
22ff656
feat(knowledge-base): T2 后端知识库同步 + Office preview 扩展 + 搜索 source/content
jsyqrt Aug 29, 2026
b275d8f
test(core): extractTextFromFile 单测(文本直读 + markitdown 缺失降级空串)
jsyqrt Aug 29, 2026
3c493ce
feat(web): T3 前端知识库区块 + L1 编辑入口 + 产出物来源筛选
jsyqrt Aug 29, 2026
36881d8
feat(web): T5 统一 Office 预览组件(pdf/docx/xlsx 内联 + 回退)
jsyqrt Aug 29, 2026
f88c8f2
feat(core): T4 Agent 知识库工具(knowledge_search/read/list 封装 deliverable_*)
jsyqrt Aug 29, 2026
3fa7ca5
fix(agent): 深度分拣不处理正式任务 + 处理中状态可见化
jsyqrt Aug 29, 2026
98bdeeb
feat(knowledge-base): T7 联调整合 — 宿主级 e2e + 前缀校验 + 边界用例
jsyqrt Aug 29, 2026
7dd079a
docs(knowledge-base): T7 收口 — 规划文档追加阶段二完成状态与验证汇总
jsyqrt Aug 29, 2026
a6ef229
docs(knowledge-base): T7 交付总结与验收清单
jsyqrt Aug 29, 2026
3c724ef
fix(web): L1 项目编辑按钮未打开项目详情面板
jsyqrt Aug 29, 2026
236ae15
fix(core): DeepSeek 文本化工具调用泄漏修复
jsyqrt Aug 29, 2026
4586c64
fix(core): 加固流式工具标签泄漏防护 + PDF/office/deliverable 边界修复
jsyqrt Aug 29, 2026
74d7354
fix(mailbox): 严格状态项保护 + 丢失执行自愈,杜绝任务卡死 in_progress
jsyqrt Aug 30, 2026
5fb6e84
fix(web-ui): 绑定知识库目录后自动扫描同步,产出物页立即可见
jsyqrt Aug 30, 2026
7573064
fix: agent stall 误报修复 + 概览页移除 CU 指标
jsyqrt Aug 30, 2026
3c459c8
feat(desktop/web-ui): 知识库路径支持系统目录选择器(浏览…),告别手输绝对路径
jsyqrt Aug 30, 2026
e6e9b03
fix(web-ui): PDF 预览 polyfill ES2025 Map方法适配Electron35; 图片预览改用streamUrl
jsyqrt Aug 30, 2026
6dee137
fix(web-ui): 将 pdfjs Worker 打包进 Blob wrapper 注入 polyfill 以修复 Electron…
jsyqrt Aug 30, 2026
b5c0312
fix(web-ui): pdf预览崩溃-补Uint8Array.prototype.toHex polyfill
jsyqrt Aug 30, 2026
db558d1
fix(web-ui): Office预览容器从固定h-[55vh]改为自适应填充可用空间
jsyqrt Aug 30, 2026
8f016b7
fix(web-ui): 知识库绑定后同步全部路径(而非仅新路径),删除路径增加确认弹窗后重新同步
jsyqrt Aug 30, 2026
17d5b5b
fix(web-ui): 修复Office预览OfficePreviewer高度链传递, 滚动恢复正常
jsyqrt Aug 30, 2026
4305a9d
fix(web-ui): 终端点击路径前校验文件存在, 拼接错误/已删除路径不再打开预览
jsyqrt Aug 30, 2026
c249dd2
docs: 删除三份临时文档(0.9.8反馈分析/知识库Office规划/T7总结),对照表归档至交付物
jsyqrt Aug 31, 2026
7f4f6b9
fix(ui): 引导改为 per-user 状态,老用户不再被引导打扰
jsyqrt Aug 31, 2026
3c47bb4
fix(ui): 引导状态全面修复——新用户可见引导、老用户永久不被打扰(服务端持久化)
jsyqrt Aug 31, 2026
7570c26
docs: RELEASELOG v0.9.9-rc.0 entry
jsyqrt Aug 31, 2026
c31ea6c
Merge branch 'feat/ui-optimize-0827' into main (v0.9.9-rc.0)
jsyqrt Aug 31, 2026
893ad6b
fix(lint): release 前清零 7 处 eslint error(prefer-const/type-import/eqeqeq)
jsyqrt Aug 31, 2026
39db4ad
release v0.9.9-rc.0: 知识库+Office预览+onboarding全面修复+可观测性/稳定性加固
jsyqrt Aug 31, 2026
7d77d5a
fix(release): CI 修复——LLM provider test 500、office 无字体环境跳过、mac vite OOM
jsyqrt Aug 31, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,12 @@ permissions:
packages: write
id-token: write

# mac/linux runners default Node heap can OOM on web-ui `vite build`
# (observed on macos-latest: "Ineffective mark-compacts near heap limit").
# Raise the cap for all build jobs — harmless on CI, avoids SIGABRT.
env:
NODE_OPTIONS: '--max-old-space-size=8192'

jobs:
publish-npm:
runs-on: ubuntu-latest
Expand Down
46 changes: 46 additions & 0 deletions RELEASELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,51 @@
# Release Log

## v0.9.9-rc.0

### Features

- **知识库(Knowledge Base)** — 绑定本地目录自动扫描同步;搜索范围扩展 `source / knowledge_root / content`;产出物页数据来源筛选;Agent 新增 `knowledge_search / knowledge_read / knowledge_list` 工具(T1-T7 全链路落地)
- **Office 预览与生成** — 统一 Office 预览组件(pdf/docx/xlsx 内联 + 回退),修复 Electron 35 下 PDF 预览崩溃(pdfjs polyfill + Worker Blob wrapper);Agent 新增 `office_generate` 工具(docx/xlsx/pptx/pdf);知识库路径支持系统目录选择器(浏览…)
- **per-agent 默认模型** — 每个 agent 可单独配置默认模型 + agent 自检工具 + 设置页按 agent 分组管理
- **可观测性(OB-1/2/3)** — 概览页把「思考中」展开为可读运行阶段;agent 列表派生运行 phase + 阻塞依赖标题;疑似卡死定位(心跳停滞 / 依赖已死明确提示);无任务「处理中」脏状态自动兜底
- **稳定性加固(SS-1/2/3)** — provider 超时 / 熔断加固(单 provider 故障隔离);前端流式 / 轮询死循环防护 + 断连自动重连;服务进程崩溃归因与自愈(崩溃日志 / 内存水位 / 启动看门狗自拉起)
- **内置浏览器开关** — 动态路由 / 配置持久化 / 设置页 UI 重构
- **LLM 重试 / 退避参数可配置化**(FD-2)— config/env 覆盖,Python 默认
- **定时任务可靠性** — agent 离线时不投递 + 卡死 `in_progress` 自动回收
- **UI 优化** — 依赖图中未完成需求强制显示其所有任务;工具分组修复(不再漏进「其他」);任务操作 / 模型测试报错国际化 + 友好提示;概览页移除缓存命中率与 CU 指标;GFM autolink 吞掉 URL 后跟随的中文 / 全角字符修复

### Onboarding 全面修复

- 引导状态从浏览器 localStorage 升级为**服务端持久化**(`preferences.guideHidden`),三种登录方式全覆盖:Google / GitHub / Email(Hub 登录)、本地 init / 首登、会话恢复
- **新用户**:全屏向导 + 概览引导清单接力显示——向导完成后清单接棒,引导不再丢失
- **老用户**:登录 / 恢复会话即标记已引导,换浏览器、清缓存都不会再被打扰
- 全屏向导与引导清单解耦:向导中途退出 / 清缓存后,清单仍照常显示

### Bug Fixes

- A2A recipient liveness 使用运行时状态而非花名册;`wake_recipient` / `reply_in_session` 支持
- stop 后重连流写进上一轮气泡导致聊天错序
- `spawn_subagents` 并发版默认工具集
- DeepSeek 文本化工具调用泄漏 + 流式工具标签泄漏防护 + PDF/office/deliverable 边界修复
- failed-blocker 级联失败防死锁 + create/update blocker 校验 + google/ollama 流逐 chunk 重置超时
- 终端点击路径前校验文件存在,拼接错误 / 已删除路径不再打开预览
- 知识库绑定后同步全部路径(而非仅新路径);删除路径增加确认弹窗后重新同步
- mailbox 严格状态项保护 + 丢失执行自愈,杜绝任务卡死 `in_progress`
- profilePage 徽标 i18n key 路径修复;未分组 agent 在 per-agent 模型设置中优先归组

### Refactor / Docs

- 动态 context 移出 system 移至 volatile tail,提升 prompt-cache 命中率
- context-os 压缩阈值延迟至 75% / WARN 对齐 80%
- 临时隐藏编程工具集成(过度工程评估)
- 反馈对照表归档交付物,删除三份临时文档

### Stats

- 63 commits, 152 files changed

---

## v0.9.8

### Features & Improvements
Expand Down
90 changes: 90 additions & 0 deletions audit-reports/audit-frontend-stream-resilience.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# 前端流式/轮询死循环防护 + 断连自动重连 审计报告(SS-2, F 域)

> 仓库:markus-wt-billing | 分支:ss2-fe-stream | 日期:2026-08-27
> 依据:0.9.8 用户反馈分析中的 S 域问题 16/17/18(前端侧;原分析文档已从 docs/ 移除,完整对照表归档于 CTO 交付物「Markus 0.9.8 用户反馈—修复状态对照」)。
> 范围:严格限前端流式/轮询(F 域),未动后端 provider 熔断(SS-1 已处理)。

---

## 一、前端流式/轮询现状盘点

Markus 前端消费 agent 生成的方式是 **fetch + ReadableStream(SSE 风格 `data:` 行)**,不是 `EventSource`。两条消费链路:

### 1. 实时发送:`api.agents.messageStream`(packages/web-ui/src/api.ts)
- POST `/api/agents/{id}/message`(`stream:true`),拿 `res.body.getReader()` 逐块读,解析 `data:` 行。
- 事件:`text_delta` / `thinking_delta` / `tool_call_start` / `agent_tool` / `text_commit` / `thinking_commit` / `done` / `error` / `heartbeat`。
- **问题**:`while(true) { await reader.read() }` 没有空转兜底——若连接真死(半开 TCP / 服务进程退出 / provider 挂起让服务端不再吐数据),`reader.read()` 会永久 pending,界面停留在「思考中」,死循环不退出。

### 路径 2:刷新后重挂:`api.sessions.reattachStream`
- `GET /api/agents/{id}/sessions/{sid}/stream?afterSeq=…`,同样是 reader 循环。同样无空转兜底。

### 轮询(DB 兜底):Team.tsx `pollForReply`
- 当 SSE 断连且本地 agent 气泡为空时,轮询 `getMessages` 从 DB 恢复回复。**问题**:固定 3000ms 间隔 5 次,无退避/抖动——断连时所有客户端同时紧密重轮(雷群效应)。

### WS 事件源:`WSClient`(api.ts)— 已有防护 ✅
- 指数退避重连(base 1s → max 30s)、每 25s 心跳、`since` 增量恢复、`disconnect()` 主动关闭。**此项已达标**。

### 页签切回自动续流:Team.tsx `tryReattachActiveStream`
- `reattachCooldownRef` 1.5s 防抖防 attach storm;`userStoppedSessions` 防复活被停止的 turn;`streamStatus` + `reattachStream` 自动重挂。**连接自恢复已达标**。

---

## 二、关键前提:服务端 SSE 心跳

`packages/org-manager/src/sse-handler.ts` 生成消息流时用 `SSEBuffer`,`heartbeatInterval: 15000` —— **服务端对 agent 消息流每 15s 必发一次 `heartbeat`**(若连接还活着)。

推论:
- 「**长任务合法执行**」期间,服务端仍会持续发 heartbeat → 前端会持续拿到数据。
- 因此「**60s 完全收不到任何数据**」只可能发生在连接真正死亡时(半开 TCP / 服务进程退出 / 网络中断 / provider 挂死让服务端不再推流)。
- ⇒ 前端做一个「空转看门狗」是**安全**的,不会误杀长任务。

---

## 三、本次修复

### 1. 新增纯函数库 `packages/web-ui/src/lib/streamResilience.ts`
- `createStreamWatchdog({ signal, timeoutMs?, onStall? })` —— 空转看门狗:
- 每次读到 chunk(含 heartbeat)后 `bump()` 重置计时;`timeoutMs` 内无任何数据则触发 `onStall()`(仅一次)。
- `signal.aborted` 或 `stop()` 立即解除计时(用户停止/导航/流正常结束)。
- 默认 60s(> 服务端心跳 15s 的 4 倍余量)。
- `exponentialBackoffDelay(attempt, {baseMs,maxMs,maxAttempts,random?})` —— 全抖动指数退避:
- `delay = random(0, min(base*2^attempt, maxMs))`,attempt 封顶 `maxAttempts-1`;注入 `random` 便于测试。

### 2. 接入 `api.agents.messageStream`(真发送)
- `while(true)` 循环前创建 watchdog(有 signal 时);每轮 `reader.read()` 后 `bump()`。
- `onStall` → `reader.cancel()`:让卡死的 `read()` 抛错/结束,流优雅降级返回,把「永久思考中」抢救出来。
- `done`/`error`/`catch`/循环正常结束均 `watchdog.stop()` 清理。

### 3. 接入 `api.sessions.reattachStream`(刷新重挂)
- 同样加 watchdog + 全路径 `stop()`。

### 4. Team.tsx DB 兜底轮询改退避
- `pollForReply(5, 2000)` 改用 `exponentialBackoffDelay(i, {baseMs:2000, maxMs:8000, maxAttempts:5})`,指数退避+抖动+上限,避免紧密狂轮。

### 5. 连接自恢复(已有,确认达标)
- WS 重连退避、页签切回续挂、`streamStatus`+`reattachStream`、`since` 增量恢复 —— 服务重启/断连后自动恢复。

---

## 四、测试(`packages/web-ui/test/streamResilience.test.ts`,10 例全过;全 web-ui 182 例全过)
- `exponentialBackoffDelay`:首尝试 0..base 抖动(防雷轰)、指数增长但封顶 maxMs、maxAttempts 封顶、自定义 maxMs。
- `createStreamWatchdog`:超时触发一次、`bump()` 重置防误杀、`stop()` 解除、`signal` abort 解除、stall 后 bump 不复发。
- 默认超时 60s 为服务端心跳 15s 的整数倍多。

---

## 五、验收方向对照

| 验收 | 状态 |
|------|------|
| 流式失败后自动重连、不死循环 | ✅ messageStream/reattachStream 加空转看门狗(reader 不再永久 pending)+ `pollForReply` 退避 |
| 不永久「思考中」 | ✅ 空转看门狗触发 → reader.cancel → 优雅降级收敛;已有 `tryReattachActiveStream` 清「思考中」 |
| 断连自动恢复 | ✅ WS 指数退避重连 + 页签切回续挂 + `reattachStream` + `since` 增量 |
| 范围限 F 域 | ✅ 只改 `web-ui`(api.ts / Team.tsx / 新增 lib + test / 文档),未动后端 |

---

## 五、遗留(非本任务)
- google/ollama 流式 provider 仍是单一定时器(非逐 tick 重置)—— 后端域,见 SS-1 遗留。
- fallback 行为告警 —— 见 MD-3。
- 可视「卡在什么」—— 见 OB-1/OB-2。
Loading
Loading