Commit Graph
225 Commits
Author SHA1 Message Date
host 56b8f98b47 perf: Chromium 启动 flag 微调 + screencast 画质 q60->q50
Flag:加 --no-first-run、--no-default-browser-check、
--disable-default-apps、--disable-extensions、
--disable-background-networking、--disable-sync、
--disable-translate,只跳过首跑/装配活,不改渲染与工具
行为。实测(runsc 容器,launch + new_page,各 3 次交替):
旧中位数 0.889s、新 0.819s——只差 70ms 且在逐次噪声
(0.70-0.99s)里,几百毫秒的预期不成立;零成本顺手留着。
画质:screencast 与 eager 抓帧 q60 -> q50,分辨率
1280x800 不动,点击坐标系不受影响。实测同页文本+渐变:
62068 -> 56428 字节(-9%),不是经验法则的 30%;觉得糊
一句话改回 60。
2026-10-30 14:27:04 +08:00
openqj 878f8de7da Merge pull request #190 from openqj/feat-remote-perf2
perf: 小优化组 + 恢复浏览器页签
2026-10-30 14:17:03 +08:00
host cbf5e65a7a perf: 小优化组 + 恢复浏览器页签
1. MCP 空闲睡眠 50ms -> 10ms:#187 后单轮 drain 约 0.3ms,
   100 次/s 空闲迭代约 3% 单核,请求与远控输入拾取延迟
   从平均 25ms 降到 5ms。
2. stream 轮询 50ms -> 20ms。
3. stream payload 加 url/title;面板 stream 处理合并 url/
   title,5 秒 state 轮询只在未观看时跑(观看时 stream 已
   全量覆盖,轮询纯冗余;不观看时保留轮询,避免会话开始
   后页眉 stale)。
4. 恢复浏览器页签:#176(ccb5a86)改写 TaskDetailPanel
   页签时顺带删了 BrowserPanel 的挂载,导致线上控制台
   自 #176 起就没有浏览器页签(面板文件一直在,只是不
   被 import,构建产物因此不变)。本次把 import、页签
   与 Card 原样挂回;构建产物含“开始观看”标记可证。
