caoqianming
|
1581b69bfa
|
fix(run_python): 超时返回超时前的部分输出 + 无缓冲(-u),模型据此续跑不整批重来(bump 0.58.36)
失败面板 #8(command timed out 19 次/7 task,累计最多)。定性(查 19 条超时的原始
tool_call 代码):不是死循环/chromium 老坑,全是真慢的批量 I/O——① 论文检索
skills.research.paper.search() 循环搜多期刊/关键词(最多,每次打 OpenAlex 累计爆超时)
② pdfplumber 多 PDF extract_text ③ 大文件下载 ④ pandas 大 Excel。超时机制正常,真正
浪费在 _run_subprocess 超时分支把已捕获的部分输出全丢了(kill 后 communicate() 已续读
超时前 stdout,却只回一句 command timed out → 模型看不到"搜到第6个"、整批重搜)。
修:
1. tools/base.py::format_timeout_result 把超时前 stdout/stderr 一并返回 + 续跑提示
(据已完成部分续跑/每项落盘/大操作用 background=true/单次别塞太多),docker
(_run_subprocess)+ host(run_python TimeoutExpired.stdout/stderr)两执行器共用。
2. -u 无缓冲:Python 管道下 stdout 块缓冲,不 flush 的 print 超时被 kill 时缓冲区就丢,
故 run_python 的 python 调用全加 -u(docker 前台 inline/script_path + host 前台 +
两处后台 procs.launch_host),让部分输出真正落管道被捕获(不碰 shell)。
提示指路(background/续跑)与语法预检不同、恰当:超时是"你这段太慢"的确定信号,
建议对任何超时都可靠。不做:不抬默认 timeout(120s 合理);不单独改 prompt。
测试 tests/test_timeout_partial.py(format 单测 + host 端到端:print 两项后 sleep
timeout=1 → 结果带两项 + 续跑提示)+ test_executor_docker argv 断言更新为 python -u,
全 34 相邻测试绿。additive(超时结果加信息不破坏 schema),不碰对外契约。至此失败面板
top 全部处置(② edit streak/③ 畸形/① SyntaxError 预检+渲染器/#8 超时)。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-17 10:53:14 +08:00 |
caoqianming
|
2a60243c02
|
feat(run_python): 宿主语法预检——中文正文硬拼进源码的语法坏码提前拦下+锐化诊断(bump 0.58.34)
工具失败面板最大头(run_python/exit SyntaxError,20 条真实样本):模型手写
python-docx 生成 docx/报告时把中文正文内联进 T("中文…"),引号/标点崩坏 →
SyntaxError → 改 → 再崩,同一文件一分钟连撞 6 次烧 token。三类:
- A 引号提前闭合(最多):中文串里 ASCII 引号 " 提前闭合外层字符串,Python 却报
"forgot a comma?"/"unterminated string" 主动误导,模型照着加逗号越修越错。
- B 全角标点漏进代码位(center=True、/采购():invalid character U+XXXX。
- C 括号/引号结构崩。
根因不是缺写长文工具(write 早能写长文进文件),而是 docx/报告无渲染管线——
documents skill 只做检索、不管 docx 生成,模型裸手撸 python-docx 内联中文;ppt 有
SVG→pptx 管线故崩得少。本轮先落机检止血(硬约束靠平台机检,不塞菜谱):
新增 core/pysyntax.py(不 import litellm,本机可测)precheck_python(code):host 上
compile()(host 3.12 ≡ sandbox python:3.12-slim,零版本偏差;只解析不执行、与依赖
无关),命中 SyntaxError 返锐化中文诊断(出错行+光标+按错误类型定向:invalid-char→
全角改半角、forgot-comma/unterminated+含中文→ASCII 引号提前闭合三改法、含中文统一
追加"正文别拼进 .py,write 进 .md/.txt 再 read"根治提示)。接进 run_python 所有派发
路径(inline/script_path/background × docker+host 两执行器,_prepare_script 内嵌覆盖
script_path 全路径 + inline 分支各加一处),命中即早返、跳过 docker 往返。
零误伤:只拦本就跑不了的码(compile 不过=运行必失败),通过原样放行、行为不变;
既有 30 个 executor/run_python 测试(合法码 fixture)全绿印证。白捡协同:预检把语法
失败从 [stderr]…[exit 1] 改成 [Error] 前缀+固定首行,loop._RepeatGuard 的 err-streak
(0.58.33)得以兜住"反复交语法坏码"的循环(旧 [exit 1] 形态它抓不到)。
测试 tests/test_pysyntax.py 11 用例(A/B/C + 合法中文串/中文引号不误伤)全绿。
下一步(未做,单列选型):docx 渲染管线,正文 write 进纯文本文件→渲染工具 read 生成
docx,正文永不进 Python 源码、也不走大正文当工具入参(避免触发 0.58.33 修的 wire
乱序畸形)。additive 内部机制,不碰对外 API/DB 契约。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-07-17 08:55:55 +08:00 |
caoqianming
|
732420a3b7
|
fix(exec): run_python script_path 宿主预检+前缀容错+code 落盘回退(bump 0.58.22)
失败聚集 run_python/exit「can't open file」15 次/7 天/13 task,DB 逐条核对三形态:
- 没写就跑(13/15):Docker 执行器补宿主侧 is_file 预检,返带纠偏提示的
[Error] script_path not found,与 host 执行器对齐,不再进容器撞裸 stderr
- 双重拼接:fs 工具输出渲 user_root 相对路径而解析按 workdir 相对(展示/解析
不对称),模型回传即踩坑;workdir 相对不存在时按 user_root 相对再试
- code+script_path 同给:文件不存在时 code 落盘到 script_path 再执行,
不再扔掉完好的 code(schema 描述同步注明)
_container_script_path 重写为 _prepare_script(前台+background 共用,code
回写在宿主侧故加 user_root 越界防护);tools/run_python.py host 路径同语义。
测试 +8;诊断脚本 scripts/diag_run_python_noent{,2}.py 留档。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-13 16:41:43 +08:00 |
caoqianming
|
daf0db854a
|
feat(procs): 后台进程 bg proc + 对话锁/完成通知 + seedance 续查(bump 0.56.0)
- shell/run_python 加 background=true(模型判断,>~1min 走后台):进程 detach 独立运行,
不受工具超时/服务重启/蓝绿切换影响;新 check_process 工具查状态/日志尾部/终止
- 状态协议纯文件(<user_root>/.zcbot_procs/<task>/<proc>/,exit_code 出现即终态,
无 DB 无队列组件):host=stdlib wrapper detach(限时+杀树+日志截尾 10MB);
docker=专用容器 zcbot-proc-*(同款硬化+iptables,product=proc 与 sandbox
reaper/shutdown_all 生命周期解耦);web lifespan 每小时 sweep(7d TTL+孤儿容器)
- web:GET /v1/procs(用户级)+ POST /v1/tasks/{id}/procs/{pid}/kill;前端
[Background] 工具卡活化(spinner/跳秒/停止,历史重渲恢复)+ 完成 toast(跨 task
可跳转)+ 对话锁(bgproc 运行期 composer 发送→停止/Enter 拦截,先锁后放消
刷新时序窗口;润色/语音与 streaming 期一致可用)
- seedance:resume_task_id 续查(轮询超时/中断后取回结果,跳过提交不重复计费),
fast/pro poll_timeout 统一 1200s;取消/超时文案引导续查
- core/llm.py:litellm timeout 显式化(默认 600s 不变,ZCBOT_LLM_TIMEOUT_S 可调)
- DESIGN 新增 §8.12(含边界:不做 job 链/自动续跑/不引 Celery);RUN/PROGRESS/
CHANGELOG 同步;scripts/test_bgproc_manual.py 手工验证;unittest 全量 201 过
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-10 16:47:11 +08:00 |
caoqianming
|
022eade18d
|
feat(research): paper_server 接口对接 API Key(bump 0.39.2)
paper_server GET 接口收紧要 Key:paper.py 全部请求带 ?api_key=
(env PAPER_SERVER_API_KEY),认证失败(服务端异常处理器压成
HTTP 400 + err_code)转带指引的 RuntimeError。这把低价值只读 key
是唯一刻意进 sandbox 的凭证:run_python env 过滤器加 allowlist
放行,docker 模式 _sandbox_env() 透传进容器(顺带修掉
PAPER_SERVER_URL 覆盖不进 docker 的缺口)。SKILL/RUN/PROGRESS
同步更新。
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
2026-07-06 11:15:51 +08:00 |
caoqianming
|
1c30a9e54e
|
Reduce chat context token usage
|
2026-06-04 16:41:14 +08:00 |
caoqianming
|
42755e246e
|
fix(sandbox): shell 也注入 PYTHONPATH + HOME=/tmp(修只读 rootfs 两副作用)
容器 --read-only rootfs 下两个副作用:
- PYTHONPATH 原先只 run_python 注入,shell `python -c "from skills..."` 撞
ModuleNotFoundError
- /home/zcbot 不可写,matplotlib/fontconfig 往 ~/.config / ~/.cache 写缓存刷
"Read-only file system" / "No writable cache" 噪音
抽 _CONTAINER_ENV = {PYTHONPATH, HOME=/tmp},shell/run_python/fs 三路共用
(-e 确定性覆盖)。HOME=/tmp 一刀让缓存落 tmpfs(matplotlib→/tmp/.config、
fontconfig→/tmp/.cache),免逐个 MPLCONFIGDIR/XDG_CACHE_HOME。纯代码改,
重启 web 生效,免重建镜像。
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
2026-06-04 14:12:53 +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
|
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
|
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
|
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 |