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 |
|
openqj
|
e9370d7291
|
Merge pull request #185 from openqj/feat-browser-stream-first-frame
fix: navigate 后立即推一帧,静态页开流不再等重绘
|
2026-10-30 13:22:48 +08:00 |
|
host
|
2d840a6c37
|
fix: navigate 后立即推一帧,静态页开流不再等重绘
screencast 帧只在重绘时来,页面可能在 startScreencast 之前
就已画好——静态页于是开流后一直无画面,直到下一次重绘。
navigate 后用 CDP captureScreenshot 抓一张当前视口塞进帧
队列,泵在下一轮就把桥帧文件写出来;泵跳过空 session 的
ack(eager 帧没有可确认的 screencast 帧)。失败静默,
screencast 本身仍照常流动。
|
2026-10-30 13:14:38 +08:00 |
|
openqj
|
b844624c96
|
Merge pull request #176 from openqj/feat-console-task-request-count
feat: 任务详情 LLM 请求数(cost_records 存 completions)
|
2026-10-30 13:05:30 +08:00 |
|
host
|
ccb5a8638d
|
feat: 任务详情 LLM 请求数(cost_records 存 completions)
|
2026-10-30 12:58:41 +08:00 |
|
openqj
|
ad4384a08e
|
Merge pull request #184 from openqj/feat-mcp-stdin-starve-main
fix: MCP 主循环 stdin 批量行饥饿
|
2026-10-30 12:55:31 +08:00 |
|
host
|
f85de63120
|
fix: MCP 主循环 stdin 批量行饥饿
select + buffered readline 会丢批量到达的行:一行 readline
可能把多行一起读进用户态 buffer,之后 select 再也看不到
空 fd,buffer 里的行永远不被读。客户端在 initialize 后
习惯把 notification + 下一请求连写,MCP 于是只答 initialize
就卡死(生产 2ff8975 活体验证两跑复现,faulthandler 证实
主线程停在 select)。改用非阻塞 fd + 自有 buffer 的行泵,
每行按到达顺序必达;附带回归测试(批量行全达 + EOF 残行)。
|
2026-10-30 12:47:23 +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 |
|
openqj
|
0c1cfcee31
|
Merge pull request #179 from openqj/feat-goal-convert-port
goal-convert / automation-create 移植:/goal 转换链 + 会话内标记工具
|
2026-10-30 07:28:45 +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 |
|
openqj
|
3a5c5db9fb
|
Merge pull request #182 from openqj/feat-browser-panel
feat: 控制台浏览器远控面板
|
2026-10-30 07:11:25 +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 |
|
openqj
|
80b32f25b3
|
Merge pull request #181 from openqj/feat-browser-phase2
feat: 浏览器二期后端:远控服务 + ref 快照 + server 代理
|
2026-10-30 06:51:20 +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 |
|
openqj
|
7bea8df512
|
Merge pull request #180 from openqj/feat-browser-phase1
feat: 浏览器一期:坐标点击 + live 截图
|
2026-10-30 06:27:46 +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 |
|
openqj
|
872b23a296
|
Merge pull request #175 from openqj/feat-project-memory-reuse
feat: 经验复用 MCP 暴露(项目记忆列/建/废弃)
|
2026-10-30 05:13:26 +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 |
|
openqj
|
903098de09
|
Merge pull request #171 from openqj/feat-cloud-mcp-more2
feat: 云端 MCP 工具 12→20
|
2026-10-30 05:00:50 +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 |
|
openqj
|
5b03e0a85d
|
Merge pull request #169 from openqj/feat-console-redesign
console: 重排版为侧边导航 + 三栏工作台 + 任务详情内页签
|
2026-10-30 03:45:48 +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 |
|
openqj
|
f0aba700e0
|
Merge pull request #168 from openqj/feat-imagegen-mcp-basefix
fix: imagegen MCP env 必须写死本地网关 base URL
|
2026-10-30 03:15:59 +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 |
|