caoqianming
fedf5a2cd5
fix(deploy): 默认镜像源改清华(pip+apt)/ npmmirror(npm)— 腾讯源给出损坏 litellm wheel
...
腾讯源返回的 litellm-1.87.0 wheel 文件损坏:镜像 index 声明的 sha256(fbbba7e…,
与 PyPI 官方一致)对,但实际吐出的文件字节算出 bbebefff…,pip 报
"THESE PACKAGES DO NOT MATCH THE HASHES"。本仓 requirements.txt 未钉 hash,
是镜像端 index 自声明 hash 与文件不符 = 镜像存的文件损坏/截断(非篡改、非 require-hashes)。
deploy/update.sh 三个默认值:
- PIP_INDEX_URL -> 清华 pypi.tuna.tsinghua.edu.cn(境内稳 + 同步及时;阿里 PyPI 曾滞后到没有 litellm>=1.83)
- APT_MIRROR -> 清华 mirrors.tuna.tsinghua.edu.cn(Debian / security 路径同官方,sed 替 host 即可)
- NPM_REGISTRY -> registry.npmmirror.com(清华无 npm registry,npmmirror 是境内事实标准)
换默认会让下次 build 从 pip 层全量重跑一次(~5-10min),之后命中 cache。
Dockerfile ARG 默认(官方源 fallback)不动。
RUN.md:头部「最后更新」、§镜像构建默认源说明、手动 build 示例、故障表
(新增 hash-不匹配诊断行 + 其余镜像行对齐新默认)。PROGRESS.md:2026-06-03 加一条。DESIGN 不动。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:46:54 +08:00
caoqianming
9cd33cf4d6
revert(workspace): 撤 ZCBOT_WORKSPACE_DIR env 覆盖(架构 bug),数据盘改用 bind mount
...
2026-06-02 给 resolve_workspace 加的 env 覆盖与路径存储层冲突:core/paths.py
把 DB working_dir 锚定 ROOT(代码仓库目录)存相对串,to_db_path 对 ROOT 外路径
直接 relative_to raise。env 一旦指向 ROOT 外的 /data/...,三家分叉:
- 文件面板 /v1/files 走 resolve_workspace(吃到 env)看数据盘
- agent resume 走 from_db_path(锚 ROOT)看 ROOT/workspace
- 新建 task to_db_path 直接 500
现场症状:文件面板"目录尚未创建",但 agent 文件其实写在老 ROOT/workspace。
改法:resolve_workspace 回退成 显式 arg > cfg workspace_dir > 默 workspace
(均 ROOT/<值>)。import os 保留(别处仍用)。要把重写入区落独立数据盘改用
bind mount 把 /data/zcbot/workspace 接到 ROOT/workspace —— .resolve() 不展开
bind,内核路径保持 ROOT 内,relative_to(ROOT) 照常过,DB 不用改,dev 不受影响。
RUN.md:删 .env 的 ZCBOT_WORKSPACE_DIR 段;「workspace 落独立数据盘」段改
bind mount(+ RequiresMountsFor 开机顺序硬化);故障表替换旧 env 行 + 加
"目录尚未创建"诊断行。PROGRESS.md:2026-06-03 加回退记录。DESIGN 不动。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-03 10:24:14 +08:00
caoqianming
382a85e88e
feat(workspace): resolve_workspace 加 ZCBOT_WORKSPACE_DIR env 覆盖(per-host 落盘)
...
prod 要把重写入的 workspace/users/ 落到独立数据盘(xfs prjquota),但
config/agent.yaml 的 workspace_dir 是 dev/prod 共用提交的,改绝对路径会带歪 dev。
resolve_workspace 优先级改为 env ZCBOT_WORKSPACE_DIR > yaml workspace_dir > 默 "workspace"
(对齐 sandbox.* 的 yaml+env 模式);env/cfg 值都按 ROOT/<值> 解析,绝对路径直接生效。
dev 不设 env 维持 ROOT/workspace,prod systemd 设数据盘绝对路径,两边不抢同一份 yaml。
PG 暂不迁(元数据库小,留默认 /var/lib/postgresql 少坑)。
RUN.md:env 段加 ZCBOT_WORKSPACE_DIR + 新增「workspace 落独立数据盘」段
(mkfs.xfs + fstab prjquota + rsync 迁移 + systemd env)+ 故障表一行。
PROGRESS.md:2026-06-02 加一条。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 14:42:00 +08:00
caoqianming
33bea27d85
fix(web): embed 模式登录页一闪而过 — body 首行同步隐藏 #login
...
#login 默认 display:flex(带 login-in 动画),加 body.embed-mode 隐藏它的
embedInit() 在 body 末尾才执行;单文件 3800+ 行,浏览器常在解析到底部脚本前
就先把登录卡画出来,造成"一闪而过"。改法:在 <body> 第一行加一段同步内联脚本,
?embed=1 时立即 add embed-mode,赶在 #login 解析/绘制之前隐藏它。
只是绘制闸门,底部 embedInit(postMessage 握手 / embed-waiting / token 分支)
完全不动,embed-mode 幂等。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-02 09:23:32 +08:00
caoqianming
4c1a26cee8
fix(deploy): update.sh 的 docker build 回到默认 TTY 进度 UI(撤 --progress=plain)
...
分层折叠刷新的 TTY UI 更直观;step 2 pip 去 -q 已足够让装包进度可见。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:07:35 +08:00
caoqianming
74580e951e
fix(deploy): update.sh 加自更新重跑守卫,修"改了源仍报旧错"
...
脚本 git pull 会改自己:变量默认值在 pull 前已求值、bash 又按字节偏移边读边跑,
首次拉到"改 update.sh"的提交那一轮跑的仍是旧脚本(默认源还是阿里 -> litellm 报缺版本)。
pull 后检出本脚本有变更即 exec 新版本从头重跑(ORIG_ARGS 原样回传,ZCBOT_UPDATE_REEXEC 防死循环)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:04:25 +08:00
caoqianming
4eacfe1bd9
fix(deploy): update.sh 默认源改腾讯避开阿里滞后(卡 litellm>=1.83);build 跳过改 --skip-build;进度可见
...
阿里 PyPI 镜像同步滞后(只到 litellm 1.82.6),撞 requirements 的 >=1.83.0。
- 默认 APT/PIP/NPM 源阿里 -> 腾讯(已到 1.88);step 2 host pip 显式 --index-url(sudo -u 会洗掉 PIP_INDEX_URL env)
- ZCBOT_SKIP_SANDBOX_BUILD=1 env -> --skip-build CLI flag(开发期不留兼容)
- step 2 pip 去 -q + step 4 docker build --progress=plain,部署逐行流式可见
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 16:00:00 +08:00
caoqianming
f66d55cc3b
feat(deploy): 加一键部署脚本 deploy/update.sh(pull/pip/migration/build/restart/healthz)
...
固化日常部署:git pull --ff-only → pip install → db upgrade head →
docker build sandbox → systemctl restart → curl /healthz 验活。
两处钉死:① migration 不能漏,env.py 直读 os.environ 不读 .env,脚本从
.env 抠 ZCBOT_DB_URL 显式喂进去;② build 必先于 restart —— 容器复用 +
tools/ 烤进镜像,restart 时 shutdown_all 清旧容器,下次 ensure() 才用
新镜像重建。sandbox 每次 build 无所谓(重活在 COPY tools/ 之上,cache
让改代码部署秒过)。镜像源默认阿里,可置空回落官方。前置守卫 + healthz
失败 dump journalctl 非零退出。bootstrap 不进脚本,留 RUN.md。
RUN.md §部署 SOP 重写为指向脚本 + 手动 fallback;PROGRESS 加一条。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 14:52:44 +08:00
caoqianming
fb5e68d9e7
fix(sandbox): 装 CJK 字体修 matplotlib / mermaid 出图中文方块
...
sandbox 镜像基于 python:3.12-slim 一个中文字体都没装,matplotlib /
mermaid(chromium)/ render_icon 出的 PNG 中文全是豆腐块。
- Dockerfile: apt 装 fonts-noto-cjk + fonts-wqy-microhei + fontconfig,fc-cache 刷索引
- style.py: 候选首位加 "Noto Sans CJK SC",matplotlib 优先用 Noto
- PROGRESS / RUN 故障表同步
改了 Dockerfile 必须重 build 镜像 + 清旧容器才生效。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 13:47:04 +08:00
caoqianming
0343dd6dd2
docs(progress): MP host 工具联网实测闭环 —— 换 next-gen key 后 step D 复测通过
...
初次 403 定位为 .env legacy 旧版 key 在新版 mp-api 失效;换 next-gen materialsproject.org
长 key 后查 Ca3SiO5 返 3 条 mp-xxxx + energy_above_hull,MP host 工具端到端通路确认可用。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:38:05 +08:00
caoqianming
68ce996ad2
feat(tools): documents/pymatgen secret-bearing 能力改 host-side tools,key 不进 sandbox
...
新增 tools/documents.py(document_list_kb/search/download)和 tools/materials_project.py
(mp_search_summary/get_structure/get_entries),key 只在宿主读取,sandbox/run_python 拿不到。
agent_builder 仅在对应 env 存在时注册。删 skills/pymatgen/materials.py::mp_rester() 旧入口,
smoke 改走 host tool。同步 DESIGN §6.7 secret-bearing 规则 + RUN/SKILL_LIST/两个 SKILL.md。
实测:MP step D 真连 api.materialsproject.org 返 403(工具行为正确,干净透传 [Error]),
疑似 .env 里 legacy key 在新版 mp-api 失效,待换 next-gen key 再验。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-01 09:35:10 +08:00
caoqianming
4bd074079a
design: 加 §8.1 seedream i2i + vision 后续步骤 + probe 实测 base64 通
...
用户场景"seedream 出图→基于该图二次修改"/"上传外部参考图让 agent 据此干活"
两条主模型 DeepSeek V4 纯文本覆盖不了。详评 3 方案选 E+C 组合(seedream
加 reference_images 走 5.0 i2i + 新 tools/look_at_image.py 走豆包 Seed 1.6
vision tool 调度),否决 A(换主模型降 code/tool calling 质量+改 loop/memory
工程面 5×)/ B(后台隐式 vision 路由失 agentic 控制+token 浪费)。
实测 scripts/probe_seedream_i2i.py:豆包 Seedream 5.0 /images/generations
接受 image_urls=[data:image/png;base64,...] 作 i2i 输入,200 返回新图 TOS URL
+ usage.generated_images=1。约束:输出 size≥3686400 像素(~1920²),单张参考
≤10MB,最多 14 张。**内网部署无需对象存储中介**,排除最大工程不确定性。
E+C 实施清单/风险/升级到 A 的信号已落 DESIGN §8.1,本版仅 probe+design,
tool 与 prompt 改造未启动。RUN.md / SKILL_LIST.md 不动(无 CLI/env/skill 变化)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 12:47:04 +08:00
caoqianming
e6eebbc9ad
feat(web): tool_call 标题行改显中文活动描述 + 修 args 字段 bug
...
dev.html 实时流读 ev.data.arguments 但后端 emit 的是 args,字段名对不上
导致参数永远为空、连带 artifact 路径提取失效。新增 toolActivityLabel 按
12 个工具的关键参数套中文动词(执行命令/运行 Python/读写编辑文件/查找搜索
/联网搜索/抓取网页/加载技能/生成图像视频),实时流与历史回放两处同步;完整
参数仍在折叠 <pre> 里。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-29 12:24:54 +08:00
caoqianming
aab1da3296
fix(executor_docker): 删 setsid 修 docker exec 延迟 stdout 丢失
...
实证:`docker exec ... setsid python -c "sleep(2); print"` 等满 2s 输出空,
同条件去 setsid 输出 hello。setsid 调 setsid() syscall 后 docker exec/runc
的 stdio attach 出问题,延迟输出被截。上一条 _run_subprocess 重写修了独立的
poll-loop bug 但不是用户当下症状元凶。setsid 历史是给 §7.5 Step 3b PGID kill
协议铺路,该协议未实现的当下是空头载荷 + 副作用。改 _exec_shell:141 / _exec_python:177
各删 1 个 "setsid"。回归测试加 test_run_subprocess_delayed_output_not_lost
(真子进程 sleep+print)+ test_argv_does_not_contain_setsid(防回潮)。19/19 PASS。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 11:02:17 +08:00
caoqianming
91cc14278c
fix(executor_docker): 重写 _run_subprocess 修 docker exec stdout 多 chunk 静默丢失
...
旧实现在 poll loop 里反复 communicate(timeout=0.5) 违反 subprocess API 假设,
配合 setsid bash -c block-buffered stdout 在多 chunk 输出时 chunk 静默丢失,
LLM 调 run_python / shell 拿到空 [exit 0] 8 字符,误判 paper_server 不可用。
改单次 communicate(timeout=full) + 侧线程 daemon poll cancel + 入口 inline
快路径。回归测试用真子进程 bash sleep 多次 echo 锁死,17/17 PASS。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 10:26:59 +08:00
caoqianming
f1a42ef13f
skills: 3 SKILL.md 标 sandbox env key 拦截现状(documents/pymatgen ⚠️ + research ✅ )
...
run_python `_SENSITIVE_PATTERNS` 过滤器拦含 API_KEY/TOKEN/SECRET 字面的 host env
(挡 prompt 注入抽 JWT_SECRET 等),误伤 documents/pymatgen 从 env 读 key 的 helper;
docker backend 下 host env 根本不入容器,问题更彻底。LLM 还把 research 跟它们排版
类推也放弃,可 research 不持 secret 任何模式都能用 —— 加 callout 阻止误推 + 反模式
扩到禁所有 HTTP 客户端裸调,免得 urllib 钻空子跳过 helper 教学。
broker 下轮做(host tool 范式不取),DESIGN 当时再补。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-29 09:23:41 +08:00
caoqianming
09378b56c1
skills/review: 加长文档处理段(骨架扫描 + 用户挑章节深审 + 中间文件落盘)
2026-05-28 16:29:26 +08:00
caoqianming
cf23c9d178
models: 加 local.{r1,qwen3} 内网模型档案,涉密任务用
...
DeepSeek-R1 (满血) + Qwen3-30B-A3B(服务端 alias 名是 Qwen/QwQ-32B,实际后端
Qwen3) 部署在 http://182.54.21.126:9000/v1,OpenAI 兼容,共享 LOCAL_LLM_API_KEY
env。thinking_mode=false(R1/Qwen3 默认就思考,不通过 reasoning_effort 控制)。
local.qwen3 已通连通性,local.r1 服务器侧调试中。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 15:55:37 +08:00
caoqianming
4b7d7e6f77
fix(skill_tool): docker backend 下返回容器路径而非 host 绝对路径
...
实测部署 dogfood analyze skill 时,LLM load_skill 拿到 host 绝对路径
`/home/lighthouse/zcbot/skills/analyze`,照 SKILL.md 拼 references 路径调 read
→ 容器内 namespace 没这条路径(容器只有 /sandbox/skills:ro 这 mount),抓瞎。
修法:LoadSkillTool 加 container_skills_dir 构造参数;agent_builder 在装它时
判 ZCBOT_SANDBOX_BACKEND==docker → 传 "/sandbox/skills",其它 → 保持原 host
绝对路径(开发期 host backend 不破)。
结构性收益:proposal/ppt/research/coding/pymatgen/stats_ml/plot_pub 全部 skill
references 在 docker backend 下自动 work,不用一个个改 SKILL.md 教用容器路径。
tests/test_load_skill.py 4 case 锁:host 走 host 路径 / docker 走 /sandbox /
末尾斜杠拼接不双斜杠 / 未知 skill 走原路径。docker executor 15/15 回归 PASS。
部署后:git pull + 重启 agent 进程让新代码生效(SkillRegistry 每请求重建但
LoadSkillTool 实例化在 build_agent 里,需要新进程)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 13:37:19 +08:00
caoqianming
203e14d15d
skills: 加 analyze(科学问题拆解 / 引导,PICO + Issue Tree + 5Whys/TRIZ/DoE)
...
服务"用户拿模糊高层科研问题过来、还没决定要不要立项 / 不知道从哪入手"的早期阶段
—— 之前 10 个 skill 没人接这场景(proposal/research/stats_ml 都要先想清楚)。本 skill
不执行任务,只把模糊命题翻译成可操作子问题 + 实施路线图,最后接力给下游 skill。
四段式工作流:
1. PICO/PECO 规范化(P/I/C/O + FINER 五维自检)— BLOCKING
2. Issue Tree 拆解(MECE,默认机理-现象-工艺三层,叶子标 类型/优先级/能力描述)— BLOCKING
3. 按叶子类型分支深化:根因→Fishbone+5Whys / 创新→First-principles+TRIZ / 优化→DoE 选型
4. 实施路线图(每步标干什么/能力/产物/判停)+ TODO + 接力建议
7 文件 657 行:SKILL.md + 5 references(按需读)+ 1 template(analysis.md 骨架)。
关键决策:
- 不硬编码"叶子能力→skill 名"映射(skill discovery 已注入 prompt,改名不破坏)
- description 双重防护:触发条件写死探索阶段 + 输出末尾推 X 能力接力
- 不要 Python helper(全引导式对话,跟 review skill 同范式)
- TRIZ 摘 10 对建材矛盾(强度↑韧性↑ / 早强↑后期↓ / 致密↑透气↑...)够 80% 场景
- DoE 只规划设计类型 + 因素表,具体点位生成由下游 stats_ml 跑 pyDOE2
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 13:18:54 +08:00
caoqianming
85415470d2
sandbox+infra: Python 3.10→3.12(host+Dockerfile)+ docker PYTHONPATH 加 /sandbox
...
为通过 3 个科学 skill 的 smoke 解决两件基础设施问题。
1. emmet-core 0.86.0rc1 用了 typing.NotRequired(3.11+),host .venv 是 3.10
→ mp_rester ImportError。选 3.12(当下 ML 生态默认稳定版,比 3.11 多一年
优化,比 3.13 wheel 覆盖更全 Windows 不踩坑)。Dockerfile python:3.11
→ 3.12 同步升,部署机 rebuild image 时生效。
2. executor_docker.py:172 PYTHONPATH 由 /workspace 改 /sandbox:/workspace,
修历史 bug —— skills/ bind mount 到容器 /sandbox/skills:ro,SKILL.md 教
LLM `from skills.xxx import yyy`,docker backend 之前根本 import 不到
(research/paper 同款受影响,只是 dogfood 一直跑 host backend 没暴露)。
test_executor_docker.py:243 regression 测试改为 assertIn 含 /sandbox,
15/15 PASS。
smoke 验证:pymatgen XRD / sklearn / statsmodels / plot_pub 全通,
mp_rester 联网遇 MP 服务侧 IP/ASN 403(LBNL 对国内 IP 临时封,非代码问题)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 11:35:02 +08:00
caoqianming
52f201404c
skills: 加 pymatgen / stats_ml / plot_pub(建材院无机材料场景)
...
服务中国建材院无机非金属材料 R&D。从 K-Dense AI scientific-agent-skills 仓库挑
3 个 ★★★ skill fork,不走 npx 一键装(138 个 description 入 prompt 噪声 + 误触发)。
- pymatgen: 晶体结构 / XRD / 对称性 / 相图 / Materials Project。helper
materials.py 内 CEMENT_PHASES 收 66 条中英文相名映射(水泥熟料 / 水化产物 /
陶瓷耐火 / 玻璃晶相 / 常见矿物)、lookup_phase 大小写不敏感、mp_rester 从
env MP_API_KEY 拿 key
- stats_ml: 纯指南 skill,场景导航 sklearn / statsmodels / PyMC 三选一,
5 个工作流(配方-性能回归 / DoE 二阶响应面 / 显著性分析 / 贝叶斯小样本 /
DBSCAN 异常配方)+ 16 条反模式
- plot_pub: 出版级 matplotlib,helper style.py 内 apply_pub_style() 一键
设置中文字体跨平台 fallback (SimHei / YaHei / WenQuanYi) + viridis +
dpi + PDF Type 42
requirements.txt 加 pymatgen / mp-api / scikit-learn / statsmodels
(pymc 注释,装包重按需开)。RUN.md env 段加 MP_API_KEY(可选)。
SCIENTIFIC_SKILLS.md 根目录沉淀整体评估,后续 materials_db 落地参考。
scripts/smoke_scientific_skills.py 三 skill 链路通路验证脚本。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 11:33:59 +08:00
caoqianming
1d6a9898e4
DESIGN §7.5: image 体积 / 多 user 资源 / 后续加包策略
...
把"image 大 = 资源占用大 = 多 user 容器爆炸"的直觉关联拆开:
① layer 共享 + 空载 sleep,image 大 ≠ 运行时吃更多 RAM;
② 多 user 瓶颈在并发 exec 非 idle 容器,杠杆全在 cgroup
limit / 并发 semaphore / idle 回收;
③ 新增依赖采用 base 收敛 + per-user 持久化 venv + 使用频次沉淀
(长尾 domain 包私有装,>30% × ≥3 次再沉淀回 base)。
落地排 Stage C Step 6 Executor。PROGRESS 加一条指针。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-28 08:13:39 +08:00
caoqianming
0b7c084458
skills+general_v1: ppt 歧义反问 + 路由产物形式歧义先问
...
skills/ppt/SKILL.md:3 上次收紧白名单+反例后,"MES 汇报方案" 这种请求
还是被路由命中 —— 反例列表只列了 "生成方案/写报告/出文档/做纪要",
"汇报方案" 未列入,而 "汇报" 在 LLM 语义里本就有强烈的 PPT 联想
(工作汇报/季度汇报多以幻灯片形式),足以压过 "必须明确点名 PPT"
的硬约束。
修法:
- ppt SKILL.md description 改三段(✅ 触发白名单 / ⛔ 不触发 [只留
"报告/文档/纪要" 明确指向文档的词] / ⚠️ 歧义先反问)。把 "汇报/
方案/材料" 从反例摘出来,改成 "先反问 'PPT 还是 Word/Markdown 文档'
再决定 load",把判断权还给用户而不是赌 LLM 路由词典。
- prompts/system/general_v1.md Skill 机制段加 "产物形式歧义时先问"
通用原则,跨 skill 生效(imagegen/videogen 各自 skill 内本来就有
'问清楚再画' 逻辑,抽到 system prompt 让新加 skill 也继承)。
否决:
- 继续往反例堆 "汇报方案/汇报材料/汇报内容":堆词典治标不治本,
下次 "做个 Q4 总结" 又得加。
- 路由层加 required_keywords 结构化字段,在 discovery_block 之前
grep 兜底:跨多 skill 都得补字段,工程量大,短期 LLM 反问范式
收益已够。
- ppt skill load 后再反问:路由命中就已是误触发,要在路由阶段拦。
代价:用户心里已经清楚要 PPT 但没说时会多一轮反问;缓解靠反问句式短
+ 暗示默认选项,一个字 "PPT" 就能过,比生成完整 deck 后推翻代价小
一个数量级。
热更新无需重启服务:agent_builder.py:197 每次 build_agent 现读
general_v1.md;SkillRegistry 也每次 build_agent 重建。DESIGN/RUN 不动。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 15:36:25 +08:00
caoqianming
8109f20345
ppt skill: description 收紧路由,避免 "生成方案" 被误命中
...
skills/ppt/SKILL.md:3 原文含 "方案" / "生成" 字样,Claude 路由时把
"生成一个方案" 也命中到 PPT skill。改成显式白名单
(PPT/幻灯片/演示文稿/.pptx/slide/deck)+ 显式反例
("生成方案/写报告/出文档/做纪要" 不触发)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 15:10:21 +08:00
caoqianming
c4229bede4
skills: /v1/skills 每次现扫,加/删 skill 目录无需重启
...
lifespan 静态快照改 per-request 扫描,SkillRegistry 构造 ~3ms / 次,
e2e ~20ms 在 JWT + DB 噪声里完全可忽略。agent_builder 早已每次新建
registry,本次只补前端下拉这一处。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:47:47 +08:00
caoqianming
da4e47139f
dev SPA: embed+task_id 模型下拉 + 导出/清空键 disable 修复
...
- loadModels 收尾若有 task 选中补一次 renderChatMeta,修 embed+task_id 模型下拉
在 models 接口 resolve 前 selectTask 已跑过的竞态(同步覆盖生图/生视频下拉)
- btn-export/btn-clear-msgs 不再按 n_messages 门禁,只要选中 task 就常亮;清空
保留 running 期禁用。修历史 bug:清空后两键 disable,新对话进来 taskMeta 不
重渲一直灰
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 12:42:19 +08:00
caoqianming
eaf7f3ea1e
Stage C 收尾包:资源 yaml + 磁盘配额 + 网络放开 + 容器内源持久化
...
dogfood + 信任同事白名单阶段 Step 4 完整 egress proxy 暂不做(沉淀为升级触发
信号:任一陌生用户注册 / 模型异常 outbound / 信任白名单出现非密切相识者 → 必上)。
本批 3 件:
(A) 容器资源 yaml 化(可调不重 build):
- agent.yaml 加 sandbox 段(memory/cpus/pids_limit)
- SandboxPool ctor 加三字段,优先级 env > yaml > 默(2g/1.0/256)
- setup_pool/init_pool 透传 sandbox_cfg
- sandbox check 输出加 [info] 4 行给运维一眼对账
(B) 应用层磁盘配额(§7.5 #4 软配额):
- migration 0008 user_disk_usage 单行 per user
- core/storage/disk_quota.py:parse_bytes("5gb"/int)+ scan_user_dir
(os.scandir 跳顶层 .zcbot_tmp / .memory)+ upsert ON CONFLICT
+ check_disk_quota + scan_all_users 串行
- lifespan _disk_scanner 后台 task(启动跑一次 + 默 15min 周期)
- DockerExecutor write/edit 起手 gate 超额 [Error] 不调容器
- /v1/files/upload 同款 gate 超额 HTTP 413
- yaml `quotas.disk_bytes_per_user: 5gb` + `disk_scan_interval_seconds: 900`
- race 接受:扫描间隙写入轻微突破(image/video 配额同款 race-tolerant);
外部用户开放前 OS 层 xfs prjquota 兜底
- 11 测试 covered parse_bytes / scan / 跳 dotfile
(C) 网络放开 + 容器内源持久化:
- network.py 去 --internal flag,容器走 docker bridge default 有 NAT outbound
- 已存在 internal network 不自动 rm 仅 warn,RUN.md 给迁移命令(避免破现有容器)
- iptables 红线段不动(169.254/127/10/172.16/192.168/100.64/PG_IP DROP),
挡 cloud metadata + 内网扫描 + loopback,基线不依赖 proxy
- Dockerfile 加 /etc/pip.conf(global index-url + timeout 60) + /etc/npmrc
(global registry),让运行时模型 `pip install foo` / `npm install bar`
也走 mirror(此前 --build-arg 只 build 时生效)
unittest discover 46/46 PASS(原 35 + 新 11)。
DESIGN 不动(延后决策仍在 §7.7 Stage C 阶段语义内,触发信号沉淀进
PROGRESS / RUN);RUN.md 加 env 列表 + 网络迁移 + 配额 + 故障兜底 3 行。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 08:35:53 +08:00
caoqianming
23ff996d38
Stage C Step 3d: fs 工具进容器 + DESIGN §7.5 #6 重写(物理边界替代代码护栏)
...
Ubuntu dogfood 暴露 host 工具漏底:base_dir=Path.cwd() 无 user_root 校验,
模型 glob "*" 列出 host /home/lighthouse/zcbot/.git/.venv/... zcbot 源码自身。
DESIGN §7.5 #6 原写"host 工具走 paths.py::resolve_user_path 校验"是假命题
(代码里没那函数),绝对路径完全不挡。
修法:fs 工具(read/write/edit/glob/grep)也走 docker exec,物理边界替代
代码护栏(Phase B path validator 那条不做 ── 脆弱)。
- core/sandbox/tool_runner.py 新增:容器内 helper,stdin 接 JSON args,
调 tools/fs.py 的 Tool 子类;base_dir=cwd,user_root=/workspace
- DockerExecutor 加 FS_TOOLS 信任域 + _exec_fs_tool:docker exec -i ...
python /sandbox/tool_runner.py <name>,stdin 喂 JSON args(CJK / 引号
透明传不被 shell metachar 切)
- _run_subprocess 加 stdin 参数 + is_fs_tool 分支返 stdout 直透(原 Tool
返回串语义保持),exit≠0 stderr 当 ToolResult content
- SandboxPool 加 repo_root 字段 + <repo>/skills:/sandbox/skills:ro mount
让容器内 read SKILL references 能解析
- Dockerfile COPY tools/ /sandbox/tools/ + tool_runner.py(build-time COPY
而非 mount ── 容器内代码不应跟随 host repo 改动)
- web/app.py 透传 ROOT 给 init_pool
- 留 host 的工具:load_skill(SkillRegistry 内存查找)/ web_search /
web_fetch / seedream / seedance(持 Bocha/ARK key 不入容器)
- DESIGN §7.5 #6 重写:"几乎所有工具进容器,host 只留持 key + 跨 user 的",
原假命题溯源标注 2026-05-26 修正
代价:每 fs tool call +~200ms docker exec overhead,对话级 N≤15 总 1-3s,
LLM 推理 5-30s 下噪声。升级触发(§7.9 升级表)docker exec → unix socket RPC
仍按原信号(overhead/total > 30% 持续 / 长驻服务工作流)。
测试:test_executor_docker 加 4 fs 路径测试(argv 形态 / CJK stdin JSON /
exit≠0 stderr 透传 / timeout);改原 read 直通测试 → load_skill 直通
(read 现在进容器)。unittest discover 35/35 PASS。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 21:56:41 +08:00
caoqianming
d93cc1a949
Stage C Step 3 hotfix: exec_user 跟随 build_arg + 镜像装 mermaid-cli
...
Ubuntu dogfood 暴露两个真问题:
(1) uid 错配:DockerExecutor 写死 --user 1000:1000,但镜像 build 时
--build-arg HOST_UID=$(id -u) 跟随 host 实际 uid(腾讯云轻量 lighthouse
uid=1001),docker exec 进容器 uid=1000 → bind mount owner 1001 错配 →
写 /workspace/<wd>/ 全 EACCES,文件落 /tmp。
改 DEFAULT_EXEC_USER = "zcbot"(username,docker 自动查容器 /etc/passwd
拿 uid),无论 HOST_UID build 成 1000/1001/其他都跟 bind mount owner 对齐。
(2) proposal/patent skill 渲 mermaid 缺 Node:render_diagrams.py 调
shutil.which("mmdc") 容器没装 → 退 mermaid.ink → sandbox --internal
默 deny outbound API 也不通 → ASCII fallback 出 docx 没图。
Dockerfile 加 chromium + nodejs + npm + @mermaid-js/mermaid-cli,
+~400MB 接受成本(ASCII 不能用)。容器 chromium 缺 setuid sandbox +
/dev/shm 不够大会跪,镜像落 /sandbox/puppeteer-config.json
(--no-sandbox --disable-setuid-sandbox --disable-dev-shm-usage) +
ENV MERMAID_PUPPETEER_CONFIG;render_via_mmdc 改读 env 拼 -p 注入,
host 上跑 env 没设行为零变化。
PUPPETEER_SKIP_DOWNLOAD + PUPPETEER_EXECUTABLE_PATH 让 puppeteer 用
容器内 chromium 不下载自带 Chrome(省 ~300MB)。
NPM_REGISTRY build-arg 同 pip 同款(腾讯云内网 / 阿里 npmmirror)。
RUN.md 加 NPM_REGISTRY 段 + 故障兜底 3 行(EACCES uid 错配 / mmdc 报
launch chromium / npm 慢)。DESIGN 不动(纯 bug fix + skill 依赖)。
unittest discover 31/31 PASS。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 21:47:33 +08:00
caoqianming
1a950dedb5
Stage C Step 5: main.py sandbox check + lifespan fs quota WARN
...
- main.py sandbox check 子命令:5 项独立探测 + 汇总 exit code
① docker daemon 可达 ② zcbot-sandbox:latest 镜像存在
③ zcbot-sandbox-net network 存在(warn 不 err) ④ 镜像 zcbot uid 与 host
uid 对齐 ⑤ workspace/users 所在 fs 类型可 quota
- core/sandbox/check.py:detect_fs_quota(path) -> (level, msg) 抽出来给
lifespan 与 CLI 共用;识别 xfs+prjquota/ext4+project/zfs/btrfs/tmpfs/其他
- web/app.py lifespan docker backend 启用时调 detect_fs_quota 打 WARN
到 stdout(不阻塞启动,应用层周期扫描仍生效)
- err vs warn 分界:err = docker backend fail-fast 根因(daemon/镜像/uid),
warn = 不阻塞启动但外部开放前要清(network 缺/fs 不可 quota)
- run_sandbox_check 用 module-level getattr 而非固化 CHECKS 元组,让
unittest patch core.sandbox.check.check_xxx 生效
- tests/test_sandbox_check.py 19 测试覆盖各分支 + exit code 汇总;
unittest discover 31/31 PASS
- RUN.md 加"部署前置对账"小节 + "配额硬化"重写(fs 状态→处理映射表 +
xfs 升级 4 步) + 故障兜底 3 行;DESIGN 不动
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 16:41:16 +08:00
caoqianming
dfac0acfa6
Stage C Step 3: DockerExecutor 集成 AgentLoop + web lifespan reaper
...
- core/executor_docker.py 新增 DockerExecutor:组合 HostExecutor+SandboxPool,
shell/run_python 走 docker exec(setsid + --user 1000:1000 + --workdir),
其他工具直通 host(§7.5 #6 信任域二分)
- run_python tmp .py 落 <user_root>/.zcbot_tmp/<task_id>/(dotfile,/v1/files
天然过滤),容器内对应 /workspace/.zcbot_tmp/...,跑完 unlink
- ZCBOT_SANDBOX_BACKEND=host|docker env 切 backend,默 host(Windows dogfood
零变化);docker 路径 pool 未 init → fail-fast 不静默退化
- web/app.py lifespan:docker backend 启动时 init_pool + shutdown_all 清孤儿 +
60s 后台 reaper(run_in_executor 调 sync reap_idle);关闭时 cancel + 兜底清
- pool.py 顺手清 Step 2 债:asyncio.Lock → threading.Lock,ensure 改同步
(主使用方是 BG 线程 tool call,ephemeral loop 会让 asyncio.Lock 跨锁失效)
- Cancel limitation 接受:Popen.kill() 仅杀 docker CLI 客户端,容器内进程靠
idle 5min reaper 兜底;升级到 PGID 协议(§7.5 #3 )等用户反馈触发
- tests/test_executor_docker.py 11 测试覆盖关键路径(host 直通/argv 形态/
tmp 清理/timeout/cancel/未知工具/enable_run_python=False)
- DESIGN.md 不动(纯按 §7.5 #5 #6 既有协议实施)
- RUN.md 加 ZCBOT_SANDBOX_BACKEND env 段 + 切 docker 的前置条件 + 集成验证路径
- unittest discover 12/12 PASS
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 16:13:16 +08:00
caoqianming
160e801ab0
Stage C Step 2: Docker per-user 容器池 + iptables blocklist 基底
...
- deploy/sandbox/Dockerfile: python:3.11-slim + tini + iptables + non-root uid via HOST_UID build-arg + 全套 requirements
- deploy/sandbox/init.sh: 6 段红线 IPv4 + ::1 + ZCBOT_PG_IPS 环境注入,任一规则失败 fail-fast
- core/sandbox/network.py: ensure_network() 创 --internal zcbot-sandbox-net
- core/sandbox/pool.py: SandboxPool 容器命名 zcbot-sandbox-<user_id>,per-user asyncio.Lock,
in-memory _last_active dict(Docker 23+ 移除 docker update --label-add),hardening flags
全套(read-only / tmpfs / cap-drop ALL + NET_ADMIN / no-new-privileges / pids/mem/cpu limit /
bind mount user_root → /workspace)
- core/sandbox/__init__.py: 公开 SandboxPool / container_name / setup_pool / NETWORK_NAME
Step 2 范围明确不含 AgentLoop 集成 / shell-run_python 切容器 / egress proxy / reaper task ——
pool 孤立 commit,Step 3 接入。本地 Windows 无 docker 走不动,Ubuntu 上 5 条 smoke 命令
(build / iptables 段 / non-root uid / read-only / 销毁)写进 RUN.md "Sandbox(Stage C,Ubuntu)" 段。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:44:34 +08:00
caoqianming
48f99cf66d
Stage C Step 1: Executor 接口骨架 + HostExecutor in-process backend
...
- core/executor.py: Executor ABC + ExecCtx(user_id/task_id/working_dir/cancel_check) + ToolResult
- core/executor_host.py: HostExecutor 包原 tools dict,统一三种错误为 ToolResult
- core/loop.py: AgentLoop 接 executor 而非 tools,_execute_tool_call 收成单条 call_tool 调用
- core/agent_builder.py: tools 装完后 HostExecutor(tools) 包一层,working_dir 透传 AgentLoop
接口形状与 DESIGN §7.5 #5 sketch (`call_tool(name, args, ctx)`) 完全一致,
backend 无关 —— Step 3 docker backend 接入时 AgentLoop 零改动,只换装配层。
行为零变化:smoke 4 分支(unknown/bad args/happy/schemas)全过,unittest 1/1 PASS。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 10:07:55 +08:00
caoqianming
d6af9a59fe
新增 patent skill + REVISIONS.md 修订日志机制
...
patent skill 写中国发明专利技术交底书,五阶段 workflow (素材摄取 → 挖点 → 检索 → spec → 逐章起草 → 自查渲染),BLOCKING 节奏同 proposal/ppt。复用 markitdown CLI + proposal scripts (render_diagrams/render_docx) + web_search/web_fetch + documents/research skill,零新增脚本;不实现 CNIPA 爬虫(维护成本高)。
REVISIONS.md 作为产物迭代 changelog,覆盖 proposal/patent/ppt 三个产物型 skill — spec = 宪法定调,REVISIONS = 每次卡点累加;单行 bullet 倒序追加,何时记/何时不记按 skill 领域定制(技术路线/区别特征/版式)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 09:34:01 +08:00
caoqianming
a6ae6c4647
在 DESIGN §7.5 末尾沉淀 Stage C 沙盒实施硬协议
...
把 §7.5 的原则具化成 6 条硬协议,Stage C 实施时按表对账而非凭记忆:
① 网络 blocklist 硬编码段(cloud metadata 169.254/16 / loopback / 内网三段 /
CGNAT,PG IP 单独再 block 一遍 belt-and-suspenders);
② egress proxy 模型(容器 HTTP_PROXY env + iptables DROP except proxy
端口防 SDK 绕 env;宿主侧 proxy 做域名 allowlist + 字节计量 +
network_audit 审计日志;allowlist 初始集列出 PyPI/GitHub/npm 等);
③ 进程组清理协议(docker exec 走 setsid + kill -- -PGID,防 nohup & /
disown 跨 exec 持久化破"同 user 不内隔离"残留风险假设);
④ 磁盘配额硬化时点(外部开放前必须升 xfs/ext4 project quota 或 zfs
dataset quota,否则扫描间隙打满共享 fs 拖死同节点其他 user);
⑤ Executor 接口走 backend driver + ZCBOT_SANDBOX_RUNTIME config 注入
(未来切 gVisor/Firecracker/e2b 应用层零改动,避免 Docker API 形状
泄漏到接口层);
⑥ 工具按信任域二分 dispatch — host in-process: read/write/edit/glob/
grep/load_skill/web_search/web_fetch(原本就在 host 持凭据 / 走
paths.py 校验,塞容器无收益付 200ms × N);container exec:
shell/run_python(执行任意代码必隔离)。
同时写死 gVisor / Firecracker-e2b / 容器内 tool-runner 三档升级触发信号
+ 不升级的反向兜底理由,防凭审美决策。
PROGRESS:状态表 §7 SaaS 行 + 下一步候选 #2 加锚指向新清单;时间估值
2-3 天 → 3-5 天;补 5 项 Stage C 完成 DoD 红队回归用例(metadata IP
timeout / PG IP block / nohup 残留 docker top 不见 / 跨 user 容器互访
阻断 / 非 allowlist 域名 403)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 09:00:16 +08:00
caoqianming
fe95df0b9d
Add web_search and web_fetch tools via Bocha AI search API
...
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-25 11:37:33 +08:00
caoqianming
ade7f3d1e1
Vendor markdown frontend assets
2026-05-25 09:31:36 +08:00
caoqianming
7a0d03fb29
Show upload progress
2026-05-25 08:54:06 +08:00
caoqianming
6e33f07bfb
Show pasted upload chips
2026-05-25 08:43:07 +08:00
caoqianming
f157a4e050
Add resizable web panes
2026-05-25 08:31:31 +08:00
caoqianming
f3017480d0
Show full file names on hover
2026-05-25 08:18:20 +08:00
caoqianming
3525399041
Fix task list scroll container
2026-05-25 08:06:33 +08:00
caoqianming
ae6b8630e2
ui: 手机端对话面板顶栏 + chat-meta 紧凑化 (5 按钮换行不竖排 + 模型 label 转 emoji)
...
- #pane-mid .pane-head 加 flex-wrap + 按钮 white-space:nowrap,
消除 "完\n成" / "废\n弃" 这种内部断行;藏 "对话" label / spacer
- #chat-meta 手机端 gap 8→6px,藏 .tid,.desc 限宽 60vw ellipsis
- 三个模型下拉 label 加 .mdl-text / .mdl-icon 双 span,
桌面文字 / 手机 emoji (💬 /🖼/🎬 ) CSS 切换,桌面零变化
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 16:00:52 +08:00
caoqianming
72ae0ded0a
feat(web): embed 模式接受 ?task_id=<uuid> URL 参数自动定位 task
...
首次签发 token / 已有缓存 token 两条进入路径都覆盖;
401 重签不重置选择,尊重用户中间 UI 切过的 task。
EMBED.md URL 参数表 + 故障兜底同步更新。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 15:27:19 +08:00
caoqianming
758486e2cd
feat(quotas): 媒体生成每账号每日上限 (默 20 图 / 5 视频, yaml 可配)
...
config/agent.yaml 加 quotas 段;core/storage/usage.py 加 check_daily_quota
(COUNT usage_events WHERE user_id+kind+created_at>=本地今日 00:00);
SeedreamTool / SeedanceTool ctor 收 daily_limit, execute() 起手 if 超额
返 [Error] 不调远端不烧钱。错误串只暴露已用/上限 + 重置时间,不写
yaml 路径 (避免 LLM 转述泄漏内部 schema 给外部用户)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 15:21:39 +08:00
caoqianming
84388b278e
ui: "+ 新建任务"按钮改通栏单独一行 (windows 320px pane 不再换行)
...
挪到 #pane-left 第一行 pane-head 之下的独立行,flex:1 撑满整行(primary 红底
通栏 CTA)。原塞 spacer 之后,中文五字在 320px pane 被挤断行。顺手删 @media
phone 里 #hd-new 紧凑覆盖(通栏不需要缩)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:44:30 +08:00
caoqianming
5e27ea9424
ui: "+ 新建任务"按钮从 header 挪到任务面板 pane-head
...
语义更贴(任务面板的动作);顶栏减负只剩身份区(brand/who/logout);两种模式
DOM 一致,顺手删了 embedInit 里动态 insertBefore 那段。文案保留完整"+ 新建任务",
样式加 small 跟周边对齐高度,保留 primary 红底显眼。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:40:49 +08:00
caoqianming
76f4c45350
feat(web): dev.html 加 iframe embed 模式 (?embed=1&parent_origin=...) + EMBED.md
...
embed 模式藏左上 brand / 用户名 / 退出登录,桌面整层 header 移除,移动端保留
header 给 mobile-tabs;"+ 新建任务" JS 移到任务面板 pane-head。postMessage 双向
握手:iframe 发 zcbot-ready / zcbot-401,父端回 zcbot-token{token,user_id,
user_name?};双向 event.origin 校验(parent_origin URL 参数白名单)。401 改写
logout 不 reload,而是通知父端 + 显灰底 spinner 等待层。复用已有 /v1/auth/login
SSO 入口,platform 后端 PLATFORM_KEY 代换 JWT,不下放浏览器。EMBED.md 写给
platform 工程的对接手册(URL / 协议 / Node+Python 后端示例 / 父端前端示例 / CORS
+ CSP frame-ancestors 收紧建议 / 调试 + 故障兜底)。
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 14:32:16 +08:00
caoqianming
d6cbe8194b
ui: chat-input 支持 Ctrl+V 粘贴文件上传 + chat-hint 反馈
...
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-22 13:59:53 +08:00