前言¶
DeepSeek Harness(DSH)在智能体开发中常配合 ego lite 浏览器完成网页操作。但 DSH 进程和 ego 宿主是两个独立进程,两者之间没有现成的通信管道。开发者想要在 DSH 的侧边栏里看到 ego 当前的操作画面,通常只能依赖截图工具或远程桌面,既不实时,也会拖慢 ego 的渲染性能。
ego-liveview 插件解决了这个问题:它在 DSH 的侧边栏里提供一个 tab,实时显示 ego lite 浏览器的画面,帧率在 60–80 fps,单帧约 17–25 KB,不需要额外端口,也不占用 ego 的渲染管线。
插件定位¶
ego-liveview 是一个 DSH 客户端插件,由维护者 xieyh2002 开发,分类为「客户端」。它的核心价值是在 DSH 和 ego 之间建立一条低延迟的图像传输通道,让 DSH 的侧边栏能像预览一样看到 ego 当前的页面状态。
安装与启用¶
这个插件不在官方仓库,需要先克隆源码,再手工挂载到 DSH 的 profile 里。
- 克隆仓库
git clone https://github.com/xieyh2002/ego-liveview.git
- 加依赖到 profile 的 package.json
编辑 %USERPROFILE%\.dsh\profiles\desktop\package.json,在 dependencies 里添加:
"@local/ego-liveview": "link:C:/path/to/ego-liveview"
再把 "@local/ego-liveview" 加进 dsh.profile.bundles 数组。
- 在 Windows 下建立目录链接
cd %USERPROFILE%\.dsh\profiles\desktop\node_modules
mklink /J ego-liveview C:\path\to\ego-liveview
(Windows 下 ln -s 不可靠,会把目录复制成真目录,所以使用 junction。)
- 挂载到 cordis
在 %USERPROFILE%\.dsh\profiles\desktop\cordis.patch.yml 末尾添加:
- insert:
- id: ego-liveview
name: "@local/ego-liveview"
config: {}
- 重启 DSH
使用方式¶
-
在 DSH 右侧边栏的标签列表里点击 +,选择「ego 浏览器」(英文界面为 ego browser)。
-
有画面即表示连接成功。底栏会显示当前页面标题、帧率和单帧大小。
-
在 DSH 里用 ego skill 操作浏览器时,侧边栏画面会同步更新,无需额外配置。
插件会自动跟随:它扫描 ego 的所有 TaskSpace,选择最新有内容的页面;页面切换或新开 space 时会自动切换,不需要手动指定。
工作原理¶
ego lite 没有对外暴露 TCP 或 CDP 端口,第三方进程无法直接连进去。唯一的入口是在 ego 宿主进程里运行的 ego-browser nodejs 脚本。
ego-liveview 的实现思路是:
- 在 ego 宿主进程里启动一个 pump,调用
Page.startScreencast获取 JPEG 帧。 - 通过 Windows 命名管道把帧数据发送到 DSH 进程,格式为
[1B type][4B len][payload]。 - DSH 侧边栏的插件通过
ctx.webServer.register暴露/ego-live/stream.mjpg,以 MJPEG(multipart/x-mixed-replace; boundary=frame)方式输出画面。 - 侧边栏 tab 里是一个
<img>,直接拉取流。
不用额外端口、不用 WebSocket(ego 工作区没有 ws 包)、MJPEG 不被 gzip 压缩(multipart/x-mixed-replace 不在 compressible 表里)。
路由说明¶
| 路由 | 说明 |
|---|---|
GET /ego-live/stream.mjpg |
MJPEG 流,multipart/x-mixed-replace; boundary=frame |
GET /ego-live/frame.jpg |
单帧快照 |
GET /ego-live/status |
JSON 状态(看的哪个 space/页面、fps、viewers…) |
访问限制:只允许 loopback(Host 头必须是 127.0.0.1 / localhost / [::1]),否则返回 403。
启动时机与生命周期¶
ego-liveview 不会在插件加载时自动启动。插件加载后处于待命状态:不 spawn ego-browser、不碰 ego 窗口、不占用管道。
只有当侧边栏的那个 tab 真的在拉流(viewers.size > 0)时,bridge 才会启动;最后一个观众离开后立刻释放(releasing bridge (last viewer left))。
这一点很重要,因为 ego-browser CLI 会连带拉起一个完整的 ego 实例(ego-browser.exe → ego.exe --startup-ego-browser-service)。如果在加载时预热,等于 DSH 一启动就多一个浏览器进程和一个没人看的新标签页窗口。
看门狗同样受这个门控:没人看的时候它不会重启任何东西,只会把残留的 bridge 收掉。所以 taskkill /IM ego.exe /F 之后的行为是——有观众就恢复,没观众就不恢复。
三个必须知道的坑¶
1. ego 的窗口必须是「显示过」的状态。
老版本 ego(0.6.0.16)在用 --startup-ego-browser-service 启动时窗口是隐藏的(IsWindowVisible=false)。隐藏窗口的合成器一帧都不提交:Page.screencastFrame 不来,Page.captureScreenshot 直接超时。
在这种情况下,把 showWindow 配置项打开,bridge 会调用 bridge/wake-windows.ps1,用 ShowWindow(hwnd, 7)(SW_SHOWMINNOACTIVE,最小化、不抢焦点、不挡屏)把隐藏的 Chrome_WidgetWin_1 窗口显示一下;只要显示过一次,之后就一直出帧。
0.6.0.20 起 ego 的 service 实例本身就带一个可见窗口,wake 脚本什么也命中不了,所以 showWindow 默认关闭,不去动别人应用的窗口可见性。
2. 千万别在要跑 screencast 的 target 上调 Page.captureScreenshot。
窗口最小化时截图会报 Cannot capture a screenshot while the window is minimized. 并超时,而这个超时会让该 target 的 screencast 永久不再出帧(重启 ego 才能恢复)。早期所有「0 帧」的排查都是踩在这上面。要帧就用 screencast,不要混着截图。
3. ego 长时间跑过之后,取帧管线会整体失效,重启 ego 才回来。
症状:/ego-live/status 里 ok:true、metadata 正常刷新、watched 指向正确页面,但 framesSeen 不涨、lastFrameAgeMs 一直变大、侧边栏画面冻住。此时窗口状态、rAF、Performance.getMetrics 的 Frames 计数都正常(说明页面在渲染),只有 screencast 不出帧,Page.captureScreenshot 超时、stopScreencast+startScreencast 也救不回来。
实测在 ego 连续跑约 3 小时后出现,重启 ego 后立刻恢复到 65–85 fps。重启 ego 会让所有 TaskSpace 清空,插件会显示「ego 里还没有打开的网页」,让 dsh 重新开一个页面即可。
其它实测数据:单进程内 screencast 稳定 58–82 fps、JPEG q60 960×600 约 17–25 KB/帧、首个管道连接 118ms、首帧 459ms。静态页面不出帧是正常行为(screencast 只在合成器有变化时发帧),所以 ensureBridge() 判活用的是 metadata 心跳而不是帧到达。
配置项¶
cordis.patch.yml 里的 config:
| 键 | 默认 | 说明 |
|---|---|---|
quality |
60 |
JPEG 质量 |
maxWidth / maxHeight |
960 / 600 |
缩放上限(比这大的页面会被缩) |
space |
'' |
空 = 自动跟随最新 space;填名字或 id 就固定看那个 |
idleTimeoutMs |
20000 |
多久没心跳就重启 bridge |
healthCheckMs |
5000 |
看门狗检查间隔;0 关闭(不推荐,见下) |
showWindow |
false |
把隐藏的 ego 窗口显示成最小化(只在老版 ego 上需要) |
egoBinary |
ego-browser |
CLI 路径 |
healthCheckMs 不能关:MJPEG 的 <img> 是一个长连接,断了之后浏览器不会再发新请求,所以没有看门狗的话管道一死侧边栏就永久冻住,直到用户手动刷新页面。看门狗判活用的是 metadata 心跳而不是帧到达(静态页本来就不出帧),而且它只在有观众时才动手。
想让插件完全不干涉 ego 的启动(比如你自己管 ego 的生命周期),把 healthCheckMs 设 0 并别打开那个 tab 就行——没有人拉流,bridge 根本没起来。
改完代码要重启 DSH 才生效(bridge.mjs 只在插件加载时复制到 %TEMP%\ego-liveview-runtime\,运行中的 pump 是内存里的旧版)。
文件结构¶
index.js host 半边:三个路由 + 管道客户端 + bridge 进程生命周期
client.js 客户端半边:__ModuleLoader__ 模块,注册 better-sidebar tab
bridge/bridge.mjs 在 ego 宿主里跑的 pump:扫描 space → screencast → 写管道
bridge/wake-windows.ps1 显示隐藏的 ego 窗口
依赖 ctx.webServer(host)和 ctx.get('betterSidebar')(client)。better-sidebar 不在就静默不注册,不报错。
局限¶
- 只能看,不能操作。 tab 里是一个
<img>,点击/滚动不会传给 ego。要操作还是让 dsh 调 ego skill。做成可交互需要把鼠标事件转成 CDPInput.dispatchMouseEvent并做坐标缩放,没做。 - 只跟随一个页面。 多标签时跟随
active那个;ego 里切标签会跟着切,但侧边栏里看不到「其他标签」。 - Windows only。 命名管道和窗口唤醒(
user32.dll)都是 Windows 接口。 - 静态页面 fps 会很低(甚至 1–2)。这不是故障——Chromium 的 screencast 只在合成器有变化时发帧。所以 bridge 判活用的是 metadata 心跳,不是帧到达。
License¶
MIT
参考资料¶
- 插件目录页:https://www.skillhub.cn/plugins/xieyh2002/ego-liveview
- GitHub:https://github.com/xieyh2002/ego-liveview