关于 kimi-webbridge
kimi-webbridge 是供 Agent 使用的技能,通过本地守护进程操作用户浏览器,包括使用用户登录会话的页面。它提供网页交互与检查工具,并包含将网站调研整理为可复用 CLI 工具或脚本的流程。
主要功能
- 01导航并管理浏览器标签页
- 02通过无障碍快照读取页面
- 03点击元素并填写字段
- 04截取页面并保存为 PDF
- 05检查网络请求与响应
- 06创建网站 CLI 的工作流程
适用场景
- 01跨网页调研信息
- 02在现有浏览器会话中填写表单
- 03探索网站时检查页面请求
- 04根据网站调研构建可复用 CLI
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mxyhi/ ok-skills --skill kimi-webbridge安装后在 Claude Code 中输入/kimi-webbridge确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/operations.mdreferences/cli-creator/companion-skill-template.mdgo-layout.mdlogin-handling.mdsite-exploration.mdworkflow.md详细介绍
Kimi 浏览器扩展(原名 Kimi WebBridge)
通过本地守护进程 http://127.0.0.1:10086 控制用户的真实浏览器(及其登录会话)(这是默认地址;地址不同时,请参阅工具调用失败时)。
当用户要求为某个网站构建可复用的 CLI 工具或脚本(而非执行一次性任务)时,请遵循 references/cli-creator/workflow.md。其中的阶段说明了何时阅读以下各项:
references/cli-creator/site-exploration.md——查找每项功能如何获取数据的协议references/cli-creator/login-handling.md——网站需要登录时references/cli-creator/go-layout.md——CLI 使用 Go 编写时references/cli-creator/companion-skill-template.md——用于指导 Agent 如何使用 CLI 的技能模板
工具
| 工具 | 参数 | 返回值 | 说明 |
|---|---|---|---|
navigate | url、newTab(bool)、group_title | {success, url, tabId} | 首次调用会打开一个标签页——请参阅标签页。group_title 用于设置标签组的可见名称 |
find_tab | url、active(bool) | {success, url, tabId, borrowed} | 重新选择本次会话打开的标签页;active:true 会借用用户正在查看的标签页——请参阅标签页 |
snapshot | 可选的 ref;format:"aria" 可选择返回文本,并可指定 max_chars(1–60000)或 cursor 以继续 | 默认 {url, title, tree};ARIA {url, title, tree_text} | 无障碍树(文本)——用于读取页面内容和定位元素 |
click | selector(@e 引用或 CSS) | {success, tag, text} | 合成的 el.click() |
fill | selector、value | {success, tag, mode} | 适用于 <input>/<textarea> 以及 [contenteditable](ProseMirror/Lexical/Slate)。mode 为 "value" 或 "contenteditable" |
evaluate | code(要使用 await,请将其包装在 async IIFE 中——顶层 await 会导致 SyntaxError) | {type, value} | |
cdp | method、params | 原始 CDP 响应 | 原始 chrome.debugger 直通接口——对于 JS,evaluate 是什么,cdp 对 CDP 就是什么。适用于上述工具无法处理情况的底层逃生通道。Page.bringToFront 是最后手段:当标签页的焦点模拟关闭时,调用它会开启焦点模拟,而不是激活标签页(标签页会渲染并接收真实输入,但不会切换到该标签页);只有在模拟已开启后调用,才会激活标签页;并且绝不会将 Chrome 切换到用户正在使用的其他应用之上。Target.activateTarget 会被拒绝 |
screenshot | format(png|jpeg)、quality(0-100)、可选的 selector(@e/CSS)、可选的 path | {format, path, sizeBytes, mimeType} | 返回文件路径,而非 base64——请参阅屏幕截图 |
network | cmd(start|stop|list|detail)、filter(URL 子字符串,用于 list)、requestId(用于 detail) | list:{count, requests:[{requestId, url, method, status, mimeType, completed}]};detail:该请求及 requestHeaders、requestBody、body(响应) | 按标签页捕获,从调用 start 时开始。请在调用 stop 前调用 detail——停止捕获会释放响应正文,此后 detail 会返回 bodyError 而非 body |
upload | selector、files(string[]) | {success, fileCount} | |
save_as_pdf | paper_format、landscape、scale、print_background、可选的 path | {path, sizeBytes, mimeType, pageTitle} | 将当前页面渲染为 PDF,并返回文件路径——请参阅将当前页面另存为 PDF |
list_tabs | — | {success, tabs:[{tabId, url, title, active, groupTitle}]} | 查看当前会话中的标签页 |
list_browser_tabs | — | {success, tabs:[{tabId, windowId, url, title, active}]} | 查看此 WebBridge 连接在所有窗口中可见的全部标签页;不会附加或聚焦任何标签页 |
attach_tab | tabId | {success, tabId, url, title, borrowed} | 将指定的现有标签页附加到本次会话,而不聚焦它;借用的标签页在调用 close_session 后仍会保持打开 |
close_tab | — | {success, closed: bool} | 关闭会话中的当前标签页 |
close_session | — | {success, closed: int} | 关闭本次会话打开的标签页;借用的标签页保持打开。closed 为关闭的标签页数量。何时调用,请参阅会话 |
标签页和当前标签页
单标签页工具(snapshot、click、fill、screenshot、save_as_pdf)会在当前标签页上执行操作——即你最近通过 navigate 打开、通过 find_tab 选中或通过 attach_tab 附加的标签页。
- 打开页面:如果需要让多个页面并存(用于比较、交叉引用),请使用
newTab:true;如果要将当前标签页转到新 URL,则省略该参数。 - 返回较早打开的标签页:调用
find_tab,重新将你在本次会话中较早打开的标签页设为当前标签页。传入标签页的 URL——可从list_tabs或较早的navigate结果中获取。匹配依据是主机名:kimi.com也能找到www.kimi.com标签页,且会忽略路径。默认情况下,find_tab只搜索本会话自己的标签页,不会访问用户的其他标签页或窗口。 - 操作用户已经打开的页面:调用
list_browser_tabs,根据 URL/标题和tabId选择标签页,然后用该 ID 调用attach_tab。此方法也适用于其他窗口中的标签页,且不会改变用户当前的前台标签页。附加的标签页是借用的,在调用close_session后仍会保持打开。对于用户当前正在查看的特定标签页,使用find_tab并设置active:true仍然有效。 - 如果
find_tab报错"no tab matching … in this session",说明该页面未在本会话中打开——请改用navigate并设置newTab:true。
curl -s -X POST http://127.0.0.1:10086/command \
-d '{"action":"find_tab","args":{"url":"https://www.kimi.com","active":true},"session":"k26-research"}'
调用格式
每条命令都包含一个顶层 session,用于指定当前任务——请参阅下文的 会话。后续章节中的示例仅为简洁起见省略了它;实际调用时请务必包含。每条回复都是一个信封:成功时为 {"ok":true,"data":…}(上方的返回值列描述了 data),失败时为 {"ok":false,"error":{"code","message"}}。命令格式取决于用户的操作系统。
macOS / Linux——可以使用内联 JSON:
curl -s -X POST http://127.0.0.1:10086/command \
-H 'Content-Type: application/json' \
-d '{"action":"navigate","args":{"url":"https://example.com","newTab":true,"group_title":"My task"},"session":"my-task"}'
如果内联调用失败——例如 bash 返回 shell 引号/语法错误,或守护进程返回 HTTP 400——不要原样重试同一条命令。请将请求作为文件正文重新发送:
- 使用你自己的文件写入工具,将 JSON 正文写入一个唯一命名的临时文件——不要使用 shell
echo/heredoc,因为它们会以同样的方式破坏 JSON。每个请求都使用一个新文件名(例如/tmp/webbridge-req-<random>.json)。 - POST 该文件:
curl -s -X POST http://127.0.0.1:10086/command -H 'Content-Type: application/json' --data-binary @/tmp/webbridge-req-<random>.json
- 请求返回后立即删除临时文件。
Windows(PowerShell / cmd)——shell 会破坏命令参数或管道中内联传递的非 ASCII 字符(如中文);这些字符到达守护进程时会变成 ?,且无法恢复。所有请求都必须作为文件正文发送:
- 使用你自己的文件写入工具,将 JSON 正文写入一个唯一命名的临时文件——不要使用 shell
echo/heredoc,因为它们同样会破坏非 ASCII 字符。每个请求都使用带随机后缀的独立文件名(例如webbridge-req-<random>.json),以免并发请求共用同一个文件并相互覆盖。 - 使用
curl.exePOST 该文件——始终使用curl.exe,不要使用裸curl,因为 Windows PowerShell 会将其别名映射到Invoke-WebRequest:
curl.exe -s -X POST http://127.0.0.1:10086/command -H "Content-Type: application/json" --data-binary "@$env:TEMP\webbridge-req-<random>.json"
- 请求返回后立即删除临时文件——不要将请求正文留在磁盘上。
会话
一个任务 = 一个会话 = 一个标签页组。 session 会将任务打开的所有标签页收集到一个标签页组中,让用户能在一个组中看到“Agent 当前正在做什么”。将其作为请求正文的顶层字段传入(不要放在 args 内)。
- 在任务开始时选定一个会话名称,将其用于每条命令,任务中途绝不切换——即使跨不同网站也一样。 按网站切换会话名称是标签页组分散的头号原因。
- 会话名称应体现任务,而非网站(
camping-research、phone-compare)。只有真正无关的并行任务才使用多个会话。 group_title是供用户阅读的组标签——请用用户的语言填写,并在任务中的第一个navigate时设置。- 创建组时(任务中的第一个
navigate),告知用户一次:此任务的页面会收集在名为「标题」的组中,并且用户提出要求时你会关闭它们。
# First tab: set session + a human label (in the user's language)
curl -s -X POST http://127.0.0.1:10086/command \
-d '{"action":"navigate","args":{"url":"https://www.kimi.com","newTab":true,"group_title":"K2.6 feature research"},"session":"k26-research"}'
# Another site, same task → same session → joins the same group automatically
curl -s -X POST http://127.0.0.1:10086/command \
-d '{"action":"navigate","args":{"url":"https://www.moonshot.cn","newTab":true},"session":"k26-research"}'
关闭操作始终由用户发起:只有在用户明确提出要求(“关闭那些标签页”“清空标签页”)时,才调用 close_session。一次调用即可清除整个组。
截图
守护进程会将图像写入磁盘,并返回 {format, path, sizeBytes, mimeType}——不会返回 base64,因为模型无法读取原始图像字节。获取 .path 后,使用 Read 工具打开它,才能实际查看图像。
# Default: PNG of the visible viewport, daemon picks a temp path
curl ... -d '{"action":"screenshot","args":{}}'
# Options (each independent): JPEG quality, element-only via @e/CSS selector, custom output path
curl ... -d '{"action":"screenshot","args":{"format":"jpeg","quality":60}}'
curl ... -d '{"action":"screenshot","args":{"selector":"@e123"}}'
调用方提供的 path 会原样使用(创建父目录,覆盖现有文件)——请使用唯一名称以避免覆盖其他文件。save_as_pdf 遵循相同规则。
优先使用 snapshot,而非 CSS/JS 选择器
snapshot 会返回带有 @e 引用的交互元素,这些引用绑定到观察到的 DOM 节点。将引用作为不透明字符串复制到 click/fill 中。重新读取页面会保留相同节点的引用;节点被移除或文档/连接发生变化时,则需要重新执行 snapshot。引用不会自动选择名称相同的替代元素。
若要读取限定长度的文本,请调用 snapshot 并设置 format:"aria",还可选择设置 max_chars(默认值为 60000)。这会限制 tree_text,但不限制元数据。如果 truncated:true,请将 next_cursor 作为 cursor(不带 ref)传回,以继续读取同一已保存的观察结果;continued:true 表示后续文本块。拼接 tree_text 时不要添加额外分隔符:文本块可能会拆分较长的行,且预算按 UTF-16 代码单元计算,不会拆分代理对(若下一个字符需要 2 个代码单元,则预算设为 1 会报错)。游标会在五分钟后、缓存被清除后、导航后或连接重置后过期;遇到游标过期错误时,请重新执行 snapshot。同一文档中的内容编辑不会刷新已保存的文本。缓存最多保存八个 snapshot/八百万个代码单元;超过四百万个代码单元的观察结果会明确失败,因此请缩小读取范围。或者,使用带有特定 query 的 find 在完整的主文档无障碍树中搜索,然后使用选定匹配项的 ref 调用 snapshot 读取其子树。搜索结果包含祖先路径,可用于区分名称相同的匹配项。范围和预算不会重新分配已有引用;此搜索不包含 iframe 内容。
仅在以下情况下回退到 evaluate(JS):
- 目标在 snapshot 中没有
@e引用 - 需要获取 snapshot 中没有的属性(例如
href) - 需要派发复杂事件序列或滚动
Evaluate 提示
- 始终使用精简的
JSON.stringify(data)——不要添加null, 2格式化。缩进和换行可能会让响应膨胀数倍,导致传输过程中被截断。 evaluate调用共享页面的 JS 环境——在两次调用中重复声明相同的const/let会引发SyntaxError。请使用 IIFE 创建独立作用域:(() => { const x = ...; return x; })()。
文本输入 — 使用 fill
fill(选择器 = CSS 或 @e 引用,以及要填入的值)适用于 <input>/<textarea>(返回 mode: "value"),也适用于 [contenteditable] 富文本编辑器——ProseMirror、TipTap、Lexical、Slate、Quill 等(返回 mode: "contenteditable"),并会触发相应的输入事件,让页面作出响应。
fill 会先清除再插入:替换现有内容。要追加内容,请通过 evaluate 读取当前值,拼接后再用结果调用 fill。
表单提交/特殊按键
没有单独的“按 Enter”工具。要提交表单,请直接点击提交按钮(对 @e 引用或选择器调用 click)。要以编程方式分派按键事件(例如按 Escape 关闭模态框):
{"action":"evaluate","args":{"code":"document.activeElement.dispatchEvent(new KeyboardEvent('keydown',{key:'Escape',bubbles:true}))"}}
将当前页面保存为 PDF
save_as_pdf 会将当前页面渲染为 PDF 并返回文件路径。所有参数均为可选:
paper_format:letter(默认)|a4|legal|a3|tabloidlandscape:false(默认)scale:1.0(默认),范围为[0.1, 2.0]print_background:true(默认)——保留背景颜色path:调用方提供的输出路径;如果未指定,守护进程会在操作系统临时目录下选择默认路径,并以页面标题作为文件名
path 的语义与 screenshot 一致:按原样写入,自动创建父目录,覆盖已有文件。
解码后的 PDF 上限为 100 MB。超过此大小时,守护进程会拒绝处理;请降低 scale 或拆分页内容。
已知限制
- 严格检查
event.isTrusted的网站(例如某些银行门户、验证码)会忽略click/fill,因为这些操作会触发 DOM 层级的合成事件(isTrusted=false)。遇到这种情况,请告知用户该页面需要手动操作。(通过协议层的cdp逃生舱可以实现可信输入,但这属于高级用法:你的标签页在后台运行,只有在启用焦点模拟时,真实输入才会发送到后台标签页——输入前发送Emulation.setFocusEmulationEnabled{"enabled":true},在该标签页操作完成后发送{"enabled":false}。如果输入仍未生效,最后的办法是使用Page.bringToFront;请参阅cdp行。) - iframe 内的内容:
snapshot、fill、click和evaluate只能访问顶层文档——嵌入的文档(预览窗格、沙盒预览、嵌入式应用)属于独立页面,其节点不会出现在树中。当快照在树之后列出frames(frames: [{frame:"#f1", url, size, …}],按面积从大到小排列)时,请使用列表中的句柄,通过read_page{"frame":"#f1"}读取其中一个框架。框架读取结果会回显frame;如果没有回显,说明扩展比此技能版本旧,并返回了顶层页面——请参阅下文的版本不匹配。预览框架通常会在页面本身加载数秒后才出现——使用wait{"frame":"any"},即可在占据屏幕大部分区域的框架可读时立即返回,而不必重新获取快照。PDF 预览通过查看器自身的文档读取,因此无需滚动即可获取所有页面。目前仍不支持对框架内的元素执行操作——有时直接导航到框架的 URL 可行,但经过身份验证的预览流通常无法单独加载。
如果工具调用失败(守护进程或扩展尚未就绪)
如果工具调用无法连接到守护进程(连接被拒绝),或者回复不是上面的 ok 信封(有其他程序正在响应该端口),请自行运行 start,不要询问用户。任何时候运行都安全:如果守护进程已启动,则不会执行任何操作。 二进制文件不在 PATH 中:~/.kimi-webbridge/bin/kimi-webbridge(Windows:%USERPROFILE%\.kimi-webbridge\bin\kimi-webbridge.exe)。
守护进程的监听地址始终会显示在 start 的输出中,或者显示在 kimi-webbridge status 中(运行时显示 port,未运行时显示 addr)。如果地址不是 127.0.0.1:10086,本任务中的每次调用都使用该地址。配置文件只用于更改守护进程地址,不用于查找地址。然后重试工具调用。
如果回复为 ok:false,且代码为 extension_not_connected,说明守护进程正常,但浏览器端未连接——运行 start 不会改变这一点。消息会说明用户需要做什么;请用用户的语言转告他们,并在用户确认后继续。
start 失败并显示 "did not come up … held by another program" → 另一个程序占用了该端口。更改守护进程地址:将 {"addr":"127.0.0.1:<port>"}(选择一个空闲端口)写入错误中指定的配置文件,然后再次运行 start,接着请用户将扩展指向新端口一次(Kimi 侧边栏 → Settings → Local agent remote control → Connection address → ws://127.0.0.1:<port>/ws;扩展会记住该设置)。
如果仍然失败,说明二进制文件缺失(command not found 表示未安装 kimi-webbridge),或者浏览器扩展无法连接——请引导用户访问帮助页面,不要深入排查:
- English: https://www.kimi.com/en/products/kimi-webbridge
- 中文: https://www.kimi.com/products/kimi-webbridge
切勿自动运行 stop / restart / upgrade / uninstall——这些命令会终止正在运行的守护进程。当 status 显示 version_mismatch、update_available 或 skill_mismatch,或者 kimi-webbridge 命令输出 ==> … Run: <command> 行(同样的提示也会输出到 stderr)时,请告知用户,并原样提供他们需要运行的命令——即 command 字段中的内容,或 Run: 后的内容;这就是这些提示的用途。当用户询问 kimi-webbridge 本身(安装、启动/停止/升级、“是否正在运行”、status 的含义、更改端口)时,请先阅读 references/operations.md。
版本不匹配
如果工具返回的错误中包含 "Please update the Kimi Browser Extension",说明用户的浏览器扩展版本低于此技能所需的版本。不要尝试自行协调版本——只需用用户的语言告知他们更新扩展并重试: