host
49fc27eef1
feat: Docker 沙箱 /tmp tmpfs 隔离 + 可选根只读(内层 bwrap 本体不在本仓修复范围)
2026-10-30 04:17:09 +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
openqj
276d433da6
Merge pull request #166 from openqj/feat-console-pagination-tabs
...
console: 任务列表服务端分页 + 控制台分页面签
2026-10-30 02:38:35 +08:00
host
e5b6c45c83
console: 任务列表服务端分页 + 控制台分页面签
...
任务列表分页(服务端 + 前端):
- GET /tasks 新增 limit(1..100,非法回 400)、offset、
order=desc、status/executor/q 服务端过滤;回 total(过滤后
计数)与 status_counts(全项目统计,不受过滤与分页影响,
数据卡片不再把当前页当成全项目);无 limit 时旧行为不变
(全量、正序,协调子任务与旧调用不受影响)。
- 前端每页 20 条、最新在前,上一页/下一页 + 页码;筛选与
搜索改服务端过滤(搜索防抖 300ms),切筛选/切项目/派发
后回第 1 页,10 秒刷新与刷新按钮停在当前页;新测试
test_task_list_pagination.py 5 项。
分页面签:
- 顶栏锚点导航改成 5 个页签:工作台(派发 + 任务列表 +
对话 + 详情)、项目(项目 + 成员)、环境与 Workers、
技能与自动化(技能 + 自动化 + 分诊)、管理与 Key;
数据卡片仍在页签上方常驻。选中任务存在 App 层 store
里,切页不丢,回来仍是同一任务、10 秒刷新续同步;
页签同步到 location.hash(#tab-workbench 等),刷新与
分享链接落在同一页签;窄屏工作台仍保持派发在前的顺序。
- 工作台页签仍是左(任务)右(派发/对话/详情)两栏,
沿用等高内部滚动规则;其它页签单列堆叠。
2026-10-30 02:25:48 +08:00
openqj
6a5a837aac
Merge pull request #165 from openqj/feat-doc-tools-result-cap
...
文档/图片工具进任务镜像 + 结果截断改为提取 text 上限 20000 字
2026-10-30 02:19:46 +08:00
host
c1d25d11b1
feat: 文档/图片工具进任务镜像 + 结果截断从截断 JSON 改为提取 text 上限 20000 字
2026-10-30 02:03:14 +08:00
host
d5a602f7d3
feat(mcp): 云端 MCP 工具从 8 个扩到 12 个
...
#159 只包了读 + 建 + 取消,日常闭环还缺:读产物文件、
读完整结果、重试、合并。新增 get_task_files(path 为
worktree 内相对路径,服务端 _safe_worktree_path 防逃逸,
MCP 层不展开绝对路径)、get_task_result_full(依赖 #162
的 /result-full 端点,未部署前该工具回 404 isError,不炸)、
retry_task、merge_task(写操作,服务端状态机校验,非法
转换 409 原样透传,MCP 层不绕过)。
单测 test_mcp_server 10 项(含新增翻译 1 项)。
2026-10-30 02:00:58 +08:00
host
8afcd3253e
fix(automations): 审计行不再显式插 TEXT id,PG identity 下不再丢审计
...
旧 _audit_row 显式插 uuid 当 audit_log.id:SQLite 下能跑,
生产 PG 的 id 是 BIGINT GENERATED BY DEFAULT AS IDENTITY,
插 TEXT 直接报错、审计行全丢(best-effort 吞掉后无声无息,
#156 留下的已知局限)。修法:INSERT 一律不带 id,让两端
自增/identity 生成;表不存在时先按 PG 口径建、再按 SQLite
口径建、逐个重试——automations 按设计不 import 其它 cloud
模块,所以用先插、失败再按口径重试做方言探测。
单测:test_automation_run_due 4 项(含新增 PG-like 假连接
1 项:只接受不带 id 的 INSERT,旧实现在此应失败)。
2026-10-30 01:55:59 +08:00
openqj
9a11ef27b8
Merge pull request #159 from openqj/feat-cloud-mcp-server
...
feat(cloud): MCP 云端任务入口 + 上游 0.164 对齐配置
2026-10-30 01:55:43 +08:00
openqj
0c458cb2ce
Merge pull request #158 from openqj/feat-repo-access-check
...
feat(repos): 仓库接入预检 + codexsvc deploy key 配给脚本
2026-10-30 01:53:52 +08:00
openqj
aa5bf7da72
Merge pull request #157 from openqj/feat-final-audit-detail
...
fix(worker): 终态审计带上 error,复发卡死可定位
2026-10-30 01:53:39 +08:00
openqj
8d8774edee
Merge pull request #160 from openqj/feat-console-single-chat
...
console: 对话只留一处实时单列;任务列表与 API Key 加滚动上限、三栏等高
2026-10-30 01:52:45 +08:00
host
972203c38f
feat(cloud): MCP 云端任务入口 + 上游 0.164 对齐配置
...
- cloud/mcp_server.py:stdio MCP 服务,把云端任务 REST 翻成
tools/list / tools/call(health、list_projects、list_tasks、
get_task、create_task、cancel_task、get_task_cost、
get_task_trace),底层只走已有 REST,不另开任务逻辑;
鉴权只认调用方自己的 CODEX_CLOUD_API_KEY(缺了启动失败,
绝不打印),服务端权限 403 原样透传;create_task 只传已知
字段,未知字段丢弃;REST 报错时 isError=true。
单测 test_mcp_server 9 项(假 transport,不联网、不碰真 key)。
- 上游对齐 #80 的可合部分:config.example.toml 加
[features] daemon_auto_start = false(防 managed daemon 绕过
版本 pin)+ docs/upstream-164-alignment.md 对齐表;换稳定版
二进制是另一次主机侧部署动作,本批不做、不谎称已升级。
2026-10-30 01:41:34 +08:00
host
41c2b0ab2f
console: 任务列表与 API Key 加滚动上限,左中右栏等高
...
任务列表与 Key 列表此前无高度上限:任务一多就把整栏
(乃至整页)撑到无限高,左中右栏又因 align-items:start
各按内容高度结束,底部参差不齐。
改法(仅宽/中屏,窄屏 <900px 仍是单列页面滚动,不动):
- .issue-list 上限 60vh、内部纵向滚动,搜索/筛选栏在
列表外、滚动时仍可见;.api-key-list 上限 320px、内部
滚动;两处均 overscroll-behavior:contain,不让列表
滚动直接拖动整页。
- 三栏固定为同一高度:calc(100vh - 260px)(减顶栏、
数据卡片与页面边距),下限 480px,超出的部分各栏
自己内部滚动;网格 align-items 改为 stretch。
2026-10-30 01:40:57 +08:00
host
c192c5dec8
console: 对话只保留一处实时单列(ChatGPT 式)
...
根因:ConversationSection 同时渲染 TracePanel(prompt +
全部链路条目)和 ContinuePanel(GET /chat-history,
服务端已把 prompt + 继续 + 后续 + 全部链路种类按时间
合并、并去掉了后续消息回声),简单任务的两份名单
显示同一组用户 + 助手卡片,看起来就是对话重复。
改法:删 TracePanel 名单,只留 ContinuePanel 这一列;
TracePanel 唯一不重复的控件(链路类型筛选、下载完整
链路)移到这一列顶部,筛选只过滤链路消息、用户消息
恒保留;实时性不丢:基础是 10 秒轮询的 chat-history,
SSE 新链路条目按 id 去重合并进来,轮询拿到后不再
重复;无 chat-history 的旧服务端回退路径也改成渲染
全部链路种类(不再只渲染 message),并跳过 fu- 回声。
2026-10-30 01:40:20 +08:00
host
1ff8906aee
feat(repos): 仓库接入预检 + codexsvc deploy key 配给脚本
...
本机 https 到 GitHub 常被出口策略挡、ssh 才通(2026-10-30
实测),而新项目填 https 私有仓会在 worker 里花几分钟超时
才失败。控制面不存仓库凭证的设计不动,缺的是建项目前的
快速预检与按仓库通用化的配 key 流程:
- cloud.repos.check_repo_access:只跑 git ls-remote HEAD,
不 clone、不写盘、不改库;失败返回 (False, 原因),https
失败时追加改走 git@ 形的提示;CLI python3 -m cloud.repos
check <url>,退出码 0/1,只打印结果与原因。
- deploy/provision_codexsvc_key.sh:主机上以 root 跑,为
codexsvc 生成/复用 ed25519 key(绝不覆盖已有 key),只
打印公钥(私钥绝不打印),--check 时以 codexsvc 身份跑
ls-remote,通了才算配好。
- 内层沙箱边界诚实说明:Docker 任务内层本就是
danger-full-access(见 sandbox.py 注释),外层 Docker/gVisor
才是防线;宿主级 bwrap workspace-write 的 fresh proc 在嵌套
pidns 下是内核 EPERM、/tmp 不隔离——这些是上游 codex 二进制
与内核的边界,本批不谎称在仓库代码里修掉,只把仓库接入
这一档做成可重复流程。
单测:test_project_repo 20 项全过(新增 check 5 项)。
2026-10-30 01:39:46 +08:00
host
f4fb4000e1
fix(worker): 终态审计带上 error,复发卡死可定位
...
2026-10-29 任务 A:认领后 61 秒 interrupted,但终态审计只记
task_id、自动续跑又把 error_text 覆盖掉,事后无法区分取消、
配额、host 返回 interrupted 还是其它失败;容器 --rm 后日志
也没了,根因至今无法从留存证据证明(不是 sweep:阈值 300
秒;不是外部取消:该时段无取消审计;是 worker 自己写回
interrupted,但第一轮的 error 已被第二轮 failed 覆盖)。
本批不谎称找到根因,只补可定位性:run_one 终态审计在
interrupted/failed 时 detail 带 error(截 500 字、去换行),
完成态仍只记 task_id;分段审计 worker_exec_start/error/done
已在现 main,复发时最后一段 + 终态 error 即能定位。
单测 test_final_audit_detail_carries_error:失败派发后
worker_failed 审计 detail 以 'A:' 开头且含 error 文本。
2026-10-30 01:38:01 +08:00
host
3a06205d8b
feat: 跨 worker 真 kill(kill_requests 意图表 + 收殓器)与自动化触发入闸
...
机制 A 移植自旧 PR #101(分支 feat-residual-b,头 895e004),
不合旧 PR:旧基线 6e3eb7b 已 CONFLICTING,本批重做到现 main
6d4f87e(#151 合并后)上。
- kill_requests 意图表:cloud/db.py POSTGRES_SCHEMA + migrations
清单补表;server.ensure_kill_requests_table / request_kill
(同一任务只留一条 pending,写失败返回 False);init_db 的
SQLite 分支补建表(PG 分支由 POSTGRES_SCHEMA 全量建表覆盖)。
- 取消/sweep 写请求 best-effort:_cancel_task 在 commit 后调
request_kill(失败不挡取消);sweep_stale_tasks 在同一事务
内为被扫任务写 system 请求。
- worker 收殓器 _reap_kill_requests:owner 活着(心跳停滞未超
300 秒,COALESCE(last_heartbeat, updated_at))绝不抢杀;只
有 owner 已死且任务仍 interrupted 时,按任务派生容器名
(executor.container_name,codex-<安全字符任务 id>)在本机
真杀,绝不按前缀扫、绝不杀自由传入的名字;本机无容器时
请求照常终结;任务行失踪或已不在 interrupted 时请求直接
终结;单条异常只记日志。run loop 每轮调一次,放在 sweep
块外(旧 PR 只在 sweep 块内,sweep 关掉时请求会积压)。
- 自动化入闸只补两条旁路:worker._coord_sync_children 建子任
务前过 _quota_exceeded(超限跳过建任务、记审计,同一 worker
内同一分工只记一次);automations.run_due_automation
(claim 抢单 -> 配额门 -> 建任务 -> 记产出,超限记
skipped_quota 不进失败重试)。triage/webhook/续跑/后续/
分叉未动。
- 单测:旧 PR 三份单测原样移植(Worker/Server 签名与现 main
兼容,未改用例语义)。
2026-10-30 01:32:35 +08:00
openqj
b306b56517
Merge pull request #155 from openqj/feat-chatgpt-codex-align1
...
ChatGPT Codex 对齐:技能包 + 租户播种 + web_search Docker 联网修法
2026-10-30 01:29:47 +08:00
host
71e31b22a0
websearch: MCP env 写进租户 config,不只靠 docker -e
...
2026-10-30 实测:Codex bash 里有 SEARXNG_URL + proxy,
MCP 链却只有 duckduckgo、DNS 瞬间失败——Codex 的 MCP
子进程不继承 Codex 进程 env;给租户 config 加
[mcp_servers.websearch.env] 后同一任务立刻返回真实
SearXNG 结果。修法:worker 在 _docker_task_context
算出网关后、容器启动前,用 ensure_websearch_mcp_env
把 proxy + 搜索 env 写进租户 config(网关此时才已知,
播种时写不死;写失败只记日志不阻塞)。
测试:新增 test_websearch_mcp_env 4 项,相关共 33 项全过。
2026-10-30 01:16:49 +08:00
host
08d56b15ce
websearch: SearXNG 默认只查 bing,360search
...
默认 general 类别在 Docker 任务容器里要 20.0 秒才回
(wikipedia/wikidata/brave/duckduckgo/google 引擎全超时,
只有 bing+360search 回),撞 MCP 默认 20 秒超时;随后
DuckDuckGo 经代理也超时,整条链失败。代理本身无问题
(Tinyproxy 白名单早已放行 searx 与 duckduckgo)。
修法:_provider_searxng 默认 engines=bing,360search,
SEARXNG_ENGINES 可覆盖、空值恢复旧行为;worker 搜索
env 透传补 SEARXNG_ENGINES。容器实测:钉住后 0.26 秒
回 3 条(首条北京天气),auto 链 0.15 秒成功;旧 20.0 秒。
测试:新增 test_websearch_searxng 3 项,MCP/worker 共
21 项全过。生产未部署。
2026-10-30 01:16:49 +08:00
host
378cddfb1e
align: 修正技能播种路径:codex-home/skills/ 才是用户技能目录
...
2026-10-30 主机实测(临时 codex-home,生产未动)纠正:
先播 .agents/skills/ 时 skills/list 只返回 5 个系统技能,
3 个自有技能一个没出现;改播 skills/ 后返回 8 个,
3 个自有技能以 scope=user 出现。系统技能本身就在
skills/.system/ 下。
- skill_seed DEST_SUBDIR 由 .agents/skills 改为 skills,
模块文档与 worker 注释同步修正。
- 测试期望路径同步改为 skills/。
- 对照表补实测结论与附带发现:Codex 自带系统技能
imagegen,图片生成在 Codex 本体里不是无技能。
验证:skill_seed + chatgpt skills + websearch worker
共 14 项全过。主机探针文件已全部清理,生产未动。
2026-10-30 01:16:49 +08:00
host
cf9d17f035
align: 第二批:把技能包播种进租户 codex-home
...
仿 websearch MCP 播种,默认关:
- cloud/skill_seed.py:cloud/skills/ 的 SKILL.md 拷进租户
codex-home/.agents/skills/(个人级技能路径,见模块
文档的路径依据与诚实边界);幂等,租户改过的文件
绝不覆盖(上报 differs),缺包不阻塞任务。
- cloud/worker.py:新增 --seed-skills,_tenant_dirs 里
调用播种;老租户下一次任务自动合并;播种失败只记
日志、不阻塞任务(技能是可选流程说明)。
- cloud/tests/test_skill_seed_worker.py:播种助手 + worker
开关,仿 test_websearch_worker.py 的结构。
- docs/chatgpt-codex-alignment.md:补第二批说明与实测
待办(真实 Docker 任务 skills/list + $live-info 调用,
通过前不宣称生产任务已能用这些技能)。
验证:skill_seed + chatgpt skills + websearch worker
共 14 项全过。本批不改生产配置、不部署,autoscaler
加 --seed-skills 是部署时另行的主机步骤。
2026-10-30 01:16:49 +08:00
host
8a26d1973c
align: ChatGPT Codex 对齐第一批:技能包 + 对照表
...
对照用户提供的 ChatGPT Codex 工具目录,区分可对齐与
不照搬:核心编程工作流已对齐,ChatGPT 托管专属
(CUA、宠物、Docs/Sites 连接器、图片生成模型)不在
开源宿主编排层范围,不凭空宣称对齐。
第一批只补技能层,不改 worker、不改生产行为:
- cloud/skills/live-info:天气/时区/股票/体育,查一级
来源、带来源和快照时间,绝不编数字。
- cloud/skills/document-tools:LaTeX/Word/PDF/表格/
演示文稿,先核查工具、缺了明说、产出后重读验证。
- cloud/skills/image-workflow:已有图片处理 + 生成工具
已配置时才生成,未配置时明说、绝不顶替。
- docs/chatgpt-codex-alignment.md:逐项对照表与不照搬
的诚实边界,方向为自动化编程任务平台。
- cloud/tests/test_chatgpt_codex_skills.py:校验技能
frontmatter、名字与目录一致、正文非空、无密钥占位。
验证:新测试 2 项全过。播种进租户 codex-home、 worker
改动、CUA/连接器/图片模型均不在本批,另行评审。
2026-10-30 01:16:49 +08:00
host
b60f4facbd
console: 任务详情改卡片式排版
...
只改排版,不改数据与操作:原来一整块 <br> 分隔的
信息行拆成卡片——概览(状态 + 耗时/token/成本三张
指标卡)、基本信息(键值网格)、prompt(单独一张
卡,长 prompt 不再挤在信息行末尾)、操作与结果、
协调子任务/子代理链路/评审队列/审批队列/发消息/
线程(各一张卡)。指标卡在窄的详情列里用
auto-fit 网格自动折成一列,不挤压;nav-detail
锚点保留在外层容器上。
2026-10-30 01:13:32 +08:00
host
ce85043a24
trace: 标注被截断的链路消息,避免误读为模型未写完
...
2026-10-29 实弹:468 字 final_answer 在链路里只剩前 300 字、
断在 fu 后,控制台照原样当助手回复展示,用户误以为模型
没写完。截断本身是设计(防链路文件写爆),缺的是标记。
- host.py _summarize_trace_item:agentMessage 超 300 字时
条目带 truncated=True,短消息不带,完整回复仍在任务
result_text 里,不在链路条目里。
- 控制台:TraceEntry 加 truncated 字段,mapTrace 与
traceLineText 在被截断的消息后标注“链路摘要已截断至
300 字,完整回复见右侧任务结果”,console.html 为构建产物同步。
- 单测:tests/test_host_trace.py 新增截断标记用例(468 字
截 300 字且带标记、短消息不带标记)。
验证:host 10 项、cloud test_task_trace 14 项全过;
React tsc+vite 构建通过,产物 322151 字节、含截断标注、
含 #150 的 total_tokens/首字/总耗时,无回退。
2026-10-30 01:01:50 +08:00
openqj
fd9fe5f254
Merge pull request #153 from openqj/feat-auth-unknown-role
...
fix(auth): unknown project role denies instead of KeyError 500
2026-10-30 00:55:54 +08:00
host
c823e32336
fix(auth): unknown project role denies instead of KeyError 500
...
check_permission now returns False for roles not in _ROLE_LEVEL
(e.g. a directly-written 'member' row, which set_member itself
rejects but legacy/direct DB rows can still carry), so the failure
mode is PermissionError/403, never an unhandled 500. Regression test
test_unknown_role_denied_not_500 fails with KeyError on old code.
2026-10-30 00:49:03 +08:00
host
994c4ea5d1
console: 任务详情自动显示成本明细
...
打开详情就自动拉 GET /tasks/{id}/cost(不再只靠
“查成本”按钮出 JSON),详情顶部新一行:美元、总
token(实际/估算、缓存、无价单列)、轮数、fallback
次数;美元小于 1 美分时用 4 位小数,避免小任务
显示成 $0.00 误导成免费;加载中/失败有各自的
弱化文案,成本拉失败不影响详情其它内容;原
“查成本”按钮不动,仍可手动拉原始 JSON。
服务端不用改:成本接口与 _get_task 的 token 聚合
都已在 #150 / 详情 meta 那单里就位。
2026-10-30 00:39:13 +08:00
host
0f7162934b
console: 任务详情也显示首字、总耗时、token
...
列表行与详情共用同一口径:新抽 api/taskMeta.ts(首字/
总耗时/token 计算),TaskListSection 改 import 它(逻辑
原样不动),TaskDetailPanel 在状态行下方加一行:首字
方块 + 耗时 + token,title 里写口径。
详情的数据缺口一并补上:单任务接口 _get_task 此前走
_task_to_dict 默认 total_tokens=None,详情 token 只能
显示占位;现与列表一样用 _task_tokens_map 一次聚合
(单任务只多一条查询),详情直接出真数。
types.ts 里过期的“列表不回 token”注释同步更新。
新测试:单任务 GET /tasks/{id} 聚合回 total_tokens。
2026-10-30 00:39:13 +08:00
host
4cbdc41e20
fix: task files endpoint resolves tenant docker worktrees
...
GET /tasks/{id}/files previously returned 409 for all docker tasks
on the grounds that tenant docker shares /app/work per project.
Production inspection shows the worker creates a per-task
host-worktrees/<task-id> subdirectory under the tenant work dir
(62 such dirs under the wwww tenant), so per-task reads are
attributable after all: the endpoint now resolves tenant docker
tasks via tenants/<project>/work/host-worktrees/<task-id> (local
worktree as fallback), never serves the shared /app/work mount
itself, and still 409s cloud/cross-host tasks. Docs and the
harness2_tasks boundary notes are updated to match.
2026-10-29 23:16:01 +08:00
host
9eedee5a3d
server: 任务列表一次聚合回 total_tokens
...
_list_tasks 在取附件的同时用 _task_tokens_map 一次查
cost_records 按 task_id 求和(GROUP BY),一屏只多一条
查询,不按任务逐个调成本接口。无记录计 0、表不存在时
全计 0 且列表不失败;_task_to_dict 新增 total_tokens
参数,默认 None(非列表调用方不把“未算”写成 0)。
前端 TaskListSection 的 token 栏位此前已接好 total_tokens,
补上后列表行直接显示真数,不再显示 token —;前端注释
与占位文案同步更新。
新测试 test_task_list_tokens.py 3 项:HTTP 列表聚合
(actual+estimated 加总、无记录为 0)、缺表不炸、
_task_to_dict 默认 None。
2026-10-29 18:27:53 +08:00
host
65a875ada9
console: 任务列表行显示首字、总耗时、token 栏位
...
任务列表每一行新增三项(筛选、搜索、选中高亮、状态点不动):
- 首字:行前小方块,prompt 第一个非空白字符(按码点取),
无 prompt 时用任务 id 首字符兜底;原 prompt 文案不动。
- 总耗时:只用列表已回时间戳算。终态用 finished_at -
started_at(与服务端 avg_duration_seconds 同口径);running
显示“进行中 + 已用时长”,随列表刷新更新;无 started_at
时用 created_at 兜底(含排队,title 注明口径)。格式:
3分12秒、1小时5分、1天1小时。
- token:栏位已接好,total_tokens 优先,actual +
estimated 分项加总次之;但列表接口 _task_to_dict 目前
不回任何 token 字段,单任务真数只在 GET /tasks/{id}/cost
里,所以当前显示“token —”,不编造、不逐个调 /cost
拖慢列表。服务端在列表里补 total_tokens 后本行自动出真数。
诚实边界:worker 每次认领重写 started_at,多轮续跑任务
的耗时是末次认领时长,不是历次之和;严格累计需服务端
保留首次 started_at 或累加各轮时长。token 的服务端缺口:
需在 _task_to_dict / 列表查询里按 task_id 聚合 cost_records
的 total_tokens,不需要新端点。
构建:npm run build(tsc + vite singlefile)0 退出,
dist/index.html 原样拷到 cloud/console.html,产物含
issue-first、耗时、token —,未动其它确认框。
2026-10-29 18:24:07 +08:00
host
6d9cd24553
console: 新建任务选完全访问不再弹确认框
...
DispatchSection 提交时删掉 full 的 window.confirm:下拉里
选 full 本身就是显式选择,提交直接送 approval,不再二次
确认。计划模式与 full 互斥的拦截不动,其它确认框(取消/
合并/提 PR 等)不动。
构建产物 cloud/console.html 由 npm run build(tsc + vite
singlefile)重新生成,产物里已无“确认提交吗”,仅剩下拉
选项本身的“完全访问”文案。
2026-10-29 18:06:18 +08:00
host
7d400afa37
console: add goal-mode invincible option
...
DispatchSection gains a 'goal 模式无敌版' checkbox next to 'goal 模式':
checking it sends goal_mode=1 plus no_time_limit=1 (server already
accepts the field; the console just never exposed it). Plain goal
checkbox behavior is unchanged; invincible wins when both are
checked. Plan/coordinator mutual exclusion now covers invincible
too (it is a goal variant). TaskDetailPanel shows
'goal 模式无敌版(不限时)' when a task carries no_time_limit.
Help text states the honest boundary: worker/docker total timeouts
are lifted, the 600s single-turn host guard stays. Built with
npm run build (tsc+vite pass); console.html synced verbatim from
dist/index.html.
2026-10-29 17:58:50 +08:00