56 KiB
56 KiB
实施进度
配合
DESIGN.md。本文件只记 phase 状态、决策偏差、文件量、下一步。每条 1-2 句:做了啥 + 关键判断;细节查git log/git diff/DESIGN §7.9。
最后更新:2026-06-07(前端模块化 Step 2:抽出 layout / auth / preview / files / media.js)
状态
| Phase | 标题 | 状态 | 备注 |
|---|---|---|---|
| 1-3 | 骨架 + Skill + run_python | ✅ | 多 skill(coding/proposal/ppt/research/documents/imagegen/videogen/review/patent);CoreCoder 唯一匹配 edit;敏感 env 过滤 |
| 4 | 演化性能力 | 🟡 | Model Profile + Probing ✅;版本化 prompt 未做 |
| 5 | Eval Suite | ⏸ 不做 | dogfooding 替代,probe 覆盖健康检查 |
| 6 | 长任务工程化 | 🟡 | task + 恢复 ✅;双层记忆 ✅;context 压缩未做 |
| 7 | 打磨 | ❌ | Docker 沙盒 / 更多 skill |
| §7 SaaS | DESIGN §7 路线 | 🟡 | A 事件流化 ✅;B 完工 ✅;D /v1 JSON API ✅;D' 过渡 auth + dev SPA ✅;单活 run 锁 + cancel ✅;0004 schema 瘦身 ✅;入口归位 ✅;真 OIDC 待;C Step 1-3 + 3d ✅(Executor + Docker 池 + DockerExecutor + fs 工具进容器)+ Step 5 部署前置对账 ✅ + 容器资源 yaml + 应用层磁盘配额(scan+gate)✅ + dogfood 网络放开 + 容器内 pip/npm 源持久化 ✅;Step 4 完整 egress proxy + Step 3b PGID kill 协议延后到外部用户开放前;外部用户开放仍需 egress proxy + xfs project quota OS 层硬化(§7.5 落地清单 #2 #4)。 |
已完成关键能力
2026-06-06
- 前端模块化 Step 2:抽出
media.js(工具活动标签 + artifact 抽取/渲染)+ 收敛 downloadFile 反向依赖:对话内toolActivityLabel(工具调用→中文活动名)、extractArtifactRels(从结果文本/working_dir 提产物路径)、extractMediaBanner(seedream/seedance 横幅)、renderArtifactBarHtml(产物 chip 条 + 图/视频内联占位)、upgradeMediaArtifacts(占位异步 fetch blob 填<img>/<video>带缓存)、downloadFile(blob 下载)→media.js(237 行,原 main.js 1134–1359)。收敛点:downloadFile 移入 media 后,preview.js/files.js对它的 import 从./main.js改指./media.js—— 把这条反向依赖从 main 挪开。media 导入极少(escapeHtml/_categorize(preview)/state/logout),与 preview 成 media↔preview 环(均运行时调用,安全)。两次险漏靠校验抓回:① 共享 constARTIFACT_PRODUCING_TOOLS(main renderMessages/SSE 用 4 处,.has()访问非函数调用,"被调标识符"法漏掉)② 内部函数_flushMediaArtifactCache(selectTask 切任务清缓存用)—— 残留符号检查发现后补 export。新增全模块 import/export 一致性校验脚本(每个import{X}必在目标export),11 模块全过。main.js 删至 1393 行。node --check11 模块全过、静态测试 2 过。 - 前端模块化 Step 2:抽出
files.js(文件面板 + 选入 + 拖拽上传):右栏文件列表浏览/导航/删除/重命名 + 刷新 + "选入"弹框(跨目录勾选复制/移动)+ 拖拽 overlay + 上传(XHR 带进度)+ 上传状态条。代码原分散在 main.js 两段非连续区(1133–1459 文件列表/选入/拖拽 + 1697–1786 上传 helper,中间夹着 media 段)→ 合并进files.js(433 行)。导出loadFiles/scheduleFilesRefresh(SSE 文件事件刷新)/closeSrcPicker(main Esc 关栈)/uploadFiles(聊天区粘贴/拖拽复用);其余入口模块顶层自绑。反向 importopenFilePreview(preview)、logout(auth)、main gluedownloadFile/selectTask/loadTaskList/loadFolderSuggestions(后三个加export,后续随 tasks/newtask 模块化再迁)。依赖分析用"段内被调标识符 − 段内定义 − 叶子/全局"全量提取,补回固定清单漏掉的loadFolderSuggestions/loadTaskList。main.js 删至 1619 行。node --check双过、main 残留 files 私有符号清零、files 无未导入 glue、静态测试 2 过。 - 前端模块化 Step 2:抽出
preview.js(文件预览 + mini 预览):文件预览主弹框(图/视频/PDF/文本/markdown/docx/xlsx,大文件降级下载,docx/xlsx 走loadScript懒加载 vendor)+ 同时再开的小窗预览(原 main.js 1687–2048)→preview.js(379 行)。导出openFilePreview/openPasteFilePreview/closeFilePreview/closeMiniPreview/_categorize(媒体段判图/视频用)。反向 importdownloadFile(main 媒体段,加export)、logout(auth)。Esc 关弹窗栈处理器留 main(跨模块协调 chpw/选入/文件预览/小预览,加了节注释)。一处去耦:deletePastedFile(留 main)原直接读 preview 私有_fpCurrentRel/_mpCurrentRel判断要不要关预览 → 改为 preview 导出封装closePreviewIfShowing(rel),行为不变但不泄漏内部 current-rel 状态(模块边界更干净;唯一非纯剪切的微调)。main.js 删至 2034 行。node --check双过、preview 私有符号在 main 清零、无未导入 glue 引用、静态测试 2 过。 - 前端模块化 Step 2:抽出
auth.js(首个 main↔模块 ES 环):登录(邮箱密码 / UUID+PLATFORM_KEY 两 tab)+ 管理员加用户 + 改密码三节(原 main.js 21–227)→auth.js(218 行)。各入口在模块顶层自绑 onclick,只导出logout(供全局 20 处 401 处理)/closeChpwModal(供 main 的 Esc 统一关弹窗栈)。反向 import main 的 glueenterApp/embedPostToParent/embedShowWaiting(main 给这三个加export)——首次引入 main↔auth 循环依赖:三者皆 hoisted 函数声明、模块实例化即就绪,且只在运行时(点击/401)调用,绝不在顶层求值时触发 → ES live binding 下安全;这是增量拆单体的标准形态,后续 features↔glue 环同理。main.js 删至 2397 行。node --check双过、auth 私有符号在 main 清零、静态测试仍 2 过。逻辑零改动。 - 前端模块化 Step 2(起):从 main.js 抽出
layout.js:三栏布局(pane 折叠 rail + 拖拽 splitter + 手机单列视图)是 main.js 里唯一对其他功能节零出边的干净段,用它打样增量剥离。layout.js(121 行):import$+ 4 个LS_*_COLLAPSED/WIDTH,只导出mqPhone/setMobileView(后者供 selectTask 在手机宽下选中任务自动切对话面板,是唯一跨模块调用);折叠/splitter/mobile-tab 的顶层事件绑定原样保留(ES module 默认 defer,import 时 DOM 已就绪)。main.js 删 114 行 → 2606 行,加 layout import 并清掉随之不再用的 4 个LS_*import。逻辑零改动,纯剪切+连线;node --check过、main 残留 layout 私有符号清零。顺手修 Step 1 遗留测试失败:test_static_vendor第二用例原只 grepdev.html找formatContextStats/context_original_chars/cache_hit_tokens,模块化后这些搬进js/*.js→ 改为扫dev.html + js/*.js合并源,2 测试全过。后续按干净度继续剥(下一个 auth = login+加用户+改密码,会引入 main↔auth 的 ES 环,靠 live binding 解)。 - 修 deepseek-v4-flash 大参数工具调用 arguments 损坏 → loop 畸形重试 + 非流式兜底:用户报"测试docx"任务里 zcbot 回
[Error] bad arguments to write: WriteTool.execute() missing 2 required positional arguments。实证定位(dump 失败 task 全量 messages):大参数(≈7–10K 字符)的 write/run_python 偶发把别处内容碎片错位粘进arguments开头(如].cells[1].merge(...{"path":...}),json.loads直接失败;有时退化成空{}→ execute 缺参报 TypeError。根因双层:① 上游 deepseek-v4-flash 流式 delta 偶发错位(隔离复现 16/16 全干净,说明概率低);② 真正放大成灾的是 loop 把损坏的 assistant 消息原样入库 + 每轮重发 → 模型学坏的投毒级联(失败 task 里大半 write 连锁失败)。读 litellmstream_chunk_builder源码排除"content 混进 args"(content 与 tool_args 两趟独立合并);批量验证非流式 8/8、流式 8/8 在干净上下文均不复现 → 确认是间歇上游抖动 + loop 零容错。修法(core/loop.py):_stream_llm重构成「拉一轮 →_malformed_tool_calls校验 tool_call arguments 能否json.loads→ 不能则丢弃整轮(不 append/不记账)重 roll」,最多 3 次;最后一次降级_nonstream_once(provider 服务端拼 tool_calls,绕开流式错位,content 整段补 emit)。断投毒环 + 不依赖猜准上游成因 + 不动正常路径。backstop:executor_host.py/sandbox/tool_runner.py缺必填参数(空{})早返缺少必填参数 [...];请带齐 [...] 重新调用,替掉暴露内部签名的missing N required positional arguments。重试消耗 token 不单独记账(罕见路径)。tests 全过(唯一失败test_static_vendor::formatContextStats是前端 ES module 化遗留,与本改无关)。
2026-06-05
- 前端模块化 Step 1:
dev.html单文件拆零构建 ES module(叶子优先):web/static/dev.html原 4087 行(纯原生 JS、手写state+ 手动 DOM、零内联onclick全addEventListener、唯一window.*是比较非赋值)。定方案「1 拆文件 → 2 后续引 Alpine/petite-vue 局部响应式 → 3 永不上 Vue+构建链」,本步只做 1。抽出 4 个无依赖叶子模块到web/static/js/:state.js(state单例 +LS_*+EMBED*)、format.js(escapeHtml/humanSize/fmtTokens/fmtCost/usage 系列等纯格式化)、dom.js($+ 浮层菜单 showMenu/hideMenu,import escapeHtml)、api.js(api()Bearer 封装,import state)、markdown.js(renderMd/highlightIn,依赖 vendor 全局)。剩余主体(login→boot,原 1387–4084)整体落main.js并 import 上述叶子;dev.html内联大<script>换成一行<script type="module" src="js/main.js">,降到 1121 行。逻辑零改动,纯剪切+连线。app.py加mimetypes.add_type("text/javascript", ".js")兜底(防 Windows 把.js判 text/plain 致 module 拒执行;本机实测.js→application/javascript 本就 OK,纯防御)。校验:6 模块node --check全过 + 无私有符号(_menuItems/_embedQS)泄漏到 main。后续步骤将从 main.js 把 login/tasks/stream/files/preview 等逐个剥成独立模块(tasks↔stream 循环依赖靠 ES live binding 解)。 - 改密码弹框样式修复:
#chpw-modal原先没专属 CSS,.card只继承公共骨架(背景+圆角+阴影),缺 padding/width/表单整形 → 卡片被撑到近全宽、无内边距很素。改为复用「选入文件」弹框(#src-picker-modal)的头/体/脚分隔布局:标题区底部分隔线、表单内容包进.body(内边距 16/18)、按钮区顶部分隔线右对齐,.card收到 400px + flex column,input focus 红框高亮。纯 CSS/HTML 结构调整,无对外行为变化(不动 DESIGN/RUN)。 - run_python 过程脚本约定
<task_dir>/scripts/:确认现状是模型生成的.py直接落 task_dir 根(系统提示只说"只写到 task_dir",无 scripts/ 分层),过程脚本和交付产物(.docx/.pptx/spec)混在一起。定调:模型显式写文件再script_path跑的过程脚本 →<task_dir>/scripts/(可见/持久/可重跑,WriteTool自动建父目录);inlinecode匿名片段 → 维持临时用后即焚(host 走系统 temp、docker 走.zcbot_tmp/<task_id>/dotfile 隐藏+删,均不动)——不持久化到 scripts/,免把目录污染成匿名垃圾堆。改core/agent_builder.py系统提示工作目录段加一条 scripts/ 引导(>~15 行/要迭代/出产物用文件,短抛弃代码才内联)+tools/run_python.py的 tool description /script_path参数说明同步。inline 执行逻辑两后端均未改。teststest_run_python_script_path/test_executor_docker全过(2 skip 为 Linux-only)。 - 新增
standardskill(国标/行标/团标起草):联网核实市面无可直接复用的"写标准文件本身"的 skill(搜到的 technical-proposal GB/T 8567、official-document GB/T 9704 都是相邻品类——投标书/公文,非标准),据 GB/T 1.1—2020 自建。覆盖三层级(国标 GB·T / 行标 JC·T / 团标 T/,重点对接 CSTM → T/CSTM,材料试验团标对口建材院检测方向)× 两体裁骨架(试验方法 GB/T 20001.4 + 产品标准)。文件:SKILL.md(阶段化:定层级体裁→八条 spec→逐章段段卡→自检渲染)+ 3 references(gbt_1_1_structure要素骨架/必备可选/规范性资料性/封面前言套话、standard_levels选型+CSTM 体系立项、drafting_rules能愿动词应宜可能/不可考核词过滤/指标量化闭环/术语规则/引用真实性+§8 自检清单)+ 4 templates(spec/test_method/product_standard/编制说明)。渲染复用 proposalrender_docx.py+render_diagrams.py(兄弟 skill../proposal/scripts/,同 patent 范式);冒烟测过表格/中文渲染正常。坑:proposalquality_check.py按申报书固定章节名查"缺章节",对标准全是误报且无跳过开关→阶段三不用机检,改 drafting_rules §8 人工 12 条清单(与 patent self_check 同思路)。产出是结构合规草稿 docx,正式报批再灌官方 TCS/CSTM 模板做版式精修。 - dev 页加"改密码"功能 + 文件面板"选入"按钮文字改图标(防换行):① 自助改密码——
web/auth.py::change_password(user_id, old, new)(验旧密码 → 新密码 ≥6 → bcrypt 重哈希写回,错误归一到现成UserCreateErrorcode 体系wrong_password/no_password/weak_password/user_not_found,不为此新开异常类),POST /v1/auth/change_password挂Depends(require_user)(user_id 取自 JWT 不信前端,旧密码错/无密码→403、弱→400、行没了→401)。前端顶栏「退出登录」左侧加「改密码」按钮(#hd-chpw,并入 embed 隐藏规则——embed 模式不显示)+ 一个复用.modal骨架的弹框(旧/新/确认三项,前端先验长度+两次一致再提交,成功alert提示不登出,401 走logout())。否决"点用户名展开菜单"(多写菜单逻辑不划算)。②#btn-src-pick的文字选入…改单字符图标⊕(和旁边⬆ ↻ ›同款单色字形,title保留"选入"语义)——原中文文字在窄面板偶发换行。 - 记账给 DeepSeek 前缀缓存命中折价(修虚高 ~2-3x)+ 前端体现缓存命中/真实成本:排查"rust 优势→PPT"那 task(flash,34 轮)发现
tokens_in累计 69.9 万里 88.6% 是缓存命中,但usage.py::_fallback_chat_cost_cny把命中段也按input全价(1.0)算 → 记 ¥0.84,真实(命中按 0.1x)只 ~¥0.28,越大的 task 虚高越多(文献采集 53% 命中:¥33→~¥16)。修:①ModelCapabilities加cache_hit_cny_per_mtoken(deepseek flash 0.1 / pro 0.2;0=不区分按全价兜底,绝不少记);② 成本公式拆三段「命中×缓存价 + (input−命中)×input价 + output×output价」,loop.py把cache_hit_tokens+ 缓存单价透传进record_chat_usage;③ 前端不加 DB 列——web/app.py加_usage_aggregates(单查询 GROUP BYusage_events,复用列表msg_counts同款批量范式,无 N+1)on-the-fly 算每 task 真实成本 + chat token + 缓存命中,_task_dict带出;列表行不内联花费、只显 tok 数,花费/缓存命中率藏 hover tooltip(taskUsageTooltip,多行:输入/输出拆分 · 命中 + 命中率 · ¥真实花费),顶栏额外内联简版。折价只对新 chat 事件生效,历史走 backfill 脚本(scripts/backfill_chat_cost_cache_discount.py,默认 dry-run,--apply落库;--assume-cache-hit-rate RATE给无cache_hit_tokens字段的老事件按估算命中率折价——DeepSeek 当时缓存了只是没记,全价偏高;实测过的事件用真实值不受影响)。坑修:命中率分母原误用tasks.tokens_prompt,但该列会被「清空对话」重置而usage_events不重置 → 跨源相除算出 822% 怪值;改为_task_dict的 token 总量也优先取 usage_events 聚合(与 cache_hit 同源,命中率恒 ≤100%)。注:真正压低 token 体量的杠杆是减少轮数(高成本 task 全是 100+ 轮的逐步 write/run_python 循环),非本次范围。
2026-06-04
- ppt skill 版式 helper 收进可 import 的模块 + 修中文字体没真生效:逐页生成是「每页一个 run_python」,以前 ~150 行 helper(配色常量/
add_textbox/apply_brand等)要在每页里默写一遍 —— 烧 token 且长 deck 里坐标会漂(第 7 页apply_brand跟第 2 页对不上)。抽出skills/ppt/scripts/pptx_helpers.py,每页import pptx_helpers as P调用;新增new_presentation/load(按文件实际尺寸回填画布常量,逐页进程间同步)/add_slide/set_palette(默认商务红,spec_path=自动取 spec 前 3 个 hex 作主/辅/强调)入口。字体修复:python-pptxfont.name只写<a:latin>,中文字形走<a:ea>槽位没设 → 「指定微软雅黑却没真生效」的根因;set_text改为同时写 latin=Arial + ea/cs=微软雅黑,中英混排各命中正确字体。改layouts.md(helper 块换成 import 起手 + API 速查,9 个示例全改P.调用)、icons.mdA5 示例、SKILL.md资源/阶段二。冒烟测试过:ea确写入、set_palette覆盖生效、quality_check 正常解析。 - ppt
quality_check.py加内容形状重叠检测:原有数值检查只覆盖越界 + 按字数估算的文本溢出,盲区是"两个都在画布内的形状互相重叠"(文本框压图标/压另一文本框)。加纯数值两两包围盒重叠检测——只检"内容形状"(有非空文字 / 是图片),装饰元素(无文字纯色填充:品牌条/分隔线/圆点/色块标签/装饰星箭头)天然排除,"文字叠在色块上"也不误报(色块无文字)。交叠宽高均 >0.08in 且 交叠面积/较小形状面积 ≥25% 才报,滤掉边缘贴合。测试过:合规 deck(L2 徽章+字 / L5 标签叠 chip / L4 圆点+bullet)零告警、两文本框故意叠触发并报百分比+形状名。零依赖、确定性、host+docker 都跑。 - ppt
quality_check.py配色检查纳入形状填充色 + 改按三色制判定:原来只数run.font.color(文字色),品牌条/徽章/圆点/标签/底块的填充色全漏——而这些恰是最易跑偏处。加_shape_fill_hex(取纯色实心填充,主题色/非实心挡掉)并入seen_colors。同时把粗阈值「≤5 色」改成贴合三色制的「非灰阶色 ≤3」:_is_neutral(R/G/B 极差 ≤12 视为灰/黑/白)把中性色排除——否则一旦计入填充,合规商务红 deck(INK/GREY/HAIRLINE/BG/WHITE+3 红)轻松超 6 狂报假阳;spec 比对也只比非灰阶色。测试过:合规红 deck 无配色 warning、塞 4+ 彩色触发、ACCENT 强调线填充被正确捕获。 - 前端顶栏展示用户已用存储:后端已有
user_disk_usage表(后台 15min 扫描落库),但无对外查询口。加GET /v1/user/storage(Depends(require_user)),返{bytes_used, file_count, limit_bytes, scanned_at},limit_bytes由parse_bytes(quotas.disk_bytes_per_user)得(≤0/None=不限)。disk_quota.get_user_usage扩为返(bytes,count,scanned_at)三元组(复用而非新开函数,顺手改唯一调用方check_disk_quota解包)。前端dev.html右侧「文件」面板底部钉一条进度条+文字指示器(#pane-right改 flex 列让#file-list独占滚动、存储条钉底;loadStorage()在enterApp拉一次;不限额时只显已用、隐进度条;超额变红;hover 显文件数+统计时间)。 - sandbox 容器 env 收编到一处 + shell 也注入(修两个只读 rootfs 副作用):①
PYTHONPATH=/sandbox:/workspace原先只run_python注入,shell 里python -c "from skills..."撞 ModuleNotFoundError;②--read-onlyrootfs 下/home/zcbot不可写,matplotlib/fontconfig 往~/.config/~/.cache写缓存刷 "Read-only file system" / "No writable cache" 噪音。改:executor_docker.py抽_CONTAINER_ENV = {PYTHONPATH, HOME=/tmp},shell/run_python/fs 三路共用(-e确定性覆盖)——HOME=/tmp一刀让缓存落 tmpfs(matplotlib→/tmp/.config、fontconfig→/tmp/.cache),不用逐个 MPLCONFIGDIR/XDG_CACHE_HOME。纯代码改,重启 web 生效,免重建镜像。
2026-06-03
- 修 docker sandbox 下 system prompt 焊死宿主路径(agent 找不到自己的文件):
ZCBOT_SANDBOX_BACKEND=docker时 shell/run_python/fs 工具全在容器里跑(<workspace>/users/<uid>bind 到/workspace),但_build_system_prompt注入的task_dir/ cwd 是宿主绝对路径(容器内不存在),LLM 据此find /home/ubuntu/zcbot ...全空、瞎转到pwd才发现真身在/workspace/<wd>。修法同LoadSkillTool的container_skills_dir改写:docker 下task_dir+ 「宪法」glob 范例换成容器路径/workspace/<wd_rel>,并去掉 docker 下无意义的 cwd 行(容器 cwd 恒等 task_dir);host 不变。 - 顺扫清掉 SKILL.md 里残留的宿主路径假设(同 docker 隐患):
patent跨 skill 调 proposal 脚本原用<repo_root>/skills/proposal/...(还举例硬编码D:/projects/zcbot)→ 改兄弟 skill 相对<skill_dir>/../proposal/scripts/...(两后端都对);research的fetch_pdf范例硬编码working_dir=r"D:/..."→ 改<task_dir>占位;patent/proposal/ppt的<task_dir>举例用废弃旧布局…/workspace/tasks/<task_id>/→ 改 host/docker 双形态说明。 - 修 ppt 图标缓存写进只读挂载(docker 拉新图标失败):
fetch_icon.py -o <skill_dir>/assets/icons/在 docker 下 skills 是:robind,写回必败;host 下还顺带污染仓库工作树。改为(方案 A,与"产物只写 task_dir"的全局规矩一致):种子图标库<skill_dir>/assets/icons/降为只读(glob 读),fetch_icon.py新拉的图标一律-o <task_dir>/assets/icons/;读路径改两处都 glob(种子库 + 本 task)。涉ppt/SKILL.md、references/icons.md、assets/icons/INDEX.md;脚本本身已out.parent.mkdir,无需改。 - 默认镜像源改清华(pip+apt)/ 腾讯(npm):腾讯 PyPI 吐损坏 litellm wheel(index 声明 sha256 与文件实际字节不符,非篡改 = 镜像端文件损坏)。
deploy/update.sh三默认值改清华(境内稳 + 同步及时;npm 无清华源走腾讯);换默认让下次 build pip 层全量重跑一次。 - 回退
ZCBOT_WORKSPACE_DIRenv 覆盖,workspace 落数据盘改用 bind mount:env 覆盖与core/paths.py锚 ROOT 的相对存储冲突 —— env 指向 ROOT 外致文件面板 / agent resume / 新建 task 三家分叉。resolve_workspace回退成arg > cfg > 默(均 ROOT 内),数据盘改用 bind mount(/data/zcbot/workspace→ROOT/workspace,DB 不改、dev 不受影响)。
2026-06-02
- 【已于 06-03 回退,见上】
resolve_workspace加 env 覆盖ZCBOT_WORKSPACE_DIR:prod 想把 workspace 落独立数据盘且不碰共用 yaml,改优先级arg > env > cfg > 默。回退因与相对存储锚点冲突(见上)。 - 修 embed 模式"登录页一闪而过"(绘制时机,非鉴权):
#login在embedInit标记embed-mode前已被绘制;在<body>首行加同步内联脚本,?embed=1时立即加embed-modeclass,赶在#login绘制前隐藏。只挪绘制闸门,底部握手逻辑不动。
2026-06-01
deploy/update.sh加自更新重跑守卫:git pull会改脚本自身,首次拉到"改 update.sh"那轮跑的还是旧脚本行为。pull 后 diff 检出本脚本变更则exec用新版本从头重跑(标记防死循环),修"改了源仍报旧错"根因。deploy/update.sh默认源改腾讯 + build 跳过改--skip-build+ 进度可见:根因 = 阿里 PyPI 同步滞后缺litellm>=1.83。默认镜像源改腾讯(host venv pip 显式拼--index-url)、跳过 sandbox build 由 env 改 CLI flag、pip 去-q让进度可见。- 修 MP host 工具的全量下载(IP 被封根因):
mp_search_summary没传分页 → mp-api 默认翻完所有页 = 每搜一次整库级下载,MP 判 abusive 封 host IP。改num_chunks=1, chunk_size=limit服务端限量;mp_get_entries天然全量(相图用途)只在 description 警示。注:宿主 IP 仍被 MP 临时封,需邮件 support 人工解封后才能联网复测。 - 加一键部署脚本
deploy/update.sh(Ubuntu / systemd):git pull → pip install → db upgrade → docker build sandbox → restart → curl /healthz。两处钉死:migration 从 .env 抠ZCBOT_DB_URL喂 alembic;build 必须在 restart 之前(容器复用,restart 才换新镜像)。前置守卫:非 root / 非 git / 工作区脏 / 缺 .env 中止。 - sandbox 镜像加中文字体,修 matplotlib / mermaid 出图中文方块:根因 =
deploy/sandbox/Dockerfile从 slim 起一个 CJK 字体都没装。加fonts-noto-cjk fonts-wqy-microhei+style.py候选首位加 Noto。改 Dockerfile 须重 build + 清旧容器才生效。 - documents / Materials Project 带 key 能力改 host-side tools,key 不进 sandbox:新增
tools/documents.py+tools/materials_project.py各三工具,仅宿主 env 有 key 时注册;写文件绑定 task_dir,模型不能传 working_dir。 - 删
skills/pymatgen/materials.py::mp_rester():sandbox 内读 key 的旧入口,host tool 化后多余且违背"key 不进 sandbox",直接删;smoke 改走 host tool。换 next-gen MP key 后端到端复测通过。
2026-05-29
- Seedream 5.0 i2i base64 通路 probe + DESIGN §8.1 落册:实测豆包 Seedream 5.0
/images/generations接受image_urlsbase64 data URL → 内网部署无需对象存储中介。选 E+C 组合(seedream加reference_images+ 新增look_at_image豆包 vision tool),本版仅 probe + design,tool 改造未启动。 - web 端 tool_call 标题行改显中文活动描述:实时流分支读错字段(
argumentsvs 后端 emit 的args)致<pre>一直空。修字段 + 新增toolActivityLabel(name,args)按 12 工具套中文动词(读取文件 / 执行命令 / 运行 Python / 联网搜索…)。纯前端,刷新即生效。
2026-05-28
skills/review/SKILL.md加"长文档处理"段:阶段 1 骨架扫描(只出目录 + 全局问题,不出修改稿,停下等用户挑章节)→ 阶段 2 分章深审 + 中间文件落盘。解长稿一轮处理易略读 / 覆盖不全 / 超输出限制。- 新增
config/models/local.yaml(family=local,variant r1 / qwen3)接内网 OpenAI 兼容推理服务,涉密任务专用:model_id加openai/前缀走兼容协议,api_base指内网。关键thinking_mode=false(R1 / Qwen3 天生推理,发reasoning_effort本地 vLLM 多半 400)。不改默认模型,涉密显式选;qwen3 跑通,r1 服务端调试中 500。 - 修
LoadSkillTool在 docker backend 返 host 绝对路径致容器内 fs 工具找不到 references:skills/ bind mount 到容器/sandbox/skills,容器内无 host 路径。加container_skills_dir参数,docker backend 时返/sandbox/skills/<name>。所有 references-heavy skill 自动 work,不用逐个改 SKILL.md。 - 新增
analyzeskill(科学问题分析 / 拆解 / 引导):服务建材院 R&D 早期模糊问题翻译。四段式:PICO 规范化 → Issue Tree 拆解 → 按叶子类型分支(Fishbone / First-principles+TRIZ / DoE)→ 实施路线图。定位协调器不执行任务,接力下游 skill;不硬编"能力 → skill"映射(靠 runtime skill discovery 自匹配)。 - Python 3.10→3.12 升级(host + Dockerfile)+ DockerExecutor PYTHONPATH 修:mp-api 依赖链
from typing import NotRequired(3.11+)在 3.10 import 不进;选 3.12(ML 生态默认 + wheel 覆盖全)。顺手修executor_dockerPYTHONPATH/workspace→/sandbox:/workspace(docker backend 下import skills.xxx找不到的历史 bug)。3 科学 skill smoke A/B/C 通过,D 因 MP 封 IP 返 403。 - 新增 3 个科学计算 skill(pymatgen / stats_ml / plot_pub):服务无机非金属材料 R&D。pymatgen 带
CEMENT_PHASES中英文相名映射 50+;stats_ml 纯指南(sklearn / statsmodels / PyMC 场景导航,无 helper);plot_pub 带apply_pub_style()出版级中文字体跨平台 fallback。挑 4 个 ★★★ fork 单装,不一键装 138 个。 - DESIGN §7.5 增"image 体积 / 多 user 资源 / 后续加包策略"决策段:① image 大 ≠ 吃更多 RAM(layer 共享);② 多 user 瓶颈在并发 exec 不在 idle 容器数;③ 新增依赖走"base 收敛 + per-user 持久化 venv + 使用频次沉淀"。
2026-05-27
- ppt skill 歧义反问 + general_v1 加"产物形式歧义先问"通用原则:"汇报方案"仍被路由命中(LLM 把"汇报"联想成 PPT)。把"汇报 / 方案 / 材料"从反例摘出,改成先反问用户"PPT 还是文档",并把原则升格到 system prompt 让新 skill 继承。
- ppt skill description 收紧路由:原文含"方案 / 生成"被误命中,改显式白名单(PPT / 幻灯片 / .pptx / slide / deck)+ 显式反例(报告 / 文档 / 纪要不触发)。
- skill 热更新:
/v1/skills每次现扫:原 lifespan 启动扫一次的静态快照 → 加新 skill 须重启。改每次现扫(构造 ~3ms,非热路径);build_agent早已每次重建 registry,本次仅补前端下拉这一处。 - dev SPA "导出对话记录" / "清空对话"按钮改成只要选中 task 就常亮:原按
n_messages===0禁用,清空后前端计数不刷致两键一直灰。改导出常亮、清空仅在 run 进行时禁;0 条时点也不会出错。 - 修 dev SPA embed + task_id 模式模型下拉不显示:embed 带 task_id 时
selectTask早于loadModelsresolve,renderModelDropdown空 models 直接返空。loadModels尾部加一行:若已有 task 选中则补一次 chat-meta 重渲。 - Stage C 收尾包:容器资源 yaml 化 + 应用层磁盘配额 + dogfood 网络放开 + 容器内 pip/npm 源持久化:①
agent.yamlsandbox 段(memory/cpus/pids,env>yaml>默);② migration 0008 +core/storage/disk_quota.py周期扫描 + write/upload gate(race-tolerant);③ 去--internal(dogfood 能 pip install)+/etc/pip.conf/etc/npmrc让运行时也走 mirror。iptables 红线不动。Step 4 完整 egress proxy 延后到外部开放前(沉淀为升级触发信号)。 - Stage C Step 3d:fs 工具(read/write/edit/glob/grep)进容器 + DESIGN §7.5 #6 重写:dogfood 发现 host 工具 base_dir=
Path.cwd()漏底(模型 glob 列出 zcbot 源码),且原 DESIGN 写的resolve_user_path是假命题根本没那函数。选"物理边界替代代码护栏"走 docker exec,tool_runner.py从 stdin 接 JSON args(CJK 路径透明传)。留 host:load_skill / web_* / seedream / seedance(持 key 或跨 user)。 - Stage C Step 3 hotfix:exec_user 改 username + Dockerfile 加 Node/Chromium/mermaid-cli:① 写死
--user 1000:1000与 bind mount owner(host uid 1001)错配致 EACCES,改 usernamezcbot让 docker 查 passwd;② proposal/patent 渲 mermaid 缺 Node 退公网 API 又被--internal堵,Dockerfile 加 chromium/nodejs/npm + mermaid-cli + puppeteer--no-sandboxconfig。 - Stage C Step 5:
main.py sandbox check部署前置对账 + lifespan fs quota WARN:5 项探测(docker daemon / 镜像 / network / 镜像内 uid 与 host 对齐 / workspace fs 可 quota)。err = 启动会 fail-fast 的根因(daemon/镜像/uid,exit 1);warn = 外部开放前要清(network 缺 / fs 不可 quota,exit 0)。detect_fs_quota抽出给 lifespan 复用。 - Stage C Step 3:DockerExecutor 集成 AgentLoop + web lifespan(
ZCBOT_SANDBOX_BACKEND=host|dockerenv 切):shell / run_python 走docker exec,其他工具直通 host;run_python tmp .py 落<user_root>/.zcbot_tmp/dotfile(/v1/files天然过滤)。cancel 杀 docker CLI 不杀容器内进程,靠 idle reaper 兜底。pool.pyasyncio.Lock→threading.Lock。Windows dogfood 默 host 零变化。 - Stage C Step 2:Docker per-user 容器 + iptables blocklist(§7.5 #1 + #3 基底,未接入 AgentLoop):
deploy/sandbox/{Dockerfile,init.sh}(non-root + 任一 iptables 失败 fail-fast + 6 段红线 DROP)+core/sandbox/{network,pool}.py(--internal网络 + per-user 容器 ensure/reap/shutdown + hardening flags--read-only --cap-drop=ALL --memory=2g等)。docker CLI via subprocess 非 SDK;last_active 落内存 dict(Docker 23+ 移除 runtime label 改)。 - Stage C Step 1:Executor 接口骨架 + HostExecutor in-process backend(§7.5 #5):
core/executor.pyExecutorABC +ExecCtx+ToolResult,AgentLoop改接 executor 而非 tools dict。接口刻意 backend 无关(不泄漏 docker 假设),Step 3 切 docker 时 AgentLoop 零改动。 - REVISIONS.md 修订日志机制(覆盖 proposal/patent/ppt 三个产物型 skill):
<task_dir>/REVISIONS.md紧凑 changelog —— spec=宪法(定调一次),REVISIONS=实施日志(每次卡点累加)。三 skill 各加"用户确认实质改动后追加一行" + 独立小节;单行 bullet 倒序追加,首次起草 / 错别字微调 / 模型自撤不记。 - 新增 patent skill(中国发明专利技术交底书):
skills/patent/6 文件,五阶段 workflow(摄取 → 挖点 → 检索 → spec → 逐章起草 → 自查渲染,同 proposal BLOCKING 节奏)。复用 markitdown / proposal 的 render_diagrams+render_docx / web_search+documents+research,不造 CNIPA 爬虫,源 repo 8 Python tools 减到 0。 - §7.5 沙盒落地清单 6 条写入 DESIGN(Stage C 实施硬协议):网络 blocklist 硬编码(含 PG IP 单独再 block)/ egress proxy 模型 / 进程组清理(setsid + PGID kill)/ 磁盘配额硬化时点 / Executor backend driver / 工具按信任域二分 dispatch;并写死 gVisor / Firecracker / 容器内 tool-runner 三档升级触发信号,反向兜底"无信号不升级"。
2026-05-25
- dev SPA 前端依赖 CDN 本地化 + 升级稳定版:markdown 渲染(
marked@16.2.1/dompurify@3.2.6/highlight.js@11.11.1)从 jsDelivr 改本地vendor/,避免内网 / 跨境 CDN 抖动致渲染 / sanitizer 不可用;tests/test_static_vendor.py回归检查 HTML 无cdn.jsdelivr.net+ vendor 文件存在。 - dev SPA 一批上传 / 布局交互打磨(同质合并):三类上传入口(粘贴 / 按钮 / 拖拽)改
XMLHttpRequest显进度 + 粘贴上传 chip 可预览(#mini-preview-modal不覆盖主预览)可删除;三栏支持右栏折叠 + 左右分隔线拖拽调宽(localStorage 持久化);右侧文件长名 hover 显全路径;左栏滚动条只覆盖 task 列表(IntersectionObserver root 移到#task-scroll)。 - 接入博查 Web Search + Web Fetch 两个 tool:
tools/web_search.py(Bocha POST/v1/web-search,Bearer)+tools/web_fetch.py(httpx + html2text,SSRF 内网屏蔽,截断 8000);web_fetch 无条件挂,web_search 仅 env 有BOCHA_API_KEY时挂。
2026-05-22
- dev SPA 加 iframe embed 模式(
?embed=1&parent_origin=...):父页 postMessage 握手拿 JWT(zcbot-ready→ 父端用PLATFORM_KEY换 token →zcbot-token推回),event.origin白名单双向校验,PLATFORM_KEY不下发浏览器;藏 brand / 顶栏 / 退出。401 发zcbot-401等父端重换 token。web/EMBED.md对接手册。 - embed 模式接受
task_idURL 参数定位 task:首次签发 token 后selectTask,once标记只生效一次(401 重签不重置用户中途切的 task);task_id 错或不属于当前 user 走原 401/404 分支。 - 媒体生成每账号每日配额(yaml 可配,默 20 图 / 5 视频):
quotas段 +check_daily_quota按服务器本地今日 00:00 计;tool 超额返中文提示不调远端不烧钱。跨 task 跨 variant 账号级合计,失败不计,软上限不加事务锁。tool 返串只暴露已用 / 上限 + 重置时间,不贴 yaml 路径(防 LLM 复述泄漏内部 schema)。 - 对外路径协议刚性化(system 强约束 + SKILL 简化 + UI 一次性兼容):
general_v1.md规定助手 echo 产物路径用 user_root 相对全形式<wd_name>/<rel>(简写致 Web UI chip 失效),跨所有产物 skill 统一;imagegen/videogen SKILL 改"照抄 saved 行";dev.html::extractArtifactRels一次性兼容历史简写。术语用<wd_name>(working_dir 末段)而非<task_name>(允许两者不等)。 - 豆包 Seedance 2.0 Fast 视频生成接入(文生视频)+ videogen skill:
config/media/doubao.yamlvideo 段 +tools/seedance.py(ark 建任务 → 5s 轮询 → download mp4,失败 / cancel 不计费);build_agent加video_variant+cancel_check(build 阶段传,轮询期响应停止);web/app.py+dev.html第三下拉。skill 六维诊断把"光线"换成"运动 + 镜头",BLOCKING 门槛更严(¥4 vs ¥0.22)。phase 1 仅 t2v,fast 上限 720p。 - dev SPA 移动端自适应 + 交互打磨(同质合并):手机两档断点(平板 rail / 手机单列 +
.mobile-tabs切 pane,100vh→100dvh解 iOS、输入 ≥16px 防 focus 缩放)+ 顶栏 / chat-meta 紧凑化;"+ 新建任务"按钮从 header 挪到任务面板通栏;chat-input 支持 Ctrl+V 粘贴文件上传;文件预览弹框让出 chat-form 高度(打开期输入区仍可点可打字)。
2026-05-21
- dev SPA UI 打磨(同质合并):修 primary 按钮 hover 文字消失(
.primary:hover补background:var(--accent),原 fallback 到浅灰 + 白字消失);CSS 精简 + 圆角降档 + 4 个 modal 抽.modal基类(style 块 589→522 行,功能 0 改);新建任务弹窗 / 顶部 filter 工作目录回原生<select>+ sentinel+ 新建「<name>」+ 二级 input(combobox 方案试过又推翻 —— 原生 select 更稳)。 - sandbox 阻塞地位写进 DESIGN(§7.7 hard prereq / §7.8 风险行 / §7.9 取舍):
tools/shell.py::BLOCKED_PATTERNS是 trivial-bypass 装饰品(命令注入图灵完备,黑名单 fundamentally broken),不继续加规则。正确防线在 OS 层 §7.5(docker exec + drop ALL caps + read-only + egress allowlist)。本地 dogfood blast radius 限自身;SaaS 外部开放才是 hard prereq。 - system prompt 注入 task 预选 skill 提示:
_build_system_prompt加task_skill参数,非空时加一行事实,与 general_v1 已有"对应 skill 先 load"规则组合 → 主动 load。否决"完整 SKILL.md 预注入"(把 skill 从 metadata 升格成 binding,投产比不划算)。 - imagegen skill 加 ⛔ 调 tool 前必须贴 prompt + BLOCKING 等确认硬约束:清楚的描述也可能模型与用户脑里对不上,事后看图才发现白烧 ¥0.22 —— 把"模型脑内装配"摊到对话层让用户最后过一眼(装配 ≠ 授权调用)。诊断五维 → 六维加"比例 / 尺寸";
general_v1改"调 seedream 前必须先load_skill('imagegen')",description 扩 17 触发词。 - 新增 imagegen skill(引导用户说清楚生图需求):单文件五步法(诊断模糊度 → 给推断 + 待确认 → 用户拍板 → 装配 prompt → 调 seedream),防一句"画个 XX"直接烧 ¥0.22;mermaid vs seedream 选型三段式。
- 登录页加"+ 管理员添加用户"入口 + 删 chat meta 条/tok 显示:
web/auth.py::create_user(CLI / web 共用)+POST /v1/auth/admin/create_user校验ZCBOT_ADMIN_TOKEN共享口令。否决 User 表加is_admin列 + 管理员 JWT(开发期成本不划算)。 - 新增 documents skill(内部材料学科知识库 document_search API):
skills/documents/{SKILL.md, client.py}四函数,Bearer 认证;search 返整篇 Markdown(50K-200K 字符),反模式约束只 print 前 300 字防爆上下文。库实为 7 材料学科英文学术论文 21W+ 文件 + 跨语言语义检索(原写"主语料中文"是错的);与 research(OpenAlex)互补。 - dev SPA SSE 客户端重连(覆盖 --reload 抖动):
fetchSse拆 consume + 重连壳(1/2/4s 退避 ×3);后端stream_events入口检 run_status,非 running 立即吐 done 关流(防进程重启后无限挂 ping)。断开期 LLM delta 丢失,接受。 - research skill fetch_pdf 改走静态直链:从
paper["pdf_url"]流式下载,绕开 paper_pdf_view 路径 bug(disk 路径计算错);smoke 5/5。 - research skill list 端点加 pdf_url / xml_url 直链 + 新增 fetch_xml + pg_trgm GIN 索引:后端拼直链(避免 stale URL),GIN 把
?search从 30s timeout 降到几十 ms;SKILL.md 加"XML 优先 PDF"(已结构化免 OCR)。 - 顶栏 token 累计修(
sync_task_tokens改走 messages SUM):切 streaming 后内存计数器永不更新,删 TokenCounter 类改SELECT SUM(...) FROM messages现算,backfill 4 task。 - 同 wd 并发软警告 banner +
/v1/tasks加run_status筛选:Claude Code 同款"信任 + 软警告",selectTask+ SSE 收尾拉同 wd running task 黄底提示。否决硬挡 / short_id 全产物隔离 / clone task 三方案(DESIGN §7.9)。 - paper_server → research skill:范式判断走 skill(非 tool / MCP / 裸 httpx),
skills/research/{SKILL.md, paper.py}三函数;run_python注入PYTHONPATH=base_dir;paper_server 补 retrieve 端点 + serializer 加 abstract。
2026-05-20
- dev SPA artifact chip 演进(同质合并):对话内 tool_call/result 挂产物 chip,
extractArtifactRels正则锚<wd>/...+ 末段需含.;门控多次校准后落到产物工具白名单ARTIFACT_PRODUCING_TOOLS={seedream,seedance}(通用工具 echo 路径不误挂),assistant 正文不门控走seenRels去重 +allowInlineMedia防同图二次 inline;.art-chip点击委托openFilePreview。 - CLAUDE.md 加"实施前先对方案"段:非平凡改动动手前先口头对方案。
- loop.py tool message 补
name字段 + backfill 历史:OpenAI tool spec 本有name,缺它致历史回放无 banner / chip,一行 fix + 幂等回填 17 条。 - dev SPA 输入区删上传按钮 + 加"✨ 润色"按钮:
POST /v1/tasks/{id}/optimize_prompt走 task model_profile 装配 LLM(meta-prompt 含当前模型 + image variant),计费kind=prompt_optimize,不调sync_task_tokens不污染顶栏。 - 顶栏加生图模型下拉 + 中间产物图片/视频内联展示:
GET /v1/image_models扫 yaml image 段,build_agent(image_variant=...)装 SeedreamTool;renderArtifactBarHtml按_categorizeimage/video 走 blob URL inline,切 task 回收 blob。 - LLM 调用切 streaming(cancel 秒退)+ 发送/停止合并单按钮:
chat_stream(stream=True, include_usage=True)+litellm.stream_chunk_builder拼回,chunk 间 poll cancel;前端打字机靠_emit("text", delta=...);#chat-action按state.streaming切三态。 - dev SPA seedream tool 透明性 banner:tool 返串首行
[seedream] model=... · size=... · cost=¥... · elapsed=...s,前端正则 parse 挂折叠态徽章。 - 豆包 Seedream 5.0 接入 + 0007 cost_usd → cost_cny 全表统一币种:
config/media/doubao.yaml独立命名空间(ARK_API_KEY),tools/seedream.py走ark_client调/images/generations,产物落<wd>/figures/;record_image_usagesnapshot 单价进 units(调价防漂移);0007 全表 ×7.2 折 CNY;仅 ARK_API_KEY 设了才挂。 POST /v1/files/delete加recursive+ 顶层目录 task 引用闸:recursive=True走shutil.rmtree;顶层目录被 task 引用 → 409"先 DELETE task 再清"。- fs tool 输出渲染 user_root-relative 路径:
tools/base.py::Tool加user_root+_display(p)helper,fs 五 tool 走 helper;chip 锚点取末段。消 chip 404 + 防 uuid / 部署根泄漏。 POST /v1/tasks/{id}/clear清空对话:同事务 lock + 检 running 状态 + DELETE messages + reset task 三列累计 + run_status='idle';usage_events 全不动(账单 source of truth)。
2026-05-19
- 0006 模型切换(c 模式 task 级 A 粒度)+ usage_events v2 表:
tasks.model_profile变 source-of-truth,顶栏下拉 PATCH 即换(下条 send 生效);GET /v1/models扫 yaml;message 历史按messages.model_profile切换点画── DeepSeek V4 Pro ──;usage_events 重建多态形态(units jsonb,chat 已接入,媒体扩展位预留)。 - dev SPA 登录撤回 邮箱+密码,删 invites 表:前两条"邀请码 env → invites 表"一日游撤回;复用 users.email + bcrypt;
/v1/auth/login_password+user addCLI;dev SPA 双 tab 登录(last-used LS 持久化)。 - SENTINEL user 彻底撤(数据 + 代码):web 必走 JWT 后 sentinel 无角色;DB CASCADE 删 + 10 处代码删;
build_agent加*让 user_id 必填(typechecker 拦多 user 函数)。 - 任务/文件行
⋯下拉菜单 + tool_result debounce 刷新右侧:单例浮层菜单(#floating-menuposition:fixed)避开 pane overflow 裁剪;tool_result事件 debounce 500ms 刷新文件 panel。 - proposal skill mermaid 强制 + quality_check 加图相关 4 拦截 +
/v1/files/download加Cache-Control: no-cache:模型曾写满 ASCII 字符画从未用 mermaid;render_diagrams caption 强制必填 + 同 task 唯一;quality_check 加四条(figures 有 png 但 sections 0 引用 / 围栏含 box-drawing / mermaid 缺首行 caption / caption 撞名)。 - dev SPA 文件预览弹框:点击不再直接下载,90vw 模态按扩展名分派(image/pdf/text/md 已有 / docx 用 docx-preview / xlsx 用 SheetJS);vendor 入 git(~1MB)。
2026-05-18
- 入口归位:
cli.py→main.py,原main.py→core/agent_builder.py,删 CLI REPL,§7 E 撤:main.py原混三角色按 SoC 拆;git mv+ 5 处 import 修;CLI 只剩db / probe / web / user。dev SPA 已是 dogfood 主路径,REPL 无--remote双 transport 维护税。 - 0004 schema 大瘦身:删 runs / usage_events 旧版,合 run_status / run_error 入 tasks;路由 run_id → task_id:单活 run 形态下客户端只需 task_id;broker 全 task_id 索引 + 加
start(task_id)清上轮 done 标记。 POST /v1/files/rename+ 顶层目录 delete 加 task 引用闸:/v1/files/*升格为唯一目录树 mutation 入口,DB-FS 一致性服务端内化;顶层目录走 DB-aware 分支(SELECT FOR UPDATE + running/cancelling 409 + check_no_subtask + UPDATE 先于 FS rename)。- task-level cancel + AgentLoop 协作式 cancel + dev SPA stop 按钮:Broker 加
request_cancel / is_cancelled / clear_cancel(per-taskthreading.Event+ setdefault);Loop 加cancel_checkcallable +_fill_cancelled_tool_results补 cancelled tool message;LLM 同步 call 本身不可中断(后接 streaming 修)。 POST /v1/tasks/{id}/messages单活 run 锁 + 孤儿 reaper:同事务SELECT FOR UPDATE+ 活跃状态检查 + 标 running 三步原子;lifespan reaper 清进程 crash 留下的 running/cancelling 孤儿。- proposal skill 流程图/结构图管线:
render_diagrams.py扫 mermaid 块 → mmdc / mermaid.ink → png;render_docxadd_picture识别单行 + mermaid 围栏特判;图编号ctx['fig_no']递增。 - system prompt skill 机制改"可选辅助":第 14 行从"永远 load 一下"改"简单问答/读代码/改 bug 不必硬套 skill";接 GET /v1/skills 下拉。
GET /v1/skills+ dev SPA skill 字段改下拉:lifespan 启动扫一次挂app.state(FS 静态运行中不变);<select>首项空值,option 文案name — description。- dev SPA 全套 UI 中文化:静态 + 动态文案全本地化;技术字段(UUID / token / SSE event 名 / API 字段)不动。
2026-05-17
- 0003 schema:name + working_dir + skill 三件套:任务标识与工作目录解耦;
TRUNCATE tasks CASCADE+ 字段改名 + 加name TEXT NOT NULL;GET /v1/folders给 dev SPA modal datalist。 GET /v1/tasks分页 + 多维筛选 + ordering:{page,page_size,count,results}+ 6 个 query(status/skill/working_dir/q ILIKE/ordering);allowlist 防注入;默认-created_at。- task 硬删 API + dev SPA delete 按钮 + 文件 per-row 删:
DELETE /v1/tasks/{id}user_id 校验 + DB 行删(messages CASCADE)+ FS task_dir 不动(同 name 多 task 共享时 rmtree 易擦素材)。 - files API 全面 user-rooted(去掉 task_id 前置):
_safe_join边界改 user_root + dotfile 过滤(.memory/隐藏);dev SPAloadFiles()不再 gate on task_id。 - files 面板 UX 项目名 + 修 root crumb bug:
cur_rel == "."不追加无意义 "." crumb;crumbs 第一格 label 从 "/" 改项目名。 - task_dir 改 eager mkdir:
build_agent新建分支 +create_task都mkdir(parents=True, exist_ok=True);name = 项目声明,目录该 task 创建时存在。 - task = name-based 项目目录 + memory dotfile:废 UUID 派生 +
tasks/中间层;task_dir = workspace/users/<uid>/<name>/,同 name 多 task 共享;memory 搬.memory/dotfile;validate_task_name拒.起头。
2026-05-15
- §7 D 阶段
/v1JSON API 落地;Phase G Jinja2/HTMX UI 路线撤:删 templates + CSS + jinja2/markdown-it-py/pygments 依赖;SSE event 由 HTML 片段切 JSON(event: <type>+data: <JSON>);dev SPAweb/static/dev.html留作本地 dogfood 主路径。 - §7 D' 过渡 auth(PLATFORM_KEY → JWT)+ dev SPA:pyjwt HS256 +
AuthConfig.from_env()fail-fast;数据隔离全Task.user_id == user_id,跨 user 视 404;SSE 走 fetch + ReadableStream 手解(EventSource 不支持自定义 header)。 - task_dir 改相对存储:DB 存 ROOT 内→相对 posix / ROOT 外→保留绝对;
core/paths.py::{ROOT, to_db_path, from_db_path}三出口;alembic 0002 一次 UPDATE backfill。CLAUDE.md 加"开发期不写兼容层"心智。 - workspace 布局统一 per-user:
workspace/users/<user_id>/{tasks/<uuid>,memory/}/;清旧数据不留兼容。 - litellm 启动 cost map 网络警告兜底:
LITELLM_LOCAL_MODEL_COST_MAP=True走本地 cost map,冷启动 ~5s → <1s。 - Phase G G1-G6 Jinja2/HTMX Web UI (全撤,被 D + dev SPA 替换;沉淀的 sink / broker / no-subtask / files 安全归一保留)
2026-05-14
- §7.1 心智模型修正:Folder-centric → Task 一等公民 + Dir 文件副视图:dir 不是 task 父容器,双视图正交;task_dir 留空 = 一次性对话 / 指定 = 项目化。
- §7 B Steps 1-4 + 6:
core/storage/{engine,models}.pySQLAlchemy 2.x ORM(5 表)+ alembic +cli db {upgrade,downgrade,current};state.json全废,messages/TaskState 入 PG;check_no_subtask同 user 下查前缀嵌套。
2026-05-12
- §7 改写:platform/core 多租户方案废弃,改 user-direct(folder-centric → task-primary;task/messages 入 PG;no-subtask;hard cascade)。
历史(2026-Q1 → 05-11)
- Phase 1-4:骨架 / 三 skill / run_python / Model Profile + Probing;ppt v3 加商务红 + apply_brand + Iconify;素材摄取改 markitdown CLI。
- 05-06 → 05-08:Phase 6 部分(task + state.json + tokens 累计);TUI rich Markdown + spinner 实时耗时;
/resume [last|<id>]+ 懒创建 +_cleanup_if_empty。 - 05-09 → 05-10:DESIGN §7 初版(05-12 重写);
cli.py export+core/export_docx.py。 - 05-11:
atomic_write_text+core/memory.py(core.md 入 prompt,extended/* 索引);loop 事件流化sink.emit铺 SSE 路。 - 06-04 token 优化启动:
DESIGN.md §8.2写入上下文治理方案;chat usage 记录 cache hit/miss / reasoning tokens,LiteLLM cost=0 时按模型档案 CNY/Mtok 兜底;run_python新增script_path模式(长代码先 write .py 再按路径执行,减少 run_python code 入历史);run_python/shell长输出只做上下文裁剪,不写.tool_logs;document_search默认召回量保持 6×1200 chars;core/context.py先压缩旧 tool 消息、旧load_skill结果、旧 assistant tool_call arguments(write(content=...)源码参数),不改持久化历史;llm_startSSE 输出context_*压缩统计,dev SPA 底部 hint 展示上下文压缩与 cache hit/miss。rust介绍实测:task 列表70条 / 711k tok是历史累计,最近单轮 22k input 且 cache hit 高;新增 arguments 压缩后 sent_chars 估算49,166 → 34,415。
关键决策与偏差
| 项 | 决策 | 备注 |
|---|---|---|
| 工具基目录 | cwd(读)+ working_dir(写) | system prompt 同时注入两者绝对路径 |
| Workspace 布局 | workspace/users/<user_id>/{.memory/, <name>/} |
per-user 隔离;memory dotfile 防撞;同 name 多 task 共享 |
| Eval Suite | 不做 | 个人工具 dogfooding |
| 版本化 prompt | 直接 general_v1.md |
Windows 软链接麻烦,真要切再做 |
| run_python 沙盒 | subprocess + env 过滤 | Docker 在 §7 C 阶段 |
| 兼容层 | 开发期不写 | DB schema / 字段 / API 改动直接切,见 CLAUDE.md |
/v1/files/* 与 DB |
files API 作目录树唯一 mutation 入口,DB-FS 一致性服务端内化 | rename / delete 顶层目录 DB-aware |
| 单活 run | task 同时最多 1 个活 run | gate 在 post_message 同事务 SELECT FOR UPDATE |
| LLM 调用走 streaming | chat_stream + litellm.stream_chunk_builder 拼回;cancel 在 chunk 间 + tool_call 之间 poll |
cancel 延迟 100ms 级;content delta 即时 emit 给前端打字机 |
| 发送/停止单按钮 | UI 按 state.streaming 切态;streaming 期间 Enter 不触发停止 |
防误触 |
文件清单
core/capabilities.py 75 ← 模型档案增加 CNY/Mtok 计费兜底字段
core/llm.py 151 ← litellm 离线 cost map env + chat_stream(stream=True + include_usage)
core/loop.py 300 ← §7 A sink.emit + _stream_llm(chunk 间 poll cancel + emit delta)+ usage cache 明细
core/context.py 95 ← LLM 调用前压缩旧 tool / load_skill 消息,保 tool_call 协议字段,返回压缩统计
core/sinks.py 101 ← §7 A
core/ui.py 38
core/paths.py 50 ← task_dir db form 归一
core/probe.py 243
core/session.py 153 ← §7 B Step 2-3: ORM
core/skills.py 81
core/task.py 82 ← §7 B Step 3: PG-backed TaskState
core/memory.py 81 ← per-user `.memory/` dotfile
core/export_docx.py 383
core/storage/__init__.py 29
core/storage/engine.py 80
core/storage/models.py 130 ← 4 表(0004 删 runs;0005 email UNIQUE;0006 usage_events v2 + messages.model_profile;0007 cost_usd→cny)
core/storage/usage.py 150 ← record_chat_usage(USD→CNY ×7.2,LiteLLM cost=0 时 YAML 单价兜底)+ record_image_usage(单价 snapshot 进 units)
core/storage/utils.py 136
core/ark_client.py 105 ← 火山方舟 HTTP 客户端(seedream / 后续 seedance 共享)
core/agent_builder.py 325 ← 装配 lib(有 ARK_API_KEY 才挂 SeedreamTool)
tools/{base,fs,shell,run_python,skill_tool,seedream}.py ~680 行(run_python 支持 script_path)
main.py ~210 ← 入口:web / db / probe / user
db/migrations/env.py 61
db/migrations/versions/
0001_initial_schema.py 125
0002_task_dir_relative.py 61
0003_task_name_and_working_dir.py 51
0004_drop_runs_usage_events.py 77
0005_users_email_unique.py 28
0006_usage_events_v2_and_message_model.py 60
0007_cost_usd_to_cny.py 40
web/__init__.py 5
web/app.py ~1320 ← /v1 JSON API + user_id 隔离 + run lock + cancel + files copy/move
web/auth.py ~190 ← 邮箱密码 + platform_key → JWT
web/broker.py 121 ← in-process pub/sub + cancel signal(全 task_id 索引)
web/sinks.py 21
web/static/dev.html ~2480 ← dev SPA(3 栏 + 文件预览 + 双 tab 登录 + 选入弹框 + 发送/停止单按钮 + 流式打字机)
web/static/vendor/ ~1 MB ← jszip / docx-preview / xlsx
─────────────────────────────────
Python 合计 ~3400 行(+ dev.html 1700 静态 + vendor 1MB)
加 skills/ppt|proposal|coding|research/ 脚本 ~700 行 + SKILL.md / references / config / prompts(含 config/media/doubao.yaml)+ alembic.ini,总仓库约 3800 行。
下一步候选(性价比排序)
- 真 OIDC 接入 + CORS 收紧(~1 天)——
/v1/auth/login内部换 OIDC ID token 校验(路由层 Depends 不动);CORS 改 platform 域名 allowlist。真发布给真实用户前必做。 - §7 C Executor + sandbox(~3-5 天,按 DESIGN §7.5 落地清单 6 条逐项实施)——
run_python/shell→Executor.run(...),本地保留 subprocess、SaaS 走 docker;api_key_env→KeyProvider运行时注入。多用户在线跑代码前置。Stage C 完成 DoD = 6 条落地清单全完成 + 红队回归用例通过:① 容器内curl http://169.254.169.254/...→ timeout / connection refused;② 容器内psql postgresql://<zcbot_pg_host>...→ IP block(连接失败);③ 容器内nohup sleep 1000 &exec 退出后docker top <user_container>看不到残留进程;④ 跨 user 容器互访(A 容器curl http://<B_container_ip>:*)→ 网络隔离阻断;⑤ 出网走 proxy 时未在 allowlist 的域名 → 403。原 ~2-3 天估值未含 egress proxy 部署 / xfs project quota 升级 / 红队用例,补回真实工程量。 - Phase 6 context 三层压缩(~1 天)—— 先做旧 tool 消息压缩(
role/tool_call_id/name保持协议完整),再做 task summary;不写.tool_logs,不改document_search默认召回量。
§7 B + D + D' + 单活 run 锁 + cancel + 0004 schema 瘦身 + 入口归位 主体已完工。剩余:真 OIDC → C(Executor)→ F(deploy / billing)。§7 E CLI 双模式撤;Phase G Jinja2/HTMX 撤(详见 DESIGN §7.9)。