dsh-inner-browser-use 0.34.28 → 0.34.95
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +53 -18
- package/README.zh.md +26 -14
- package/client.js +161 -22
- package/docs/ARCHITECTURE.md +15 -12
- package/docs/ARTIFACTS.md +1 -1
- package/docs/BENCH.md +209 -34
- package/docs/FLASH.md +84 -0
- package/docs/ROADMAP.md +21 -15
- package/docs/VERIFY.md +20 -10
- package/index.js +144 -24
- package/package.json +17 -3
- package/read.js +633 -29
- package/runtime/flash-app/main.js +232 -0
- package/runtime/flash-app/package.json +1 -0
- package/runtime/flash-setup.mjs +151 -0
- package/runtime/swf.mjs +233 -0
- package/scripts/check-flash-local.mjs +104 -0
- package/scripts/check-flash-mirror.mjs +73 -0
- package/scripts/check-flash-tools.mjs +74 -0
- package/scripts/check-flash-window.mjs +58 -0
- package/scripts/doctor.mjs +3 -1
- package/sidecar.js +1076 -96
- package/tools.js +1068 -144
package/docs/BENCH.md
CHANGED
|
@@ -1,8 +1,172 @@
|
|
|
1
|
+
## Flash 镜像按栏改窗口(0.34.48,Electron Flash 运行时,右栏 747×1196)
|
|
2
|
+
|
|
3
|
+
Flash 路径原来采集一个固定的 1440×900 窗口,竖高右栏里上下留黑边。现在 `setViewport` 直接改窗口大小,采集源与栏同比例。
|
|
4
|
+
|
|
5
|
+
| 状态 | 窗口 | 画面占栏 | 单帧 |
|
|
6
|
+
|---|---|---|---|
|
|
7
|
+
| 0.34.47 | 1440×900 | 约 39% | 126 KB |
|
|
8
|
+
| 0.34.48 | 747×1196 | 100% | 111 KB |
|
|
9
|
+
|
|
10
|
+
轮询帧率 9 fps 不变(Flash 桥上限),改的是画面比例与单帧体积。
|
|
11
|
+
|
|
12
|
+
## 动画页下行节流(0.34.47,真实 Chrome headless,720×880,canvas 60 fps 动画)
|
|
13
|
+
|
|
14
|
+
| 状态 | 帧率 | 单帧 | 下行带宽 |
|
|
15
|
+
| --- | --- | --- | --- |
|
|
16
|
+
| 0.34.46 全推 | 60 fps | 11 KB | 654 KB/s |
|
|
17
|
+
| 0.34.47 空闲节流 | 30 fps | 11 KB | 326 KB/s |
|
|
18
|
+
| 0.34.47 指针活动(1.5 s 内) | 58 fps | 11 KB | 631 KB/s |
|
|
19
|
+
|
|
20
|
+
节流只作用于下行:`latest`、`seq`、`still()` 与输入路径不变;`browser_shot` 仍走独立整帧截图。
|
|
21
|
+
|
|
22
|
+
## 坏页读取成本(0.34.46,构造页:`querySelectorAll` 抛错被读 150 字符)
|
|
23
|
+
|
|
24
|
+
| 读取结果 | 字符 | 约 token |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| 0.34.46 一行故障说明 | 150 | 45 |
|
|
27
|
+
| 0.34.45 同一页读成 0 控件 0 字 | 20 | 6(但模型会重试或猜内容,整轮更贵) |
|
|
28
|
+
|
|
29
|
+
## 点击与多步延迟(0.34.45,headless Chrome,本地页)
|
|
30
|
+
|
|
31
|
+
| 场景 | 0.34.45 | 0.34.44 |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| `browser_do` 单步 | 73 / 83 ms | 98 / 112 ms |
|
|
34
|
+
| 遮挡点击(自动清掉横幅) | 72 / 77 ms | 97 / 112 ms |
|
|
35
|
+
| `browser_do` 20 步 | 2035 ms(102 ms/步) | 2151 ms |
|
|
36
|
+
| 崩溃恢复(换新标签页) | 1390 ms | ~1.5 s |
|
|
37
|
+
|
|
38
|
+
做法:`Page.frameStartedLoading` / `frameStoppedLoading` 打时间戳,点击后若页面已 `complete` 且没有新加载开始,`settle()` 一次求值就返回;预算不变(点击 ≤ 220、遮挡点击 ≤ 240、单步 ≤ 240、每步 ≤ 280、崩溃恢复 ≤ 2600 ms)。
|
|
39
|
+
|
|
40
|
+
## 真实站点读页成本(0.34.44,headless Chrome,720×880 栏宽,`scripts/readcost.mjs`)
|
|
41
|
+
|
|
42
|
+
| 页面 | 读法 | 字符 | 估算 token | 控件 |
|
|
43
|
+
| --- | --- | --- | --- | --- |
|
|
44
|
+
| GitHub 仓库首页(rust-lang/rust) | text | 2562 | 754 | 90 |
|
|
45
|
+
| 同上 | links | 3763 | 1107 | 90 |
|
|
46
|
+
| GitHub Topics · computer-use | links | 2590 | 762 | 90 |
|
|
47
|
+
| 同上 | text | 1939 | 570 | 90 |
|
|
48
|
+
| GitHub 登录表单 | forms | 218 | 64 | 4 |
|
|
49
|
+
| 同上 | text | 533 | 157 | 13 |
|
|
50
|
+
|
|
51
|
+
- 读页本身 1–21 ms;`max_chars` 只对长页生效(links 4600→2200:3763→2800 字符,1107→824 token),短页两种预算结果一致。
|
|
52
|
+
- 空读取重试:内容在 700 ms 后才写入的页面,一次 `browser_view` 用 614 ms 拿到内容(此前直接读到空页)。正常页面不进入该分支,延迟与 token 不变。
|
|
53
|
+
|
|
54
|
+
## 故障归因的 token 成本(0.34.43)
|
|
55
|
+
|
|
56
|
+
| 场景 | 读取结果多出的内容 | 代价 |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| 页面正常 | 0 字符 | 0 |
|
|
59
|
+
| 1 个 404 请求 + 1 个脚本错误 | 1 行,约 130 字符 | ≈33 token,替代 2 次排查调用(通常 ≥600 字符) |
|
|
60
|
+
| 同一页面再读 | 0 字符(已报过) | 0 |
|
|
61
|
+
|
|
62
|
+
## 点击与多步延迟(0.34.42,headless Chrome,本地页)
|
|
63
|
+
|
|
64
|
+
`node scripts/bench.mjs` 复现;末行 `budget` 是纳入退出码的预算断言。
|
|
65
|
+
|
|
66
|
+
| 场景 | 0.34.42 | 0.34.40 |
|
|
67
|
+
| --- | --- | --- |
|
|
68
|
+
| `browser_click` 普通页 | 97 ms | 439 ms |
|
|
69
|
+
| `browser_click` 横幅遮挡、自动清掉 | 107 ms | 593 ms |
|
|
70
|
+
| 被弹窗拦住的点击(拒绝) | 2 ms | — |
|
|
71
|
+
| `browser_do` 单步 | 95 ms | 440 ms |
|
|
72
|
+
| `browser_do` 20 步 | 2151 ms(108 ms/步) | 9067 ms |
|
|
73
|
+
| 崩溃恢复(换新标签页) | ~1.5 s | — |
|
|
74
|
+
|
|
75
|
+
预算:点击 ≤ 220 ms、遮挡点击 ≤ 240 ms、单步 ≤ 240 ms、20 步每步 ≤ 280 ms、崩溃恢复 ≤ 2600 ms。
|
|
76
|
+
|
|
77
|
+
## 点击与多步延迟(0.34.41,headless Chrome,本地页)
|
|
78
|
+
|
|
79
|
+
| 场景 | 耗时 |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| `browser_click` 普通页 | 141 ms |
|
|
82
|
+
| `browser_click` 横幅遮挡、自动清掉 | 235 ms |
|
|
83
|
+
| 被弹窗拦住的点击(拒绝) | 2 ms |
|
|
84
|
+
| `browser_do` 单步 | 131 ms |
|
|
85
|
+
| `browser_do` 20 步 | 3073 ms(154 ms/步) |
|
|
86
|
+
| 跟随点击开出的弹窗 | 22 ms |
|
|
87
|
+
|
|
88
|
+
`node scripts/bench.mjs` 复现;对照 0.34.40 的 439 / 593 / 440 / 9067 ms。
|
|
89
|
+
|
|
90
|
+
## 广度回归(0.34.40,headless Chrome,本地构造页)
|
|
91
|
+
|
|
92
|
+
`node scripts/breadth.mjs` — 66 项操作全通过:shadow DOM 读/点、表单输入/退格/清空、按字段名输入、下拉、勾选、提交、只读变化、画布编号与点选、截图尺寸、遮挡弹窗拒绝、失效 ref 跟随、断线恢复。
|
|
93
|
+
|
|
94
|
+
## 真实站点读页成本(0.34.39,headless Chrome,720×880 栏宽)
|
|
95
|
+
|
|
96
|
+
| 页面 | 字符 | 估算 token | 控件 |
|
|
97
|
+
| --- | --- | --- | --- |
|
|
98
|
+
| example.com | 976 | 305 | 1 |
|
|
99
|
+
| GitHub Topics · computer-use | 约 1.5k | 约 470 | 90 |
|
|
100
|
+
|
|
101
|
+
读页脚本此前因正则转义缺失整段无法解析,同一测例读出 0 控件 0 字符;修好后为上面数字。
|
|
102
|
+
|
|
103
|
+
## 读页 token 成本(0.34.38,构造页:300 行链接,字符预算 24000 以排除截断)
|
|
104
|
+
|
|
105
|
+
| 读法 | 字符 | 估算 token |
|
|
106
|
+
| --- | --- | --- |
|
|
107
|
+
| 列出全部控件(旧) | 9153 | 2860 |
|
|
108
|
+
| 控件折叠到 140 行(新) | 4277 | 1337 |
|
|
109
|
+
|
|
110
|
+
正文不再被编号挤到预算之外;被折叠的控件滚动后重新出现。
|
|
111
|
+
|
|
112
|
+
## 长文本输入延迟(0.34.37,真实 Chrome headless)
|
|
113
|
+
|
|
114
|
+
| 目标 | 方式 | 314 字符耗时 | 文本一致 |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `<textarea>` | 逐键 `dispatchKeyEvent` | 1686 ms | 是 |
|
|
117
|
+
| `<textarea>` | 一次 `Input.insertText` | 2 ms | 是 |
|
|
118
|
+
| `contenteditable` | 一次 `Input.insertText` | 13 ms | 是 |
|
|
119
|
+
|
|
120
|
+
## 右栏尺寸下的镜像带宽(0.34.36,真实 Chrome headless,720×880)
|
|
121
|
+
|
|
122
|
+
| 页面 | 3–4 s 内帧数 | 帧率 | 平均单帧 | 带宽 |
|
|
123
|
+
| --- | --- | --- | --- | --- |
|
|
124
|
+
| 静态真实站点(example.com) | 3 | <1 fps | 47 KB | 47 KB/s |
|
|
125
|
+
| 注入 `requestAnimationFrame` 动画 | 181 / 3 s | ~60 fps | 15 KB | 875 KB/s |
|
|
126
|
+
|
|
127
|
+
结论:静止页面几乎不花带宽(Chrome 的 screencast 只在合成器变化时发帧);满帧动画按列宽排版后单帧只有 15 KB,60 fps 总计约 875 KB/s,走本机 SSE 无压力,不设帧率上限以免牺牲延迟。「同一张图不重复发」这道闸真正省掉的是 Flash 轮询分支与 `still()` 连发(单测:3 次连发 → 1 张)。
|
|
128
|
+
|
|
129
|
+
## 镜像按右栏尺寸排版(0.34.35,真实 Chrome,`--headless=new`)
|
|
130
|
+
|
|
131
|
+
页面不再按 1440×900 排版,而是按右栏实测的尺寸排版;下表的 `inner` 是页面自己报告的 `innerWidth×innerHeight`,证明不是缩放图片而是重新排版。
|
|
132
|
+
|
|
133
|
+
| 请求尺寸 | 页面 inner | `Emulation.setDeviceMetricsOverride` + 重开 screencast | 一张整帧 `captureScreenshot` | 整帧 JPEG(纯色测试页) |
|
|
134
|
+
| --- | --- | --- | --- | --- |
|
|
135
|
+
| 720×880 | 720×880 | 41 ms | 39 ms | 11.7 KB |
|
|
136
|
+
| 520×1000 | 520×1000 | 34 ms | 33 ms | 11.3 KB |
|
|
137
|
+
| 1440×900 | 1440×900 | 49 ms | 47 ms | 17.4 KB |
|
|
138
|
+
|
|
139
|
+
冷启动到可排版 827 ms。点击链路在同一尺寸下实测:两次 `Input.dispatchMouseEvent`(按下+抬起)13 ms,页面 `mousedown` 处理器已计数,订阅后下一帧 8 ms 内到达。
|
|
140
|
+
|
|
141
|
+
## Phase 46 — 开玩前的体检,0.34.30
|
|
142
|
+
|
|
143
|
+
`npm run ready [url]` 跑新工具 `browser_prepare`,整条链路一次调用,自带 Chrome、跑完关掉:
|
|
144
|
+
|
|
145
|
+
| 页面 | 调用耗时 | 找到的输入面 | 帧率 | 按键 |
|
|
146
|
+
| --- | --- | --- | --- | --- |
|
|
147
|
+
| 4399《怪物小汽车》 | 3297 ms | frame 748×336(在屏幕外,先滚进来再点) | 页面 58 fps / 框架 59 fps | 没进到框架,工具直说「先点进框架一次」 |
|
|
148
|
+
| 奥拉星 `http://aoqi.100bt.com/` | 573 ms | — | — | —,地址已连不上,返回 Chrome 错误页说明 |
|
|
149
|
+
|
|
150
|
+
`browser_prepare` 的判断顺序:连不上就直说 → 读页面 → 挑画布/框架(优先屏幕内的,否则滚进视野)→ 有 Flash 影片就说这个浏览器放不了 → 数帧率(页面与最大的框架各数一遍)→ 派一个真键看它是否真的到达框架 → 一行结论。
|
|
151
|
+
|
|
152
|
+
## Phase 45 — 两种操作方式的实际差别,0.34.29
|
|
153
|
+
|
|
154
|
+
同一张本地页(按钮 + 输入框,页面在捕获阶段记下每个事件的类型和 `isTrusted`),`npm run modes`:
|
|
155
|
+
|
|
156
|
+
| 路径 | 受信任事件 | pointerdown | click | keydown | input | 写进值 |
|
|
157
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
158
|
+
| human 点按钮 | 3 | 1 | 1 | – | – | – |
|
|
159
|
+
| dom 点按钮 | 0 | 1 | 1 | – | – | – |
|
|
160
|
+
| human 输入 abc | 11 | – | – | 3 | 3 | abc |
|
|
161
|
+
| dom 输入 abc | 0 | – | – | 0 | 1 | abc |
|
|
162
|
+
|
|
163
|
+
`trustedEvents` 是这张表里唯一真正的分界:真人路径全为 true,`dom` 路径全为 false。要过反自动化、要看指针轨迹、要按键有 `code` 的游戏,只有 human 能走;被浮层盖住、被脚本接管了按键的登录框,`dom` 一次就过。
|
|
164
|
+
|
|
1
165
|
## Phase 44 — 真站页游场地,0.34.28
|
|
2
166
|
|
|
3
167
|
`node scripts/check-game.mjs <url>`,真 Chrome、自己的 profile、跑完自己关掉。两个真站:
|
|
4
168
|
|
|
5
|
-
| 站点 | 空闲时页面刷新 | 全屏截图(`
|
|
169
|
+
| 站点 | 空闲时页面刷新 | 全屏截图(`browser_shot` 同类)| 按住 `d` 200 ms 到达页面 |
|
|
6
170
|
| --- | --- | --- | --- |
|
|
7
171
|
| 奥拉星 `http://aoqi.100bt.com/` | **27 fps** | 中位数 **68 ms** | 是 |
|
|
8
172
|
| 4399 `https://www.4399.com/` | **59.8 fps** | 中位数 **148 ms** | 是 |
|
|
@@ -17,10 +181,10 @@
|
|
|
17
181
|
|
|
18
182
|
| 项 | 数字 |
|
|
19
183
|
| --- | --- |
|
|
20
|
-
| `
|
|
184
|
+
| `browser_key` 带 `hold_ms: 300` 整次调用 | **305 ms**(含 300 ms 按住,收尾 5 ms) |
|
|
21
185
|
| 页面测到的按住时长 | **301 ms** |
|
|
22
186
|
| `ArrowLeft+ArrowUp` | 两键都收到 `keydown`,都收到 `keyup`,顺序为倒序松开 |
|
|
23
|
-
| `
|
|
187
|
+
| `browser_click` 带 `hold_ms: 200` 页面测到 | **211 ms** |
|
|
24
188
|
|
|
25
189
|
对照 0.34.25 之前:同样的按住被 `settle` 拖到 727 ms,等于 0.7 s 才走一步——页游里这就是掉帧。
|
|
26
190
|
|
|
@@ -50,14 +214,14 @@
|
|
|
50
214
|
| 镜像延迟 | 中位 8 ms / 最大 8 ms |
|
|
51
215
|
| 遮挡检测 | 中位 3 ms / 最大 15 ms |
|
|
52
216
|
| 点一下(普通页 / 有遮罩,含读回) | 439 / 590 ms,遮罩那次 `cleared: true` |
|
|
53
|
-
| 一步 `
|
|
217
|
+
| 一步 `browser_do` | 440 / 590 ms |
|
|
54
218
|
| 截图 | 73 ms / 115 KB |
|
|
55
219
|
| 读 dense 页 text 档 | 6 ms / 1484 字 / ≈436 token |
|
|
56
220
|
| 读 dense 页 forms 档 | 1 ms / 432 字 / ≈127 token |
|
|
57
221
|
| 再读同一页 | 1–2 ms,给出「没有变化」一行 |
|
|
58
222
|
| `changed_only` | 58 字 / ≈17 token(整页 1505 字) |
|
|
59
223
|
|
|
60
|
-
这轮 bench 的作用不是数字,而是**它第一次跑到 `
|
|
224
|
+
这轮 bench 的作用不是数字,而是**它第一次跑到 `browser_view` 就报 `ReferenceError` 退出**:那个工具在真实会话里同样会失败,而单测只测了它的纯函数部分。修完之后 bench 一次性跑完,数字在上面。
|
|
61
225
|
|
|
62
226
|
## Phase 40 — the poll that names its chat, 0.34.19
|
|
63
227
|
|
|
@@ -106,9 +270,9 @@ video, a cross-origin frame — nothing in the text said "there is something her
|
|
|
106
270
|
you cannot read". A model then planned as if the page were fully described.
|
|
107
271
|
|
|
108
272
|
- `readPage` counts the unreadable visible things on the page and in frames, and `renderPage` prints exactly one line when the count is non-zero; zero adds no line (measured token cost of the feature is 0 on pages that have nothing to hide).
|
|
109
|
-
- `chrome-error://` is no longer rendered as an empty page: it says the page did not load and names `
|
|
273
|
+
- `chrome-error://` is no longer rendered as an empty page: it says the page did not load and names `browser_nav`.
|
|
110
274
|
- `navigate` retries that error page once (300 ms + 8 s cap). Cold launch on a fresh profile: first navigation recovered on the retry; an unreachable host still returns `bad` in well under the cap.
|
|
111
|
-
- `
|
|
275
|
+
- `browser_shot` without an image channel appends what the result is missing and which tool fills it; file path alone is no longer the whole answer.
|
|
112
276
|
- Suite: 101 tests, 0 failures.
|
|
113
277
|
|
|
114
278
|
## Phase 36 — a reload must not cost the browser, 0.34.14
|
|
@@ -121,7 +285,7 @@ you cannot read". A model then planned as if the page were fully described.
|
|
|
121
285
|
## Phase 35 — a review round that can be checked off, 0.34.13## Phase 35 — a review round that can be checked off, 0.34.13
|
|
122
286
|
|
|
123
287
|
- `markRound()` 追加 verdict 行,`lastRound()` 折回 `marks`;`brief({already})` 只保留 open 条目,实测提问里出现「Already handled from your previous review」,已处理点不再重复。
|
|
124
|
-
- 工具面新增 `
|
|
288
|
+
- 工具面新增 `browser_review_verdict`(`mark: [{point,status,evidence}]`,状态枚举 fixed/verified/invalid/open);越界编号丢弃、未知状态记为 open。
|
|
125
289
|
- 测试 92 → 96 条全绿。
|
|
126
290
|
|
|
127
291
|
## Phase 34 — one gate in front of every write, 0.34.12## Phase 34 — one gate in front of every write, 0.34.12
|
|
@@ -217,7 +381,7 @@ in one place.
|
|
|
217
381
|
|
|
218
382
|
## Phase 26 — a screenshot the model can see, 0.34.3
|
|
219
383
|
|
|
220
|
-
Observation was structured text only: `
|
|
384
|
+
Observation was structured text only: `browser_shot` wrote a PNG and returned
|
|
221
385
|
a path, which is a file name the model cannot look at. Codex and Claude Code
|
|
222
386
|
both hand screenshots back as image content, and that is the difference
|
|
223
387
|
between planning from the picture and guessing.
|
|
@@ -333,7 +497,7 @@ answer), and a read now also asks for the frame tree.
|
|
|
333
497
|
| key round trip | 13 ms | 2 ms |
|
|
334
498
|
| screenshot | 82 ms, 133 KB | 77 ms, 113 KB |
|
|
335
499
|
|
|
336
|
-
`
|
|
500
|
+
`browser_extract` on a 30-row list: 1106 chars for all 30 rows (≈330 tokens),
|
|
337
501
|
against 1291 chars for the same page read as text — and at a 500-char read
|
|
338
502
|
budget the text read stops around row 12 while the list still returns 30.
|
|
339
503
|
|
|
@@ -383,10 +547,10 @@ frame's corner is one `DOM.getFrameOwner` plus one call on the owner element.
|
|
|
383
547
|
| What | Number |
|
|
384
548
|
| --- | --- |
|
|
385
549
|
| the "what is on top of this control" probe | **1 ms median, 2 ms max** (5 samples) — the same `Runtime.evaluate` hop, no round trip added |
|
|
386
|
-
| `
|
|
387
|
-
| `
|
|
550
|
+
| `browser_click` on an uncovered control | 460 ms median (3 runs, page-load settle included) |
|
|
551
|
+
| `browser_click` on the same control under a cookie banner | 630 ms median (3 runs) — the banner's own Accept click, a 150 ms beat, a re-probe, then the intended click |
|
|
388
552
|
| the same under a modal that offers to delete the account | 456 ms — reported, nothing pressed |
|
|
389
|
-
| one `
|
|
553
|
+
| one `browser_do` step on an uncovered control | 458 ms median (3 runs) |
|
|
390
554
|
| the same step under the cookie banner | 633 ms median (3 runs) — cleared, then the step ran |
|
|
391
555
|
|
|
392
556
|
A batch pays it once per step that has something over it, not once per call: a
|
|
@@ -411,10 +575,10 @@ is now done inside the call, by looking the control up by what it is.
|
|
|
411
575
|
|
|
412
576
|
| What | Number |
|
|
413
577
|
| --- | --- |
|
|
414
|
-
| `
|
|
415
|
-
| `
|
|
578
|
+
| `browser_click` on a control the page just redrew | **462 ms median, 483 ms max** (8 samples) — one extra read of the page's visible text, 600 chars, to find the control again |
|
|
579
|
+
| `browser_click` on a control that was not redrawn | 445 ms median, 446 ms max (8 runs) — the probe costs nothing when the number is still good |
|
|
416
580
|
| stale refs recovered this way | **8/8** |
|
|
417
|
-
| a control that really left the page | still refused, `Call
|
|
581
|
+
| a control that really left the page | still refused, `Call browser_view and use the new number` — 2/2 in the breadth suite |
|
|
418
582
|
|
|
419
583
|
So the recovery costs about **17 ms** when it is needed and nothing when it is
|
|
420
584
|
not, against a model round trip of two calls plus the tokens of a fresh read.
|
|
@@ -442,7 +606,7 @@ change mid-session. Changing it restarts the browser, so it costs a cold start:
|
|
|
442
606
|
| windowed → windowless, same profile and page | 22.1 s | one process, cold start |
|
|
443
607
|
| asking for the shape it already has | 0 ms | nothing is restarted |
|
|
444
608
|
|
|
445
|
-
Measured through the tool layer (`
|
|
609
|
+
Measured through the tool layer (`browser_open` → `browser_state` → `ps` spawn
|
|
446
610
|
args), profile `probe-tool`, 1 run each; the same-shape row is the third call in
|
|
447
611
|
the same run. A browser start on this machine is 20–22 s either way, so the
|
|
448
612
|
switch is not what costs — the process is.
|
|
@@ -458,9 +622,9 @@ bounded wait is the difference between a silent `viewers 0` and a sentence:
|
|
|
458
622
|
|
|
459
623
|
| what | cost |
|
|
460
624
|
| --- | --- |
|
|
461
|
-
| `
|
|
462
|
-
| `
|
|
463
|
-
| `
|
|
625
|
+
| `browser_open` with a tab watching | 0 ms |
|
|
626
|
+
| `browser_open` with nothing watching | ≤ 1.2 s, and the line says so |
|
|
627
|
+
| `browser_open` when the chat has no column to draw into | 0 ms (no wait) |
|
|
464
628
|
| building the sentence on a normal state read | 0 ms, one comparison |
|
|
465
629
|
|
|
466
630
|
Measured with `/tmp/probe-unseen.mjs` (tool layer, example.com, profile
|
|
@@ -490,7 +654,7 @@ reverse-contains (1).
|
|
|
490
654
|
|
|
491
655
|
| what the caller has | what it used to take | now |
|
|
492
656
|
| --- | --- | --- |
|
|
493
|
-
| a name for the field, no number | read the page, find the number, then type | one `
|
|
657
|
+
| a name for the field, no number | read the page, find the number, then type | one `browser_type` with `field`, one round trip |
|
|
494
658
|
| the field's words live in a div | click landed on the div, text went wherever focus was | resolved to the field, `typed into "Work email"` |
|
|
495
659
|
| a banner over the field | typed under the banner | banner cleared first, then typed |
|
|
496
660
|
|
|
@@ -500,7 +664,7 @@ Breadth check `type-by-words` on the `/bare` form: value lands in
|
|
|
500
664
|
## Phase 11 — choosing a dropdown by name, 0.21.0
|
|
501
665
|
|
|
502
666
|
`/bare` now carries a `select[name=seats]` whose only name on screen is a div
|
|
503
|
-
saying `Seats`. One `
|
|
667
|
+
saying `Seats`. One `browser_select` with `field: "Seats"`, `value: "Two"`:
|
|
504
668
|
|
|
505
669
|
| what | result |
|
|
506
670
|
| --- | --- |
|
|
@@ -534,7 +698,7 @@ Exact equality still wins over the squeezed form, so `Sign in` never lands on
|
|
|
534
698
|
| what | before | now |
|
|
535
699
|
| --- | --- | --- |
|
|
536
700
|
| `{field: "Birthday"}` | not found, fell back to clicking the div | found the hidden input, clicked its visible box |
|
|
537
|
-
| value after one `
|
|
701
|
+
| value after one `browser_do` step | whatever already had focus | `2001-02-03` in `#bd`, `typed into "Birthday"` |
|
|
538
702
|
| extra round trips | read the page, guess a number | none |
|
|
539
703
|
|
|
540
704
|
The visible-box rule: a candidate is usable when it, or its nearest visible
|
|
@@ -547,7 +711,7 @@ something the person can see.
|
|
|
547
711
|
|
|
548
712
|
| what | result |
|
|
549
713
|
| --- | --- |
|
|
550
|
-
| `
|
|
714
|
+
| `browser_grab` | 6 ms, `picture-check.png`, 140x90 |
|
|
551
715
|
| before | three round trips: list the images, ask for the full address, fetch it |
|
|
552
716
|
|
|
553
717
|
A picture page has no text at all, so a read of it costs one line and no tokens;
|
|
@@ -557,7 +721,7 @@ the picture comes back as a file path the person can open.
|
|
|
557
721
|
|
|
558
722
|
Two 140x90 PNGs: one a gradient, one a single colour.
|
|
559
723
|
|
|
560
|
-
| page | what `
|
|
724
|
+
| page | what `browser_grab` answers | time |
|
|
561
725
|
| --- | --- | --- |
|
|
562
726
|
| `/pic` | `... 140x90 a picture with detail` | 21 ms (first, page cold) |
|
|
563
727
|
| `/flat` | `... 140x90 mostly one colour` | 4 ms |
|
|
@@ -569,7 +733,7 @@ travels in the same line as the path.
|
|
|
569
733
|
|
|
570
734
|
| page | read line | extra round trips |
|
|
571
735
|
| --- | --- | --- |
|
|
572
|
-
| `/pic` (gradient, no words) | `picture 140x90 a picture with detail "Chart" —
|
|
736
|
+
| `/pic` (gradient, no words) | `picture 140x90 a picture with detail "Chart" — browser_grab saves it as a file` | 0 |
|
|
573
737
|
| `/flat` (single colour) | `picture 140x90 mostly one colour "Chart" — …` | 0 |
|
|
574
738
|
| `/words` (text page) | no picture line | 0 |
|
|
575
739
|
|
|
@@ -597,20 +761,20 @@ A changed scroll offset is still reported, so "nothing changed" is never a lie.
|
|
|
597
761
|
|
|
598
762
|
## Phase 20 — one call carries the question and the answer, 0.30.0
|
|
599
763
|
|
|
600
|
-
| step | before | `
|
|
764
|
+
| step | before | `browser_ask` |
|
|
601
765
|
| --- | --- | --- |
|
|
602
|
-
| type the message | `
|
|
603
|
-
| read the page | `
|
|
604
|
-
| read it again until the answer stops growing | 2–6 more `
|
|
766
|
+
| type the message | `browser_type` + `submit` | same, inside the call |
|
|
767
|
+
| read the page | `browser_view` | — |
|
|
768
|
+
| read it again until the answer stops growing | 2–6 more `browser_view` calls | — |
|
|
605
769
|
| **turns for a chat reply** | 3–7 | **1** |
|
|
606
|
-
| measured `
|
|
770
|
+
| measured `browser_ask` on `/chat` (answer over 2 arrivals, 700 ms tail) | — | 2.5 s, one turn |
|
|
607
771
|
|
|
608
772
|
## Phase 21 — a review round that closes the loop, 0.31.0
|
|
609
773
|
|
|
610
|
-
| step | before | `
|
|
774
|
+
| step | before | `browser_review` |
|
|
611
775
|
| --- | --- | --- |
|
|
612
776
|
| write the request (repo, commit, focus) | by hand, every round | built from three fields |
|
|
613
|
-
| send it, wait for the answer | `
|
|
777
|
+
| send it, wait for the answer | `browser_ask` | same call |
|
|
614
778
|
| turn the answer into a list | read it, retype it | parsed, numbering kept |
|
|
615
779
|
| know what the last round was about | — | round log, with the commit and the time |
|
|
616
780
|
| **turns for a review round** | 3–7 + bookkeeping | **1** |
|
|
@@ -686,7 +850,7 @@ session), three were real.
|
|
|
686
850
|
| --- | --- | --- |
|
|
687
851
|
| popup lookup | any non-main tab, then navigated or closed | only a target that is neither this page nor another chat's (`isForeign`) |
|
|
688
852
|
| focused password in a result line | echoed the `.value` (`DUMMY_SECRET_123`) | name only, value always empty |
|
|
689
|
-
| `
|
|
853
|
+
| `browser_do` on a step that did not land | kept going, typed into the wrong page | stops at that step, says to re-plan |
|
|
690
854
|
| overlay that would not clear | clicked the control under it anyway | refuses the click/typing, names the overlay |
|
|
691
855
|
| `changed_only` twice | repeated the same change | diff becomes the new baseline |
|
|
692
856
|
| `/sidecar/state` | top-level `url` could be another chat's tab | `?session=` adds `chat.url/title/viewers` (live: doubao page, viewers 1) |
|
|
@@ -717,3 +881,14 @@ not.
|
|
|
717
881
|
| human typing, >160 chars | 8-char bursts, 16–58 ms gaps, ≈6 ms per char |
|
|
718
882
|
| headless UA | desktop Chrome UA, no `HeadlessChrome` |
|
|
719
883
|
| suite | 70 pass, breadth 66, ui-copy clean |
|
|
884
|
+
|
|
885
|
+
## Flash 分支(Electron 11.3.0 / Chromium 87,1440×900,Apple 芯片 + Rosetta)
|
|
886
|
+
|
|
887
|
+
| what | measured |
|
|
888
|
+
| --- | --- |
|
|
889
|
+
| cold start to a driven page | 1389 ms(热启 545–927 ms) |
|
|
890
|
+
| first painted frame | 8–10 s(SWF 自己的加载;之前是 11 KB 白帧) |
|
|
891
|
+
| one frame via capturePage | 16 ms |
|
|
892
|
+
| frame size, JPEG q72 | 96–103 KB |
|
|
893
|
+
| mirror SSE | 15 fps(66 ms 一轮),4 s 收 60 帧,均值 97.8 KB |
|
|
894
|
+
| switch cost | 一次浏览器重启(`browser_open({flash:true})` → `browser_open({flash:false})`) |
|
package/docs/FLASH.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Flash 之后:把兼容性放在正确的位置上
|
|
2
|
+
|
|
3
|
+
Chrome 88(2021 年 1 月)拿掉 Flash,不是商业决定,是插件模型的失败:一个能直接操作音频、图形、网络和本地文件的第三方二进制,安全面等于浏览器本身,而它承担的内容又都可以用开放标准重写。结论对自研同样成立:**不要再造插件槽位,要造内容层的运行时。**
|
|
4
|
+
|
|
5
|
+
## 兼容的到底是什么
|
|
6
|
+
|
|
7
|
+
一个 SWF 只有四样东西是「约定」:
|
|
8
|
+
|
|
9
|
+
1. **标签流**——Shape/Sprite/Bitmap/Font/Sound/Frame 的二进制结构,决定画面怎么组出来;
|
|
10
|
+
2. **时间线**——`ShowFrame` 与帧率构成保留模式动画,帧可以跳、可以循环;
|
|
11
|
+
3. **AVM1 / AVM2 语义**——脚本看到的 DisplayObject、事件、`MovieClip`、`SharedObject`;
|
|
12
|
+
4. **安全模型**——跨域、socket 策略、本地存储。
|
|
13
|
+
|
|
14
|
+
只要这四样对得上,游戏就能跑。渲染用 Canvas2D 还是 WebGPU、时钟是实时还是虚拟、存储落 IndexedDB 还是宿主磁盘,**游戏看不见**。这就是「参考原理重做一个更好的」的立足点:兼容性锁在 AVM + 标签流,创新空间在其余全部。
|
|
15
|
+
|
|
16
|
+
## 分层设计
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
SWF ──▶ 摄入(读取标签流, 建 IR) ──▶ 显示列表 + 时间线 ──▶ 渲染(WebGPU, 损伤跟踪)
|
|
20
|
+
│
|
|
21
|
+
├─ AVM 兼容核(Ruffle wasm / 自研 AVM1 解释器)
|
|
22
|
+
├─ 虚拟时钟(固定步长, 输入带时间戳)
|
|
23
|
+
├─ 能力沙箱(网络/存储/剪贴板 走宿主代理, 可录可回放)
|
|
24
|
+
└─ 对象图内省(每帧把状态压成 JSON 差异, 给 agent 读)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
四层的分工决定了「比 Flash 好」不是同一维度的竞速:
|
|
28
|
+
|
|
29
|
+
| 维度 | Flash 的做法 | 这里的做法 | 可测指标 |
|
|
30
|
+
|---|---|---|---|
|
|
31
|
+
| 启动 | 装插件、NPAPI/PPAPI 握手 | 页面内 wasm,零安装 | 首帧 ms |
|
|
32
|
+
| 安全 | 插件进程 + 沙箱补丁 | 无原生代码,网络存储全代理 | 无提权面 |
|
|
33
|
+
| 确定性 | 真实时钟,帧率随机器 | 固定步长虚拟时钟 + 输入时间戳 | 同输入同结果 |
|
|
34
|
+
| 内省 | 无(黑盒像素) | 显示列表与 AVM 状态可导出 | 状态 → JSON 字节数 |
|
|
35
|
+
| 传输 | 屏幕像素 | 损伤区域 + 增量 | 每帧 KB |
|
|
36
|
+
| 回放 | 无 | 事件日志可重放 | 重放一致率 |
|
|
37
|
+
|
|
38
|
+
## 已落地:PPAPI 分支做成插件里的开关(本版)
|
|
39
|
+
|
|
40
|
+
「兼容层」和「能立刻玩」不是二选一。插件现在有两套运行时,同一个 CDP 管线、同一个镜像、同一套工具,切换只是一次重启:
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
browser_open({ flash: true, url: 'http://aola.100bt.com/play/play.html?from_h5=true' })
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
开的时候宿主用 Electron 11.3.0(Chromium 87,最后一个还认 PPAPI 的 Chromium)当浏览器,关的时候切回 Chrome。输入注入、导航、读页面、镜像全都不用改,因为两边都说 CDP。
|
|
47
|
+
|
|
48
|
+
三条必须同时成立的条件(缺一条就报「Flash 缺失」,且症状会骗人):
|
|
49
|
+
|
|
50
|
+
1. `--ppapi-flash-path` 指向 bundle **里的 Mach-O 可执行文件** `PepperFlashPlayer.plugin/Contents/MacOS/PepperFlashPlayer`,不是 `.plugin` 目录。指错目录时插件报 `No PPP_GetInterface in plugin library`——那是假象,不是导出缺失。
|
|
51
|
+
2. 必须加 `--no-sandbox`。否则 ppapi 进程报 `dlopen(...) (file system sandbox blocked open())`,页面提示没有 Flash。沙箱只对这一个隐藏的独立 profile 关,正常浏览器不关。
|
|
52
|
+
3. 宿主必须是 x86_64(Apple 芯片跑 Rosetta):插件只有 i386/x86_64 切片,arm64 Electron 装不进它。所以下载固定取 `darwin-x64`。
|
|
53
|
+
|
|
54
|
+
Electron 11 的两个真实限制,代码里已按它们写:
|
|
55
|
+
|
|
56
|
+
- 它不会用当前 Chrome 的 profile 目录(会降级并上锁),Flash 分支固定用 `<profile>-flash` 独立目录;两边登录态各自独立。
|
|
57
|
+
- `/json/new` 在 Chromium 87 上是 404,单窗口应用也没有第二个窗口,所以 Flash 分支不建新页签:会话要页签时把唯一那个窗口导航过去。
|
|
58
|
+
|
|
59
|
+
实测数字(Apple 芯片 + Rosetta,1440×900):
|
|
60
|
+
|
|
61
|
+
| 指标 | 值 |
|
|
62
|
+
|---|---|
|
|
63
|
+
| 冷启动到能驱动页面 | 1389 ms(首次含解压;同机热启 545–927 ms) |
|
|
64
|
+
| 页面首帧出图 | 约 8–10 s(SWF 自己的加载),之前是 11 KB 白帧 |
|
|
65
|
+
| 单帧 JPEG q72 | 96–103 KB |
|
|
66
|
+
| `capturePage` 取一帧 | 16 ms |
|
|
67
|
+
| 镜像 SSE 节奏 | 15 fps(66 ms 一轮),4 s 收 60 帧,均值 97.8 KB |
|
|
68
|
+
| PC 版判定 | 页面里出现 `EMBED .../weblogin/20171026_1.swf`、登录框是「多多号/手机/邮箱」而不是 H5 的样式 |
|
|
69
|
+
|
|
70
|
+
**不能随包分发 Adobe Flash Player**:插件本体留在本机状态目录(`~/.dsh/inner-browser-use/flash/plugin/`),由 `npm run flash:setup` 从本机已有的安装里找/拷,找不到就明说;Ruffle 那条路(MIT/BSD)仍是可分发的那条。
|
|
71
|
+
|
|
72
|
+
## 分阶段
|
|
73
|
+
|
|
74
|
+
- **M0 摄入(已发布)**:读 SWF 标签流,给出尺寸/帧率/AVM/资源构成。`runtime/swf.mjs` + `npm run swf`。
|
|
75
|
+
- **MP 立刻能玩(本版)**:PPAPI 分支 + 插件开关,见上节;`npm run flash:setup` 备运行时。
|
|
76
|
+
- **M1 能跑**:自托管 Ruffle + 宿主路由 + `embed/object` 自动 polyfill,在一个真实 SWF 上量首帧、fps、字节数。
|
|
77
|
+
- **M2 能读**:把 Ruffle 的 player 对象与显示列表接到 `browser_eval`,agent 直接读游戏状态,不用截图。
|
|
78
|
+
- **M3 更快**:损伤跟踪 + 增量帧传输;对同一游戏给出「Flash 版 vs 这里」的毫秒与 CPU 对比。
|
|
79
|
+
|
|
80
|
+
## 诚实边界
|
|
81
|
+
|
|
82
|
+
- AVM2 的兼容上限由兼容核决定;Ruffle 官方口径是「多数游戏能玩,仍有 API 缺口」,具体游戏要实测。
|
|
83
|
+
- Stage3D、加密 SWF、依赖本地插件的网游登录器,不在 M1–M3 的承诺内。
|
|
84
|
+
- ZWS(LZMA)本版明确拒绝;补 LZMA 是一天的事,但先要有真实影片来验证。
|
package/docs/ROADMAP.md
CHANGED
|
@@ -50,7 +50,7 @@ stealing the column from other chats.
|
|
|
50
50
|
|
|
51
51
|
## Phase 2 — one call, many steps (target: a login flow in 1 tool call)
|
|
52
52
|
|
|
53
|
-
- `
|
|
53
|
+
- `browser_do`: ordered steps with per-step waits (`wait_text`, `wait_gone`,
|
|
54
54
|
`wait_idle`, `wait_url`), one result: what changed, the final URL, tokens spent
|
|
55
55
|
on one read instead of five.
|
|
56
56
|
- Auto-wait after every action: navigation start/finish, DOM quiet, and
|
|
@@ -65,7 +65,7 @@ stealing the column from other chats.
|
|
|
65
65
|
- File upload (`DOM.setFileInputFiles`), download capture with a returned path,
|
|
66
66
|
print-to-PDF, full-page and element screenshots.
|
|
67
67
|
- Tabs: new / switch / close / list; iframes addressed by frame id; dialog
|
|
68
|
-
accept/dismiss; `
|
|
68
|
+
accept/dismiss; `browser_eval` for the last 1% of cases; cookies read/write for
|
|
69
69
|
debugging; console + failed requests surfaced in the state read.
|
|
70
70
|
- Keyboard: modifiers, shortcuts, clipboard paste, IME composition unchanged.
|
|
71
71
|
|
|
@@ -86,14 +86,14 @@ stealing the column from other chats.
|
|
|
86
86
|
|
|
87
87
|
- Human takeover (0.17.1): real input in the pane (click / text / wheel / key)
|
|
88
88
|
holds the agent's next action for 6 s and says so; hover and move do not count;
|
|
89
|
-
reads stay open; `
|
|
89
|
+
reads stay open; `browser_resume` takes the page back at once.
|
|
90
90
|
- Guarded actions (upload, download, close tab, buy-ish submits) can require a
|
|
91
91
|
confirm flag. Shipped in 0.14.0 for the narrow case that matters most: an
|
|
92
92
|
overlay in the way is cleared only when its own way out is a safe word
|
|
93
93
|
(accept / agree / close / 同意 / 关闭 …) and the overlay says nothing about
|
|
94
94
|
deleting, paying or signing out; otherwise it is reported, never taken.
|
|
95
95
|
Since 0.15.0 the same clearing runs before every control-naming step of a
|
|
96
|
-
`
|
|
96
|
+
`browser_do` batch, so a multi-step flow through a cookie wall fails zero times.
|
|
97
97
|
- Crash recovery: attach to a still-running Chrome, rebuild the page, keep the
|
|
98
98
|
profile; a killed host never leaves a zombie Chrome.
|
|
99
99
|
- Every failure names what happened, what state the page is in, and the next
|
|
@@ -124,10 +124,10 @@ finding the control again by identity (kind + exact words + link destination),
|
|
|
124
124
|
refusing when the words are not unique. Measured at 462 ms against 445 ms for a
|
|
125
125
|
fresh control — 17 ms when needed, nothing when not.
|
|
126
126
|
|
|
127
|
-
Since 0.16.1 the count is visible: `
|
|
127
|
+
Since 0.16.1 the count is visible: `browser_state` reports `refs followed N`,
|
|
128
128
|
and breadth asserts it moved after a redraw, so the next rounds can tell from
|
|
129
129
|
real sites whether redrawing is frequent enough to justify more work here.
|
|
130
|
-
Next in this direction: the same identity recovery for `
|
|
130
|
+
Next in this direction: the same identity recovery for `browser_do` steps that
|
|
131
131
|
name a field by its label when the label element is rebuilt (today the step
|
|
132
132
|
falls back to a fresh read).
|
|
133
133
|
|
|
@@ -142,7 +142,7 @@ then repeat the loop with whatever the numbers say is worst.
|
|
|
142
142
|
Two things were wrong at the edge of the tool surface, and both were only
|
|
143
143
|
reachable on real sites.
|
|
144
144
|
|
|
145
|
-
The first was that the shape of the browser could not change. `
|
|
145
|
+
The first was that the shape of the browser could not change. `browser_open`
|
|
146
146
|
accepted `headless: false` and answered success; when a browser was already
|
|
147
147
|
running nothing happened, because the flag was only read at launch. A site that
|
|
148
148
|
refuses a windowless browser (chatgpt.com on this machine: a "just a moment"
|
|
@@ -150,7 +150,7 @@ page forever, versus a login page in a windowed one) therefore had no way out
|
|
|
150
150
|
except killing a process by hand. Since 0.17.0 a request for the other shape
|
|
151
151
|
restarts the browser on the same profile, cookie jar and address — 21.6 s
|
|
152
152
|
windowless → windowed, 22.1 s back, 0 ms when the shape already matches — and
|
|
153
|
-
both `
|
|
153
|
+
both `browser_open` and `browser_state` say which shape is in front of the
|
|
154
154
|
person.
|
|
155
155
|
|
|
156
156
|
The second was silence on a check page. A site asking for proof of a person is
|
|
@@ -181,7 +181,7 @@ The tool used to treat "the control that says Email" as "the field called
|
|
|
181
181
|
Email". Real forms separate the two, so the writing step now resolves the words
|
|
182
182
|
to the element that takes text, and says which one it used.
|
|
183
183
|
|
|
184
|
-
Next in this direction: the same resolution for `
|
|
184
|
+
Next in this direction: the same resolution for `browser_type` when the caller
|
|
185
185
|
names a field by its words instead of a ref, and for date/time pickers where the
|
|
186
186
|
visible box is a div and the real input is hidden beside it.
|
|
187
187
|
|
|
@@ -189,15 +189,15 @@ visible box is a div and the real input is hidden beside it.
|
|
|
189
189
|
|
|
190
190
|
Typing by name is in. The same resolution is what other steps should be able to
|
|
191
191
|
use when the caller knows the destination but not the number — the next place
|
|
192
|
-
worth doing this is `
|
|
192
|
+
worth doing this is `browser_select` (choose an option by the field it belongs
|
|
193
193
|
to), and after that the date/time case where the visible box is a div and the
|
|
194
194
|
real input sits hidden beside it.
|
|
195
195
|
|
|
196
196
|
## Phase 12 — the same words, the same place, 0.21.0
|
|
197
197
|
|
|
198
|
-
`
|
|
198
|
+
`browser_select` joined `browser_type` and `browser_do` on the shared resolver.
|
|
199
199
|
Left in this direction: the date/time case where the box the user sees is a div
|
|
200
|
-
and the real input is hidden beside it, and `
|
|
200
|
+
and the real input is hidden beside it, and `browser_click` on a control whose
|
|
201
201
|
words are split across sibling nodes (`<span>Sign</span><span>in</span>`).
|
|
202
202
|
|
|
203
203
|
## Phase 13 — the page's spelling is not the caller's, 0.22.0
|
|
@@ -216,7 +216,7 @@ name, so the fallback has to be a picture plus a click, not a name lookup.
|
|
|
216
216
|
|
|
217
217
|
## Phase 16 — a file, not a path, 0.25.0
|
|
218
218
|
|
|
219
|
-
`
|
|
219
|
+
`browser_grab` returns a path. Next: say one line about the picture (size, and
|
|
220
220
|
whether it is mostly one colour) so a model that cannot open files still learns
|
|
221
221
|
"the chart is blank" without a full read.
|
|
222
222
|
|
|
@@ -248,7 +248,7 @@ at -3000,-3000, and the column shows the only picture.
|
|
|
248
248
|
|
|
249
249
|
## Phase 21 — a review round that closes the loop, 0.30.0
|
|
250
250
|
|
|
251
|
-
`
|
|
251
|
+
`browser_ask` sends and returns an answer. Next: a round trip that carries the
|
|
252
252
|
repository address there and the review back, and records in the round log which
|
|
253
253
|
commit the review was about, so a later round can tell whether the advice was
|
|
254
254
|
already taken.
|
|
@@ -298,6 +298,12 @@ The phases above were written one at a time as the work happened; the run from
|
|
|
298
298
|
|
|
299
299
|
## 页游这一档(2026-10-28 起)
|
|
300
300
|
|
|
301
|
+
- 操作方式已分叉(0.34.29):`browser_mode` 每个聊天记一种,`human` / `dom` 单次可覆盖。页游默认 human,登录/表单默认 dom 更省事。
|
|
302
|
+
- Flash 判死:headless Chrome 里 Ruffle 交得上 swf 但起不了画面(26 秒,canvas 0、metadata 0),不承诺。真页游只能走站方 H5 / 微端 / 老 360 浏览器,页面上线前先用 `scripts/probe-flash.mjs` 问一句它要不要 Flash。
|
|
303
|
+
- 开玩前先体检:`browser_prepare` 一次调用给出输入面、帧率、按键是否真的到得了框架、以及 Flash 结论(0.34.30)。4399《怪物小汽车》实测页面 58 fps、框架 59 fps —— 不少「Flash 小游戏」其实已经是 H5,先体检再下结论;`npm run ready <url>` 可复现。
|
|
304
|
+
- 读 SWF 标签流(`npm run swf`):尺寸、帧率、AVM 版本、资源构成,FWS/CWS 都读,ZWS 明确报不支持(0.34.32)。
|
|
305
|
+
- 空白画面的两种原因分开报(`viewers` / `listening chats` / `asks.log`),并在「浏览器在跑、没人画」时自己向所属会话补发一次开页签请求(0.34.31)。
|
|
306
|
+
|
|
301
307
|
输入这一层已经到位:按住键、组合键、按住鼠标,一项 300 ms 的按住整次调用 305 ms,事件由页面自己证实。实时画面沿用同一条 CDP 帧路(60 fps、镜像延迟中位数 8 ms)。
|
|
302
308
|
|
|
303
309
|
还差的一层是「看」:4399 / 7k7k / 奥拉星这类页游把画面画在 canvas 上,文本树里没有可读的东西,判断走位、Boss 血条、按钮位置都要靠像素。本会话的模型没有视觉能力,所以这里的正确做法不是假装能玩,而是把可判读的信号做出来:canvas 局部像素采样、颜色/区域变化率、画面是否在动(`blind` 行已经在报 canvas 数量)。有视觉能力的模型接着用同一套帧路就能玩。
|
|
@@ -311,7 +317,7 @@ Ranked by what a real task still loses:
|
|
|
311
317
|
HTTP and by pid, not by a person clicking. A browser-level test that opens the
|
|
312
318
|
column, kills the driver, and clicks restore is the missing evidence.
|
|
313
319
|
2. **One-click "open here" when this chat has no seat.** `state.chats` can lack this
|
|
314
|
-
chat, and the column then only tells the model to call `
|
|
320
|
+
chat, and the column then only tells the model to call `browser_open`. The button
|
|
315
321
|
belongs in the column.
|
|
316
322
|
3. **Competitor behaviours still unmatched.** Playwright MCP's accessibility refs are
|
|
317
323
|
ours, and the blind line covers the vision-less read; Stagehand v4's
|