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/ 为构建脚本审阅产物,不进仓库。
This commit is contained in:
1 parent
5e562d8413
commit
cbf5e65a7a
7 files changed
+79
-40
No files matched your search
@@ -34,7 +34,7 @@ Threading contract (unchanged from the socket version, measured
|
||||
2026-10-30: Playwright sync calls from any thread but the
|
||||
creating one raise "Cannot switch to a different thread"):
|
||||
only the MCP main thread touches the browser. It calls
|
||||
RemoteBridge.poll() on every idle main-loop iteration (~50ms),
|
||||
RemoteBridge.poll() on every idle main-loop iteration (~10ms),
|
||||
so control/input/frames flow even while the agent is idle, and
|
||||
CDP frame acks keep flowing (no ack = CDP stops after the
|
||||
first frame).
|
||||
@@ -57,7 +57,7 @@ CONTROL_NAME = ".browser-remote-control.json"
|
||||
STATE_STALE_SECONDS = 30
|
||||
# Heartbeat interval for state writes. The server treats state
|
||||
# older than STATE_STALE_SECONDS as dead, so 0.5s is plenty;
|
||||
# writing every ~50ms iteration was pure gofer round-trips.
|
||||
# writing every iteration was pure gofer round-trips.
|
||||
STATE_HEARTBEAT_SECONDS = 0.5
|
||||
|
||||
|
||||
@@ -190,7 +190,7 @@ class RemoteBridge:
|
||||
"""One drain-loop iteration: control, inputs, frame, state.
|
||||
|
||||
Writes are change-gated. The old code rewrote both files
|
||||
on every ~50ms iteration: ~20 atomic temp+replace
|
||||
on every iteration: ~200 atomic temp+replace
|
||||
round-trips per second through the runsc gofer mount for
|
||||
identical bytes (pump returns the latest frame
|
||||
persistently, and updated_at changes every call). Now the
|
||||
@@ -269,12 +269,14 @@ def read_state(workdir):
|
||||
def effective_holder(workdir, state):
|
||||
"""Server-side holder with the control race closed.
|
||||
|
||||
The MCP rewrites the state file every ~50ms, so right after
|
||||
a takeover the state file still shows the old holder. The
|
||||
The MCP polls every ~10ms idle and rewrites the state file
|
||||
at once when the holder changes (a key change bypasses the
|
||||
heartbeat throttle), so right after a takeover the state
|
||||
file still shows the old holder for at most ~10ms. The
|
||||
control file is the newer truth when its mtime is at or
|
||||
after the state's updated_at; otherwise the state file
|
||||
(already refreshed by a poll) wins. Both agree once the
|
||||
MCP has polled, so this only closes the ~50ms window.
|
||||
MCP has polled, so this only closes the ~10ms window.
|
||||
"""
|
||||
try:
|
||||
mtime = os.path.getmtime(os.path.join(workdir, CONTROL_NAME))
|
||||
|
||||
Reference in new issue
Block a user