ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

agent-browser 实时视口流(Live Streaming)协议与接入指南:WebSocket 推帧、远程输入与带宽控制

agent-browser 实时视口流(Live Streaming)协议与接入指南:WebSocket 推帧、远程输入与带宽控制 agent-browser 实时视口流Live Streaming协议与接入指南WebSocket 推帧、远程输入与带宽控制【免费下载链接】agent-browserBrowser automation CLI for AI agents项目地址: https://gitcode.com/gh_mirrors/agen/agent-browseragent-browser 的 Live Streaming 能力让浏览器视口以 JPEG 帧的形式通过 WebSocket 实时推送并把鼠标、键盘、触摸事件回传驱动页面这正是远程预览remote preview与嵌入式 Dashboard 所连接的后端浏览器运行在 daemon 所在之处沙箱、容器或 CI 机器而客户端负责渲染帧并回传点击。读完本文你将掌握如何启用流服务、如何连接并解析服务端消息、如何发送输入与控制消息以及如何用 push/ack 两种节奏与 per-client 帧率上限在受限链路上稳定消费实时视口。本文以 skill-data/core/references/streaming.md 为核心并结合 cli/src/native/stream/ 下的 Rust 源码mod.rs、websocket.rs、cdp_loop.rs与相关测试给出协议层面的事实依据。流式传输解决什么问题agent-browser 本身是面向 AI Agent 的浏览器自动化 CLI浏览器与 daemon 运行在同一台机器上Agent 通过命令操作页面。Live Streaming 把这一模型扩展到浏览器与客户端分离的场景——浏览器运行在 daemon 所在处一个沙箱、一个容器或一台 CI 机器客户端通过 WebSocket 连接ws://127.0.0.1:port接收视口帧并在本地渲染同时把点击和按键发送回去。远程预览与嵌入式 Dashboard 连接的就是这个流服务。流的核心设计目标有两个最新的帧永远优先以及输入不被帧的写入阻塞。前者由每客户端只保留最新一帧、发送时才读取保证后者由输入在独立任务中派发、不等浏览器回复保证详见下文消息与帧率两节。这与 skill-data/core/SKILL.md 中浏览器跨命令保持运行的会话模型一致流服务由 daemon 承载随会话生命周期启停。启用流服务流服务默认即可用——文档原话是 Streaming is always availabledaemon 启动时就会绑定一个由操作系统分配的 localhost 端口。通过以下命令管理agent-browser stream status --json # 报告启用状态、端口、客户端数 agent-browser stream enable # 创建流服务--port 可指定端口 agent-browser stream disable # 拆除流服务stream enable --port 9223可以固定端口不带--port时由操作系统分配。重复enable会返回 Streaming is already enabled for this session 错误见 cli/src/native/actions.rs端口参数须在 0-65535 范围内。stream disable会关闭服务器并清理会话的.stream元数据文件cli/src/native/actions.rs。stream status --json返回结构化状态源码中的字段包括enabled、port、connected浏览器连接是否存活、screencastingcli/src/native/actions.rs。务必从这里读取端口因为 OS 分配的默认端口对每个 daemon 都不同。AGENT_BROWSER_STREAM_PORT环境变量可以在整个 daemon 生命周期内固定端口而无需每次传--port。daemon 启动时读取该变量缺省为0表示由 OS 分配见 cli/src/native/daemon.rs。启动时若指定端口被占用daemon 会自动回退到 OS 分配端口而运行期stream enable命令则不会回退端口占用会直接报错见 cli/src/native/stream/mod.rs 中allow_port_fallback参数的语义。帧编码参数帧编码参数是 daemon 级daemon-wide的只在启动时读取一次变量默认值说明AGENT_BROWSER_STREAM_QUALITY80JPEG 质量0 到 100越界会被钳制clampAGENT_BROWSER_STREAM_MAX_WIDTH视口宽度限制帧的宽度上限不会改变页面本身尺寸AGENT_BROWSER_STREAM_MAX_HEIGHT视口高度同上这些变量由ScreencastConfig::from_env()读取、parse()解析cli/src/native/stream/mod.rs解析规则值得注意quality先解析为i32再用clamp(0, 100)钳制——CDP 对越界 quality 的行为是接受但忽略会让配置看起来没生效所以这里选择主动钳制max_width/max_height必须能解析为u32且大于 0、不超过i32::MAX否则被丢弃、保留默认视口尺寸。测试覆盖了0、-100、wide、4294967295等非法输入cli/src/native/stream/mod.rs维度默认为None是有意为之注释明确说明max_width/max_height只是覆盖值None时使用会话视口若默认成固定尺寸反而会把更大的视口全部缩小。编码之所以固定 JPEG 且不提供格式开关是因为frame消息本身没有 format 字段——daemon 级切换格式会让已连接的客户端盲解。不过文档也指出显式的screencast_start会重新配置同一个底层 screencast客户端中途仍可能看到格式变化以字节嗅探sniff the bytes为准不要假设格式cli/src/native/stream/mod.rs。带宽量级参考文档在 1280x720 的繁忙页面上实测quality 80 约 54 KB/帧quality 20 约 25 KB/帧quality 20 且 640x360 时约 9 KB/帧。这直接决定了受限链路上的参数选择。底层推流由 CDP 的Page.startScreencast驱动参数为format: jpeg、quality、maxWidth/maxHeight缺省用视口、everyNthFrame: 1见 cli/src/native/stream/cdp_loop.rs。从该源码还可以看到只有engine chrome的会话才支持 screencastsupports_screencast is_chrome非 Chrome 引擎如 LightPanda不会启动帧推流status消息中的screencasting会是false。连接与来源校验连接方式极简WebSocket 客户端直接连ws://127.0.0.1:port。没有订阅消息——客户端一旦接入帧就开始自动投递连接建立时服务器会先发送status、已知的tabs并把最新一帧作为种子帧推给新客户端见 cli/src/native/stream/websocket.rs。服务端对浏览器客户端有来源Origin白名单限制只允许来自localhost、127.0.0.1、::1或file://的页面连接其他任何 Origin 会在 WebSocket 升级阶段收到403错误信息 Origin not allowed需要前置代理才能访问。实现位于握手回调中对Origin头的校验cli/src/native/stream/websocket.rs白名单判定逻辑is_allowed_origin在 cli/src/native/stream/mod.rs。同时HTTP 层的敏感端点chat、models 等也会按同一白名单反射 CORS 头避免 API key 被任意网页读取cli/src/native/stream/http.rs。e2e 测试中有一个直接用Origin: https://evil.example发起的跨源命令请求被拒绝的用例cli/src/native/e2e_tests.rs。服务端消息Server → Client所有消息都是带type字段的 JSON 文本。frame视口图像及其元数据帧是流的主体按最新优先latest-first投递机制见下一节。示例{ type: frame, seq: 41, data: base64-encoded-jpeg, metadata: { deviceWidth: 1280, deviceHeight: 720, pageScaleFactor: 1, offsetTop: 0, scrollOffsetX: 0, scrollOffsetY: 0, timestamp: 1785038682238 } }字段含义字段说明seq单调递增的帧 idack 节奏下被回显且跨浏览器重启保持递增database64 编码的 JPEG 图像metadata.deviceWidth/deviceHeight视口尺寸metadata.pageScaleFactor页面缩放因子metadata.offsetTop/scrollOffsetX/scrollOffsetY视口相对页面内容的位置metadata.timestamp捕获时刻的 epoch 毫秒Date.now() - timestamp即该帧的年龄seq的单调性由进程级原子计数器FRAME_SEQ保证cli/src/native/stream/mod.rs并有用例test_frame_ids_survive_a_stream_server_restart验证服务器重启后 id 仍递增cli/src/native/stream/mod.rs。timestamp由 CDP 的Network.TimeSinceEpoch浮点秒乘以 1000 转换而来直接按整数读会得到 0cli/src/native/stream/cdp_loop.rs 及对应测试。status/tabs/url/consolestatus连接状态、screencasting 标志、视口尺寸、引擎、录制标志。连接时发送一次之后每次状态变化再发。tabs当前标签页列表连接时若已知和变化时发送。url仅在 Chrome 上发送覆盖活动标签页主框架main frame的整页导航、History API 导航和 fragment 导航子框架child-frame与后台标签页的导航会被忽略。实现上由Page.frameNavigated与Page.navigatedWithinDocument事件驱动并先通过Page.getFrameTree确认主框架 idcli/src/native/stream/cdp_loop.rs。console控制台事件。通道语义差异重要status、tabs、url、console走有序通道——按序投递且不会像帧那样被新消息顶替。但它们并非无条件可靠客户端落后太多会从该通道掉队丢失从未见过的消息。因此文档明确建议把 console 输出当作实时流live feed而不是审计日志audit log。从源码看有序消息走 tokiobroadcast通道容量 64帧走watch通道只保留最新值——这就是两种通道语义差异的来源cli/src/native/stream/mod.rs。客户端消息Client → Server客户端可发送以下消息{type: input_mouse, eventType: mousePressed, x: 40, y: 40, button: left, clickCount: 1} {type: input_keyboard, eventType: keyDown, key: a, text: a} {type: input_touch, eventType: touchStart, touchPoints: []} {type: config, maxFps: 10} {type: config, pacing: ack} {type: ack, seq: 41}输入派发的底层行为输入在独立的任务中派发到浏览器与帧投递互不阻塞——一次点击不会排队等在一帧之后。事件不等浏览器回复就发出send_command_no_wait所以一次点击不会卡在一串鼠标移动之后。顺序保持press 永远不会越过 move。所有派发命令共享同一 socket 互斥锁、按调用顺序发送cli/src/native/stream/websocket.rs。测试test_input_dispatch_does_not_wait_for_a_cdp_reply用一个永不回复的模拟 CDP 服务器验证了不等待回复的行为cli/src/native/stream/websocket.rs。鼠标、键盘、触摸输入还会重置 daemon 的空闲计时器idle_activity.mark()因此被持续远程驱动的预览不会被空闲超时关掉cli/src/native/stream/websocket.rs。注意只有真正派发到 CDP 的输入才算活动。input_mouse支持的事件类型包括mouseMoved/mousePressed/mouseReleased等默认mouseMovedinput_keyboard支持keyDown/keyUp/char默认keyDowninput_touch支持touchStart/touchMove/touchEnd等默认touchStart。键盘消息中省略的可选字符串字段key、code、text会被整体省略而不是发null——CDP 会因 null 字符串拒绝整个命令导致按键静默丢失cli/src/native/stream/websocket.rs。config每客户端帧率上限config消息设置每客户端per-client的帧率上限maxFps1 到 1200表示不限默认值立即生效包括放宽上限的情况测试test_loosening_cap_midstream_takes_effect_immediately验证了放宽后不再等待旧的节流期限见 cli/src/native/stream/mod.rs各客户端的上限互相独立不影响其他连接大于 120 的值钳制到 120常量MAX_CONFIGURABLE_FPS 120见 cli/src/native/stream/websocket.rs负数或非数字值被忽略保持现有上限两种情况都不会拒绝连接。把设置放在 URL 上两个设置也可以放在 URL 查询参数里这是**唯一能覆盖连接首帧opening frame**的方式ws://127.0.0.1:port/?pacingackmaxFps10原因很直接种子帧在config消息到达之前就已写入。连接建立后发送的config消息仍然优先会覆盖 URL 上的设置。URL 解析在 cli/src/native/stream/websocket.rs 的config_from_upgrade中实现并有测试验证 URL 设置的 ack 节奏能覆盖首帧cli/src/native/stream/mod.rs。帧率与陈旧帧处理这是整个协议最有价值的部分应用层永远不堆积陈旧帧。最新帧优先latest-frame-wins服务器对每个客户端只保留最新一帧并在发送时读取watch通道的borrow_and_update。在一帧尚未写完时产生的新帧会被跳过而不是排队因此应用永远不会构建积压backlog。测试test_new_client_receives_latest_frame_only验证新客户端只会收到最新帧而非历史帧cli/src/native/stream/mod.rs。push 节奏默认默认的 push 节奏在此处截止底层传输TCP/WebSocket仍然有序——已经被 socket 接受的帧会按序送达所以一个停顿的客户端会先排干内核缓冲区的数据然后写线程才会阻塞。也就是说push 模式无法避免停顿后恢复要消化历史帧的问题。ack 节奏推荐用于受限链路发送{type:config,pacing:ack}后服务器同时最多只有一帧在途等收到{type:ack,seq:N}才发下一帧每一帧都带单调seq客户端应回显自己渲染完成的那一帧的 seq在 ack 未返回期间产生的新帧互相顶替永远不会到达 socket——所以一个停顿 10 秒的客户端恢复后拿到的是当前页面而不是 10 秒的历史测试test_ack_pacing_holds_one_frame_and_skips_to_newest验证ack 释放且只释放最新帧见 cli/src/native/stream/mod.rs。ack 节奏的吞吐边界一帧在途时速率约等于一次传输 一次确认往返同时受带宽和延迟约束若链路的带宽-延迟积超过单帧大小链路就会利用不足。另有几点工程细节ack 只约束一跳one hop路径中有代理时应转发渲染端生成的 ack若代理在收到帧时就本地生成 ack帧会堆积在对端。ack 是累计的确认更新的 id 覆盖所有更旧的帧。客户端乱序渲染或跳过中间 id 都不会卡死写线程send_if_modified保证水位只前进不后退见 cli/src/native/stream/websocket.rs。客户端启用 ack 节奏后停止 ack只是停止收帧status、tabs、url、console仍会继续流动。提前 ack 未来的 id 也不会卡死写线程测试test_ack_ahead_of_the_stream_does_not_wedge_the_writercli/src/native/stream/mod.rs切回 push 会立刻释放正在等 ack 的那帧test_leaving_ack_pacing_releases_the_held_frame。两个设置如何组合pacing限制在途量in flightmaxFps限制速率rate。受限链路上的预览通常两者都要{type: config, pacing: ack, maxFps: 10}或直接在 URL 上声明ws://127.0.0.1:port/?pacingackmaxFps10。局限性Limitations仅限本机localhost only。把流暴露到机器之外是接入方embedder的职责——隧道、代理或端口转发且 Origin 白名单只适用于浏览器客户端。帧是图像不是视频编码。带宽随视口尺寸和页面活跃度增长受限链路请用maxFps/quality 控制速率。push 节奏下服务器无法区分渲染慢与渲染快的客户端只有传输背压这一条线索。当这个区分很重要时改用 ack 节奏。相关资源命令全量参考skill-data/core/references/commands.md快速上手skill-data/core/SKILL.md。流服务核心实现cli/src/native/stream/mod.rs服务器与配置、cli/src/native/stream/websocket.rs连接与消息处理、cli/src/native/stream/cdp_loop.rsCDP 事件到流消息的转换。流命令enable/disable/status的入口与状态字段cli/src/native/actions.rs。环境变量完整清单含AGENT_BROWSER_STREAM_PORT/QUALITY/MAX_WIDTH/MAX_HEIGHTcli/src/output.rs。基于该流构建的嵌入式 Dashboard 位于 packages/dashboard/其启动与--allowed-origins配置说明见 skill-data/core/SKILL.md。【免费下载链接】agent-browserBrowser automation CLI for AI agents项目地址: https://gitcode.com/gh_mirrors/agen/agent-browser创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表