console.html 由 npm run build:console 重打(342484 字节)。
console-redesign/ 为构建脚本审阅产物,不进仓库。
2026-10-30 14:09:02 +08:00
host 885bf38790 feat: add software-engineering skill v0.2
Add cloud/skills/software-engineering/SKILL.md (686 lines, v0.2, appendix with 9 role templates travels inside SKILL.md because skill_seed only copies SKILL.md, not templates/). Update skill pack tests: EXPECTED set and real-pack list now include software-engineering, plus an explicit seed test asserting it lands at skills/software-engineering/SKILL.md, contains the appendix, and tenant edits are never overwritten. One-line wording tweak in the architect template avoids the existing secret-scan false positive on the substring sk- inside agent-task-contract.md; deployed file sha256 bd0436399ac05c6131b9281dad00973e50d13540e4c56ad21f21e2b5209bae8e (40759 bytes, 686 lines).
2026-10-30 06:00:31 +00:00
host fafc0734c7 perf: screencast 隔帧改每帧,跟手优先
Page.startScreencast everyNthFrame 2 -> 1,画质 q60、尺寸
1280x800 不动。静态页不产生额外成本(帧只在重绘时来,
且 #187 起桥只写变化的帧字节);收益全部落在真正需要跟
手的时候:滚动、拖拽、动画期间帧率翻倍。测试断言同步。
2026-10-30 13:50:18 +08:00
host 910168126d perf: 桥变化才写、stdin 优先、stream 50ms 轮询
1. 桥写放大:旧代码每 ~50ms 轮询都无条件重写 state 和帧
   文件(约 40 次原子 temp+replace/s 走 runsc gofer,
   泵持久返回同一帧、updated_at 每轮都变,字节其实不变)。
   现帧字节不变不写;state 只在 url/title/started/holder/
   streaming 变化时写,或 0.5s 心跳一次(判死阈值 30s,
   绰绰有余);静态页写量从 ~40次/s 降到 ~2次/s。
2. MCP 主循环 stdin 优先:旧循环先 drain 再读 stdin,
   每次工具调用都先付一轮文件 IO。现 pending 请求先处理,
   空闲轮询 drain,忙时 200ms 保底 drain 一次防饿死。
3. stream 轮询 200ms → 50ms,画面延迟下限随之下降。
附回归测试:无变化轮询不重写、帧变化立即写、holder
变化绕过节流立即写。
2026-10-30 13:36:24 +08:00
host 2d840a6c37 fix: navigate 后立即推一帧,静态页开流不再等重绘
screencast 帧只在重绘时来,页面可能在 startScreencast 之前
就已画好——静态页于是开流后一直无画面,直到下一次重绘。
navigate 后用 CDP captureScreenshot 抓一张当前视口塞进帧
队列,泵在下一轮就把桥帧文件写出来;泵跳过空 session 的
ack(eager 帧没有可确认的 screencast 帧)。失败静默,
screencast 本身仍照常流动。
2026-10-30 13:14:38 +08:00
host ccb5a8638d feat: 任务详情 LLM 请求数(cost_records 存 completions) 2026-10-30 12:58:41 +08:00
openqj 2ff8975f43 Merge pull request #183 from openqj/feat-browser-filebridge
fix: 浏览器远控传输层改文件桥(Unix socket 在 runsc 下宿主不可见)
2026-10-30 07:35:46 +08:00
host 6bcdeb8da1 fix: 浏览器远控传输层改文件桥(Unix socket 在 runsc 下宿主不可见)
根因(2026-10-30 活体实证):#181 的 .browser-remote.sock 假设
宿主能连容器内 socket,但生产 Docker 任务走 runsc/gVisor,
其 gofer 挂载下容器内建的 socket 只在容器内可见,宿主目录
里只有普通文件(browser-live.png 一直能透传)。后果:server
代理对真实任务一律 503,会话根本没活过。

修法:传输层改四个普通文件(worktree 内,原子写 + 追加日志):
- .browser-remote-state.json:MCP 每轮重写,mtime 即存活信号,
  server 判 30 秒无心跳为会话死亡(503);
- .browser-remote-frame.jpg:最新 screencast 帧(base64 文本);
- .browser-remote-input.jsonl:server 追加,MCP 按偏移量消费
  完整行,执行时再判 holder,半行等下一轮;
- .browser-remote-control.json:{holder, seq},MCP 首轮即应用,
  接管可先于浏览器启动。
- holder 竞态:control 写下后 state 文件约 50ms 才刷新,server
  的 input/stream 改判 effective_holder(控制文件 mtime 新者胜),
  否则接管后立刻点会误 409。
- 线程契约与控制权模型不变;MCP 主循环仍是唯一触页线程。
- 播种刷新(#181)让老租户自动拿到新版脚本。

测试:socket 测试改文件桥测试(桥轮询/偏移量/半行/陈旧态/
effective_holder + server 代理全链),全量 1357 项通过(skipped 4)。
2026-10-30 07:28:32 +08:00
host e81ba8d2bf feat: 会话内 LLM 自判 goal / 自动化标记工具,不靠关键词
agent 在回合输出里写 goal-convert 块,worker 在轮次边界
排成 /goal 自后续消息、走已有 followup 转换路径把本会话
转成 goal;写 automation-create 块,worker 在轮次边界
创建自动化定义(权限 create_task、配额整轮门、创建人跟
父任务走、name 缺失自动生成、首次时刻已过去单块拒绝、
bind heartbeat 可绑回本会话)。

automations 新增 first_run_at / run_once:首次时刻只管
首次、之后按间隔算;只跑一次跑过后 is_due / due / claim
三处都不再到期(SQL 到期条件与 Python 口径共用同一
_DUE_SQL);API 创建与更新同步接受这两个字段。

刻意不向 LLM 自动注入工具指南:避免 prompt 臃肿,格式
只写进 docs/marker-tools.md 与 README,需要时由用户在
会话里手动告诉 agent;服务端不按关键词再猜意图。

单测 cloud/tests/test_session_goal_automation.py 12 项,
相关回归 218 项全过。
2026-10-30 07:15:05 +08:00
host f1aab5415c feat: 不用斜杠,单发 goal 也触发 /goal 目标
触发词从仅 /goal 放宽到 /goal 或裸 goal(大小写不敏感,
单数 only,goals/mygoal 不算):goal 收xxx、goal,目标是
收xxx、发goal 收xxx 均同款触发,新建与主线转换入口共用
同一解析。讨论句式仍不触发:goal 的用法、goal 是什么、
讨论goal的用法、/goal的用法 均返回 None。
单测补 4 项:裸 goal 触发、裸 goal 讨论不触发、followup
裸 goal 转换、新建裸 goal。
2026-10-30 07:15:05 +08:00
host f3bd65c171 feat: 新建任务的 prompt 里写 /goal 也自动变 goal
上一提交只覆盖了已有主线的转换,新建任务的 prompt 里写
/goal 时仍会当成普通一轮任务跑。本提交补上 POST /tasks
入口:prompt 经 cloud/goal_command.py 解析后,目标即新任
务的 prompt 与 goal,goal_mode 强制为 1(命令优先于 body
里的 goal_mode=0),plan/验收命令冲突仍按新建规则 400,
空目标 400 不建任务;讨论里提到 /goal 不触发。
单测补 5 项:/goal 直写、整句、空目标、plan/验收冲突、
讨论 prompt 不变。
2026-10-30 07:15:05 +08:00
host 3096e04345 feat: 主线 /goal 命令自动建 goal
发给主线的一句话(含字面 /goal)即可自动建 goal,不用先
知道主线是进行中还是已终态,也不用勾选项:
- cloud/goal_command.py:server 与 worker 共用的纯文本解析,
  只认命令形状(/goal 开头、分隔符/目标标记、开启类动词),
  讨论里提到 /goal 不误触发;空目标返回空串供调用方 400。
- server followup/thread/message/continue 三入口同款:queued
  原地转 goal,已终态复活并转 goal,running 排队后由 worker
  在轮次边界转 goal;已是 goal 409、plan 400、merged 409。
- worker 排空:/goal 不当普通轮次跑,CAS 把 running 主线
  改回 queued 并写 goal/resume_message,下次认领走 goal-resume
  在同一 thread 上开新目标循环;取消/回收时 CAS 失败则把
  followup 放回 pending,绝不把取消过的任务改回 queued。
- 单测 14 项:解析、三态转换、拒绝口径、普通消息不受影响、
  continue/thread 同款、worker 轮次边界转换 + 下次 goal 跑通。
2026-10-30 07:15:05 +08:00
host 7589876cff feat: 控制台浏览器远控面板
- TaskDetailPanel 新增“浏览器”页签,内嵌 BrowserPanel。
- 开始观看:fetch + ReadableStream 读 SSE(EventSource 发不出
  X-API-Key),最新帧以 data URI 显示;状态每 5 秒轮询。
- 接管/交还:POST /browser/control;接管后点画面按 1280x800
  换算坐标 POST /browser/input,键盘直达页面。
- 产物:cloud/console.html 由 vite 单文件构建重打(341451 字节,
  含 browser/state 与“浏览器远控”标记)。
2026-10-30 07:01:48 +08:00
host 6f39ab3945 feat: 浏览器二期后端:远控服务 + ref 快照 + server 代理
- playwright_remote.py(新):MCP 进程内 Unix socket HTTP 服务,
  监听 worktree/.browser-remote.sock;GET /state、GET /stream
  (SSE 画面流)、POST /input、POST /control(接管/交还)。
  线程契约(实测):Playwright 同步调用只能在创建页面的线程,
  所以 HTTP 线程只读属性/读最新帧/入队,MCP 主循环用
  select 轮询(50ms) draining 输入并 pump screencast 帧
  (无 ack 则 CDP 首帧后停流)。
- 画面流走 CDP screencast 帧(学 chrome-devtools-mcp),不用
  定时截图;ffmpeg 录像暂不做。
- snapshot_refs/click_ref(学 playwright-mcp 的 ref 机制)+
  mouse_move/key_press/type_text;agent 工具在 holder=user 时
  直接报错,等用户交还。
- server.py:/tasks/{id}/browser/{state,stream,input,control}
  代理到 worktree socket,复用任务鉴权与 worktree 解析;
  会话不存在时 503(轮次结束即消失是设计)。
- 播种器:MCP 脚本是系统文件,版本变化时刷新老租户旧脚本
  (script_refreshed 打日志),否则远控只对新项目生效;
  新增 playwright_remote.py 进播种清单。
- 队列遮蔽修复:cloud/queue.py 会遮蔽 stdlib queue,改用
  SimpleQueue(deque+锁),仓库模式与 flat-copy 两路都通。
- 测试:新 20 项(remote 服务、server 代理、ref/输入/
  screencast fake),全量 1354 项通过(skipped 4)。
2026-10-30 06:44:24 +08:00
host 814fe8f7c2 feat: 浏览器一期:坐标点击 + live 截图
- browser_click_at(x, y):视口坐标点击(1280x800、左上角
  原点),越界与非数字拒绝;live 视图里用户在截图上的
  点击落点就走这个工具。
- browser_live_shot:固定文件 browser-live.png + 状态
  sidecar browser-live.json(URL/标题/时间戳),watcher
  轮询一个稳定路径即可;技能要求每次动作后都调一次,
  保持画面最新。
- MCP 新增 browser_click_at / browser_live_shot 两个工具;
  技能补 live 视图一节;测试 9 项(含 fake mouse、越界、
  live 文件与状态读回)。
2026-10-30 06:19:55 +08:00
openqj cb6de0e3aa Merge pull request #178 from openqj/feat-playwright-mcp
feat: 浏览器自动化 MCP(Playwright)
2026-10-30 05:39:27 +08:00
host cd3952590b test: 技能播种清单期望集加 browser-automation 2026-10-30 05:30:58 +08:00
openqj 58cbb198cf Merge pull request #177 from openqj/feat-project-todos
项目待办 + LLM 标记工具:todos 接口、控制台待办页、todo/task-list/cost/files 标记与首轮注入
2026-10-30 05:22:54 +08:00
host f67867694f test: 技能清单期望集加 browser-automation 2026-10-30 05:22:25 +08:00
host c9a483282d feat: 浏览器自动化 MCP(Playwright)+ browser-automation 技能
- playwright_browser.Browser:单页 Chromium,navigate /
  snapshot(正文 8000 字截断标记)/ click / fill / evaluate /
  screenshot(工作区内)/ close;启动参数 --no-sandbox +
  --disable-dev-shm-usage(runsc + 1003 用户实测必需),
  代理显式传给 launch(Chromium 在 Linux 下不稳定地读 env
  代理),浏览器路径 PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright。
- playwright_mcp:stdio MCP,7 个 browser_* 工具,同一进程
  单 Browser 实例;测试用 fake browser / fake factory。
- worker:--playwright-mcp flag,_tenant_dirs 播种两个脚本 +
  [mcp_servers.playwright],_prepare_tenant 写 env(代理 +
  浏览器路径,MCP 子进程不继承 Codex 进程 env,镜像 ENV
  在此必须重写,缺了会报 Executable doesn't exist)。
- 技能 browser-automation:JS 页、翻页、表单、截图时用,
  静态页优先 web_fetch / web_search;截图须 PIL 读回验证。
- 镜像(层构建,非本 PR):FROM latest + fonts-noto-cjk +
  playwright + chromium(npmmirror)+ install-deps,3.77GB;
  runsc + 1003 + docker-codex 条件下 JS 执行、example.com
  标题、截图均已实测通过。
2026-10-30 05:14:09 +08:00
host 9d6430a4d0 成本配额与文件只读标记:task-cost/quota-status/task-files 2026-10-30 05:11:06 +08:00
host 2fd73c1121 任务列表 task-list 标记 + 首轮项目上下文注入 2026-10-30 05:11:06 +08:00
host 73288f08db 待办:todo-list/create/update 标记工具 + 首轮未完成待办注入 2026-10-30 05:11:06 +08:00
host b3b3b35042 待办:项目待办模型 + /projects/{id}/todos 接口 + 控制台待办页 2026-10-30 05:11:06 +08:00
host 60283d55fc feat: 经验复用 MCP 暴露——项目记忆列/建/废弃(注入与提取已存在,不重复造) 2026-10-30 05:01:44 +08:00
openqj c10fda4e4a Merge pull request #174 from openqj/feat-repo-access-multi
feat: 仓库接入通用化(批量预检 + 多仓 ssh 别名)
2026-10-30 05:01:13 +08:00
openqj 6d49b72a9c Merge pull request #173 from openqj/feat-docker-sandbox-strict
feat: Docker 沙箱 /tmp tmpfs 隔离 + 可选根只读
2026-10-30 05:01:09 +08:00
openqj 8d7651b0b7 Merge pull request #172 from openqj/feat-metrics-extended
feat: /metrics 可观测性扩展
2026-10-30 05:00:53 +08:00
host 50ba8d9297 feat: 仓库接入通用化——批量预检 + 多仓 ssh 别名配给 2026-10-30 04:18:09 +08:00
host 49fc27eef1 feat: Docker 沙箱 /tmp tmpfs 隔离 + 可选根只读(内层 bwrap 本体不在本仓修复范围) 2026-10-30 04:17:09 +08:00
host c168304418 feat: /metrics 扩队列深度/worker 聚合/分模型成本/未定价占比/近24h失败 2026-10-30 04:15:54 +08:00
host b71cff5ee2 feat: 云端 MCP 工具 12→20(pause/goal-resume/followup/agents/workers/metrics/members/models) 2026-10-30 04:15:16 +08:00
openqj 0787496427 Merge pull request #170 from openqj/feat-image-edit-mcp
feat: 图片改图 MCP 工具 image_edit
2026-10-30 04:12:46 +08:00
openqj 09880e8f4e Merge pull request #79 from openqj/feat-app-max-permissions
feat: GitHub App manifest 扩到主机最大权限
2026-10-30 04:11:13 +08:00
host e13a95067c feat: 图片改图 MCP 工具 image_edit
- imagegen.edit:POST multipart /v1/images/edits,输入图
  必须是工作区内 plain basename 且存在(上限 20MB),产出
  必须是新文件、绝不覆盖输入;响应解析与 generate 共用
  _save_image_response(url 或 b64_json、下载落盘、格式探测)。
- imagegen_mcp 新增 image_edit 工具;image-workflow 技能
  改图分支从“无专用工具”改为用 image_edit。
- 测试:multipart 体含提示词与原图字节、输入缺失/同名/
  路径逃逸拒绝、MCP 列表含 image_edit;全量相关 16 项过。
实测依据(2026-10-30):中转站图片分组 key 调
gpt-image-2.5-flare edits 返回 200,URL 图为真实 PNG
1024x1024、909K,usage 含输入图 token(1659 image tokens)。
2026-10-30 04:05:00 +08:00
host 44b080971e console: 重排版为侧边导航 + 三栏工作台 + 任务详情内页签
旧排版(顶栏页签 + 数据卡片置顶 + 长页堆叠 + 详情卡片堆在对话下)全部去掉,功能不变:
- 左侧栏:导航按任务/管理分组,底部紧凑概览卡片始终可见;整页不再单页长滚动,各 pane 各自滚动
- 任务工作台:左任务列表轨(搜索/筛选/分页),中派发(可收起)+ 单列对话,右任务详情检查器
- 详情检查器:概览/协作/评审与审批/线程四个内页签,一次只显示一组
- 其余功能各成独立页面:项目与成员、环境与 Workers、技能与自动化、系统与 Key
- 视图同步到 location.hash(#view-tasks 等)

构建:npm run build(tsc + vite singlefile)通过,产物 332130 字节;本地全量 cloud 1275 项全过(skipped 4)。
2026-10-30 03:22:02 +08:00
host 7a920cee59 fix: imagegen MCP env 必须写死本地网关 base URL
首轮生产验收失败根因:_prepare_tenant 只把 IMAGE_GEN_* 透传
进 MCP env,没写 IMAGE_GEN_BASE_URL,也没带 SUB2API_BASE_URL,
于是 imagegen.py 回落到公网 sub2.diante.me,而它不在
Tinyproxy 白名单里,API 调用 403 Filtered。
修法:worker 在写 MCP env 前用 imagegen.build_mcp_env 算好
base(显式 IMAGE_GEN_BASE_URL > SUB2API_BASE_URL),并把
网关 host 加进 NO_PROXY;组装逻辑抽成可单测 helper,新增
2 项回归测试(本地网关解析、显式 base 优先)。
2026-10-30 03:07:31 +08:00
openqj da7b8e3a4f Merge pull request #167 from openqj/feat-imagegen-mcp
feat: 图片生成 MCP 工具 image_generate(中转站图片分组)
2026-10-30 03:03:07 +08:00
openqj cf6721f427 Merge pull request #163 from openqj/feat-docker-timeout-evidence
feat(docker): 超时不再只剩一句 docker run timeout,留存 partial 与容器日志
2026-10-30 02:54:30 +08:00
openqj 27ca53465e Merge pull request #162 from openqj/feat-task-result-full
feat(tasks): 完整结果另存 result_text_full,详情不再只剩 2000 字
2026-10-30 02:54:21 +08:00
host 8fc4e27241 feat: GitHub App manifest 全量获取:仓库/组织/企业/账号四类最高档
接上轮仓库最大权限:用户明确要求无论什么身份,取该身份
授权范围内的所有权限。manifest 现按四类全拉满(74 项权限、
39 个事件):仓库补 codespaces_lifecycle_admin、repository_
creation、metadata 只读;组织 members 升 write 并补
organization_administration 等 15 项;企业补 8 项;账号补
blocking、email_addresses、gists、密钥类等 22 项。
身份边界写进注释:GitHub 只授予安装身份能给的那部分,个人
装不上组织/企业、企业装不上仓库/组织;换 token 不传子集,
token 本就是安装全量;企业安装另需 App 公开/内部
(GITHUB_APP_PUBLIC=1)。诚实边界:企业类键名未用真实
GitHub 建 App 实测,新建时表单会校验,某键被拒删键再建,
线上旧 App 不受影响。
2026-10-30 02:53:46 +08:00
host 668c000394 feat: GitHub App manifest 扩到主机最大权限
仓库权限除 metadata 外全部拉到最高档(contents/pull_requests/
issues/actions/checks/workflows/administration 等全部 write,
members 只读),事件补齐 push/check_run/workflow_run 等;
旧权限 contents/pull_requests write + issues read 不再是上限。
风险明示:administration=write 含删库/转移,secrets=write
含管理 secret,配 All repositories 时影响面为全账号仓库。
注意:改代码只改以后新建 App 的 manifest,线上 App
(id 5476837) 仍需在 GitHub 设置里改权限并接受新权限。
2026-10-30 02:53:46 +08:00
host 33bd14638f feat: 图片生成 MCP 工具 image_generate(中转站图片分组)
- cloud/imagegen.py:POST /v1/images/generations,解析 url 或
  b64_json,下载落盘到工作区;basename 校验防路径逃逸;
  缺 IMAGE_GEN_API_KEY 时明确报未配置,绝不回退任务自己
  的分组 2 key(分组 2 allow_image=False,回退只会 404)。
- cloud/imagegen_mcp.py:stdio MCP,工具 image_generate。
- worker --imagegen-mcp:租户 codex-home 播种脚本与
  [mcp_servers.imagegen],容器启动前写 env(系统级
  IMAGE_GEN_* + 代理 + NO_PROXY 网关 host)。
- image-workflow 技能:有 image_generate 时用它生成,
  无工具或报未配置时明说无法生成;改图暂无专用工具。
- 测试:imagegen 9 项 + worker 播种/env 3 项。
实测依据(2026-10-30):分组 4 key 调 gpt-image-2.5-flare
返回 200,URL 图为真实 PNG 1024x1024;此前分组 4 账号
schedulable=False 时全模型 404,调度开启后恢复。
部署注意(主机侧,不在代码里):env 需配 IMAGE_GEN_API_KEY;
Tinyproxy 白名单需加 qinglanapi.top(下载返回图 URL 用);
autoscaler 需加 --imagegen-mcp。
2026-10-30 02:53:30 +08:00
openqj 4bbe6a99e3 Merge pull request #164 from openqj/feat-cloud-mcp-more
feat(mcp): 云端 MCP 工具从 8 个扩到 12 个
2026-10-30 02:47:36 +08:00
openqj 367b9d8873 Merge pull request #161 from openqj/feat-automation-audit-pg
fix(automations): 审计行不再显式插 TEXT id,PG identity 下不再丢审计
2026-10-30 02:47:28 +08:00
host 6e78449994 feat(docker): 超时不再只剩一句 docker run timeout,留存 partial 与容器日志
2026-10-29 任务 A 教训的收尾:超时路径直接 kill+rm,
--rm 容器一删日志就没了,事后只剩一句 timeout,复发无法
定位(#157 只补了 worker 终态审计,没补容器侧证据)。
修法:_docker_timeout_evidence 先 kill 不 rm,抓 docker
logs 尾 200 行,再 rm;同时取 TimeoutExpired 自带的
partial stdout/stderr(旧代码直接丢了)。三步都 best-effort,
任一步失败都不影响返回 failed。dispatch 与三条 goal 路径
(goal/goal-resume/goal-resume-breakpoint)四处超时点同款
处理:stdout = timeout + partial(优先)或 logs,另存
container_log_tail 与 timeout_partial_stdout 字段;--rm
命令本身不动,不留僵尸容器。
单测 test_docker_sandbox 31 项(含新增超时证据 1 项,
在两个测试类里各跑一次)。
2026-10-30 02:47:11 +08:00
host 700641fa37 fix(worker): 无 result_text_full 列的老库/手工表写回回落,不拖垮终局
CI 失败根因:P0 取消守卫测试 mock 掉 _ensure_result_columns
并手工建表(无新列),带新列的 UPDATE 直接
OperationalError。修法:带新列写回失败且错误含
result_text_full 时回滚并用旧 SQL 重写(摘要照写、完整版
丢弃),其它错误原样重抛。
2026-10-30 02:46:37 +08:00
host 92b7f8e8ff feat(tasks): 完整结果另存 result_text_full,详情不再只剩 2000 字
旧链路三层截断:sandbox stdout 截 2000 字、worker 写回截
4000 字,长答案尾部在详情里永远查不到(只把上限调大是
把截断点后移,不是修掉)。修法:截断版保持不变(列表/
摘要用),完整版另存:
- sandbox _result_from_runner/_parse_host_result(local 与
  docker dispatch 路)回包新增 stdout_full(上限 200000 字,
  只防无界增长);goal 路结论在尾部、tail 已保结论,不动。
- worker _write_execution_result 新增 result_text_full 列
  (_ensure_result_columns + server migrate_tasks_table 幂等
  补列),终局与取消分支均透传 stdout_full。
- server:任务 dict 加 result_full_available(不直接塞全文
  进列表负载),新增 GET /tasks/{id}/result-full(read 权限
  同款校验,无完整版时 404,不回摘要冒充完整)。
单测:test_queue_sandbox 45 项(含新增 stdout_full 1 项)、
test_marker_tools 30 项。
2026-10-30 02:45:51 +08:00