pramodthe/guidebridge
GitHub: pramodthe/guidebridge
GuideBridge 为 React 应用中的 Python AI agent 提供低延迟的语义化页面交互能力,让 agent 通过 WebSocket 在用户浏览器中实时执行操作并以可见光标引导用户。
Stars: 12 | Forks: 3
# 🧭 GuideBridge
**为你的 React 应用中的任何 Python agent 赋予眼和手。**
你的 AI agent 可以查看用户正在浏览的页面,用可见的光标指引用户,高亮、滚动、点击、输入、拖拽并进行讲解——这一切都实时发生在用户自己的浏览器标签页中。无需浏览器自动化。无需截图。无需托管服务。
[](https://www.npmjs.com/package/@guidebridge/react)
[](https://pypi.org/project/guidebridge/)
[](LICENSE)
[](python/)
[](packages/react/)
[快速开始](#-quickstart) · [工作原理](#-how-it-works) · [Agent 工具](#-the-agents-tools) ·
[React API](#-react-api) · [Python API](#-python-api) · [框架](#-framework-integrations) ·
[协议](#-protocol) · [安全性](#-security-model) · [演示](#-run-the-demo)

## 为什么选择 GuideBridge?
基于视觉的“computer use” agent 驱动的是*它们自己*拥有的浏览器:截图 → 视觉模型 → 像素坐标 → 点击。这种方式很慢(每次动作需要数秒)、昂贵(每次观察都消耗图像 token)、脆弱(像素漂移、重新渲染),并且无法触及用户已经打开的标签页。
当你**拥有该应用**时,你不需要视觉。GuideBridge 会对你的 React 应用进行插桩,以暴露一个协作接口:agent *观察*紧凑的语义快照(几 KB 的 JSON,而不是截图),并对命名的目标(而不是坐标)执行*操作*,通过 WebSocket 往返通信,耗时以毫秒计。可见的动画光标让用户能清晰理解每一个动作——agent 不仅仅是在执行操作,它还在视觉上*展示并解释*它们。
| | GuideBridge | Browser-use / computer use |
| -------------------- | ----------- | -------------------------- |
| 每次动作的延迟 | ~10–100 ms | 2–10 s(视觉推理) |
| 观察成本 | ~2–4 KB JSON | 数千个图像 token |
| 目标 | 语义 id | 像素坐标 |
| 在用户自己的标签页中运行 | ✅ | ❌(agent 拥有的浏览器) |
| 能在重新渲染中存活 | ✅(id + 重试) | ❌ |
| 任意第三方网站 | ❌ | ✅ |
将 GuideBridge 用于**你自己的**产品:入门指南、应用内助手、在用户注视时修复问题的支持 agent、在你的 UI 上进行教学的 AI 导师。
## 📦 盒子里有什么
| Package | Registry | 它是什么 |
| ------- | -------- | ---------- |
| [`@guidebridge/react`](packages/react/) | npm | `
`, ``, `agentTarget()`, `useAgentAction()` — 页面内 runtime |
| [`guidebridge`](python/) | PyPI | `AgentBridge` — FastAPI WebSocket endpoint、会话管理器,以及用于 LangChain / OpenAI / Anthropic / Google ADK 的工具适配器 |
| [协议](#-protocol) | — | 连接两者的小巧、版本化的 JSON 帧协议 |
```
┌──────────────┐ tool calls ┌──────────────┐ WebSocket ┌────────────────┐
│ LLM agent │ ───────────────▶ │ guidebridge │ ───────────────▶ │ your React app │
│ (LangChain, │ │ (FastAPI) │ │ (user's tab) │
│ OpenAI, ADK) │ ◀─────────────── │ │ ◀─────────────── │ cursor + DOM │
└──────────────┘ observations └──────────────┘ frames └────────────────┘
```
## ⚡ 一行命令尝试
两个包均已发布——PyPI 上的 [`guidebridge`](https://pypi.org/project/guidebridge/)
和 npm 上的 [`@guidebridge/react`](https://www.npmjs.com/package/@guidebridge/react)。这会
将一个完整可用的应用(FastAPI 后端 + Vite React 前端 + 无需 API key 的
演示导览)脚手架生成到 `./guidebridge-app` 中:
```
curl -fsSL https://raw.githubusercontent.com/pramodthe/guidebridge/main/quickstart.sh | bash
```
然后运行它打印出的两条命令,打开 ,并按下
**▶ Run demo tour** —— agent 光标会在页面上进行点击、输入并讲解。只需一行代码
即可将脚本化的导览替换为真实的 LLM agent
(`bridge.as_langchain_tools()` — 参见 [框架集成](#-framework-integrations))。
想在通过管道传输给 bash 之前先阅读脚本?该脚本是 [`quickstart.sh`](quickstart.sh) —
下载它并运行 `bash quickstart.sh my-app`。
## 🚀 快速开始
### 1. 前端 —— 标记你的应用
```
npm install @guidebridge/react
```
```
import { AgentProvider, AgentCursor, agentTarget, useAgentAction } from "@guidebridge/react";
function App() {
return (
);
}
```
暴露 agent 可以通过名称调用的应用级操作(导航,或任何 DOM 事件无法表达的操作):
```
function CheckoutShortcut() {
const navigate = useNavigate();
useAgentAction("go_to_checkout", "Navigate to the checkout page", () => navigate("/checkout"));
return null;
}
```
### 2. 后端 —— 挂载 bridge,将工具交给你的 agent
```
pip install "guidebridge[fastapi,langchain]"
```
```
from fastapi import FastAPI
from guidebridge import AgentBridge
app = FastAPI()
bridge = AgentBridge()
app.include_router(bridge.router) # WebSocket endpoint at /agent/ws
tools = bridge.as_langchain_tools() # ready for any LangChain agent
```
### 3. 让 agent 驱动
```
from langchain.agents import create_agent
from langchain_anthropic import ChatAnthropic
agent = create_agent(
ChatAnthropic(model="claude-sonnet-5"),
tools=bridge.as_langchain_tools(),
system_prompt=(
"You are an on-page guide. Call observe_page first, then point, highlight, "
"and act while you explain what you're doing."
),
)
await agent.ainvoke({"messages": [{"role": "user", "content": "Show me how to check out"}]})
```
用户会看到一个带标签的光标滑动到定价部分,将其高亮,填写表单,并在 Buy 按钮前停下——同时 agent 在进行解说。
## 🔍 工作原理
1. **``** 向你的后端打开一个 WebSocket 并注册页面:
每个 `agentTarget()` 元素,以及(默认情况下)provider 内部的普通按钮/输入框/链接,都会成为一个具有稳定 id、role、label 和实时值的可寻址目标。
2. **你的 agent 调用一个工具**(例如 `click(target_id="checkout")`)。`AgentBridge`
将其转换为一个小巧的 JSON 帧,发送到正确的浏览器会话,并等待回复作为工具结果。
3. **页面内 runtime 执行它** —— 光标*首先*动画移动到元素(约 450 ms 的提前量,以便在改变发生前传达意图),然后执行真实的 DOM 交互:
点击使用完整的 pointer-event 序列,输入使用原生 value setter(以便 React 受控输入实际更新),平滑滚动以及动画拖拽。
4. **agent 进行观察**,使用 `observe_page`:包含目标、值、滚动状态、已注册应用操作,以及用户最近的点击/输入的紧凑快照——因此它可以对用户刚刚做出的操作做出反应。
## 🛠 agent 的工具
每个框架适配器都暴露相同的 11 个工具:
| Tool | Arguments | 用户看到的内容 |
| ---- | --------- | ------------------ |
| `observe_page` | — | 无(返回语义快照) |
| `point_at` | `target_id` | 光标滑动到元素上 |
| `highlight` | `target_id`, `ms?` | 光标 + 彩色轮廓,同时 agent 进行讲解 |
| `callout` | `target_id`, `text`, `ms?` | 高亮 + 元素旁边的文本气泡 |
| `click` | `target_id` | 光标到达,点击涟漪,触发真实的 click 事件 |
| `type_text` | `target_id`, `value` | 光标到达,值逐字符输入 |
| `select_option` | `target_id`, `value` | 下拉菜单更改为该选项(按值或标签) |
| `scroll_to` | `target_id` | 元素平滑滚动到视图中,居中显示 |
| `scroll_by` | `direction`, `amount?` | 页面上下滚动一个视口(或半个) |
| `drag` | `target_id`, `to_target_id` | 光标将一个元素拖拽到另一个元素上 |
| `app_action` | `name`, `args` | 你的 `useAgentAction` handler 所做的任何操作 |
失败的动作会返回结构化的错误(`target not found: …`),以便 agent 可以重新观察并恢复。
## ⚛️ React API
### ``
| Prop | Type | Default | Description |
| ---- | ---- | ------- | ----------- |
| `url` | `string` | — | 你的 `AgentBridge` endpoint 的 WebSocket URL |
| `sessionId` | `string` | `"default"` | 此标签页的稳定 id;在多用户应用中使用你的用户/标签页 id |
| `autoDiscover` | `boolean` | `true` | 也暴露未修饰的按钮/输入框/链接。设为 `false` 则仅严格允许 `agentTarget` 的白名单 |
支持指数退避的自动重连。
### ``
| Prop | Type | Default |
| ---- | ---- | ------- |
| `label` | `string` | `"Agent"` |
| `color` | `string` | `"#2C50EE"` |
在你的应用内任意位置渲染一次;它会自行定位(`position: fixed`,
pointer-events: none),并且仅在 agent 执行操作时出现。
### `agentTarget(name, opts?)`
为 agent 命名元素的展开 props helper:
```
```
### `useAgentAction(name, description, handler)`
注册一个自定义操作。它将出现在 `observe_page` 的 `customActions` 下,agent 会通过 `app_action` 工具调用它。handler 的返回值会被序列化回传给 agent。在组件卸载时自动取消注册。
### `useAgentbridge()`
返回 `{ status, sessionId, registerAction }` —— `status` 为
`"connecting" | "connected" | "disconnected"`,非常适合用作状态指示器。
## 🐍 Python API
### `AgentBridge(path="/agent/ws", *, timeout_s=10.0, authorize=None)`
| Member | Description |
| ------ | ----------- |
| `.router` | 带有 WebSocket endpoint 的 FastAPI `APIRouter` —— `app.include_router(bridge.router)` |
| `.as_langchain_tools(session_id=None)` | 用于 LangChain / LangGraph agent 的(异步) `list[StructuredTool]` |
| `.as_openai_tools(session_id=None)` | `OpenAIToolset`,包含 `.specs`(JSON-schema 函数规范)和 `await .call(name, args)` |
| `.call_tool(name, args, session_id=None)` | 直接调度 —— 基于此构建你自己的适配器 |
| `.get_session(session_id=None)` / `.sessions()` | 检查已连接的浏览器标签页 |
| `.wait_for_session(session_id=None, timeout_s=30)` | 等待标签页连接(在脚本/测试中很有用) |
| `authorize=` | `async (websocket) -> bool` —— 在接受会话之前验证 socket(cookie、token、origin) |
`session_id=None` 针对最近连接的标签页——适用于单用户应用;
在多用户部署中传递显式 id。
如果没有连接标签页(或者它没有在 `timeout_s` 内响应),工具会返回一个优雅的哨兵值,告诉模型在没有页面的情况下继续——你的 agent 永远不会因为标签页关闭而挂起或崩溃。
## 🔌 框架集成
LangChain / LangGraph
```
tools = bridge.as_langchain_tools()
agent = create_agent(model, tools=tools, system_prompt="…")
```
OpenAI SDK
```
toolset = bridge.as_openai_tools()
resp = client.chat.completions.create(model="gpt-4o", messages=msgs, tools=toolset.specs)
for tc in resp.choices[0].message.tool_calls or []:
result = await toolset.call(tc.function.name, tc.function.arguments)
msgs.append({"role": "tool", "tool_call_id": tc.id, "content": result})
```
Anthropic SDK
```
toolset = bridge.as_openai_tools()
anthropic_tools = [
{"name": s["function"]["name"], "description": s["function"]["description"],
"input_schema": s["function"]["parameters"]}
for s in toolset.specs
]
msg = client.messages.create(model="claude-sonnet-5", max_tokens=1024,
tools=anthropic_tools, messages=msgs)
for block in msg.content:
if block.type == "tool_use":
result = await toolset.call(block.name, block.input)
```
MCP (Claude Code, Claude Desktop, Cursor, …)
```
# pip install "guidebridge[mcp]"
server = bridge.as_mcp_server()
server.run() # stdio, for local MCP clients
# 或通过 HTTP 与你的 FastAPI app 一起提供服务:
app.mount("/mcp", server.streamable_http_app())
```
连接到此服务器的任何 MCP 客户端都将获得全部 11 个页面控制工具。
Google ADK / 其他框架
任何使用 JSON-schema 函数规范的框架都可以工作:将
`toolset.specs`(或 `guidebridge.openai_tool_specs()`)喂给它,并通过
`await bridge.call_tool(name, args)` 路由调用。
## 📡 协议
每个标签页通过一个 WebSocket 传输版本化的 JSON 帧(当前版本:`v1`)。TypeScript 类型位于
[`packages/react/src/protocol.ts`](packages/react/src/protocol.ts),Pydantic 镜像位于
[`python/src/guidebridge/protocol.py`](python/src/guidebridge/protocol.py)。
```
// browser → backend, once on connect
{ "type": "hello", "version": "1", "sessionId": "default", "page": { "url": "…", "title": "…" } }
// backend → browser
{ "type": "observe.request", "requestId": "gb_a1b2c3" }
{ "type": "action.request", "requestId": "gb_d4e5f6", "action": { "type": "click", "targetId": "checkout" } }
// browser → backend
{ "type": "observe.result", "requestId": "gb_a1b2c3", "payload": { /* PageSnapshot */ } }
{ "type": "action.result", "requestId": "gb_d4e5f6", "payload": { "success": true } }
```
`PageSnapshot` 包含 `targets`(id、role、label、当前值、可见性)、
滚动状态、`customActions`,以及 `recentEvents`(用户最近的约 15 次交互)。
## 🔒 安全模型
GuideBridge **在设计上是协作式的** —— 没有需要注入的内容,也不需要扩展:
- agent 只能触及挂载了 `AgentProvider` 并**向外**连接到*你的*
后端的页面。它无法触碰其他标签页或网站。
- `autoDiscover={false}` 会将页面变成严格的白名单:只有你使用
`agentTarget()` 显式标记的元素才是可见或可操作的。
- `AgentBridge(authorize=…)` 在接受任何会话之前对 WebSocket 进行身份验证(会话 cookie、JWT、origin
检查)。
- 将破坏性流程放在 `useAgentAction` handler 之后 —— 你的代码决定实际
发生的事情,并可以在执行之前要求用户确认。
- 光标覆盖层使每一个 agent 动作都可见;没有任何事情静默发生。
## 🌱 运行演示
一个带有**实时 AI agent** 的植物店面 —— 一个真实的 Claude agent,它会阅读
你的自然语言请求,调用 `observe_page` 查看商店,并驱动光标
来执行它。(还有一个无需 API key 的脚本化导览,用于离线展示运行机制。)
```
# terminal 1 — backend
cd python && pip install -e ".[dev]"
pip install langchain langchain-openai # for the live agent
# 指向任何 Claude endpoint — 兼容 OpenAI 的 gateway…
export TOKENROUTER_API_KEY=sk-... # model: anthropic/claude-sonnet-5
# …或直接指向 Anthropic:export ANTHROPIC_API_KEY=sk-...
cd ../examples/demo/backend && uvicorn main:app --port 8000
# terminal 2 — frontend
cd packages/react && npm install && npm run build
cd ../../examples/demo/frontend && npm install && npm run dev
```
打开 并与向导对话:*"你最便宜的植物是什么?指出来。"*, *"把龟背竹加到我的购物车里。"*, *"帮我询问关于发货到尼泊尔的事。"* agent
会观察页面并移动光标进行高亮、点击和填写表单——所有这些都由
模型决定,没有任何硬编码。没有 API key?点击 **▶ run the scripted tour**
以观看固定的光标演示。
聊天使用 AG-UI 风格的事件名称(`RUN_STARTED`, `TOOL_CALL_START`/`END`, `TEXT_MESSAGE_CONTENT` 增量, `RUN_FINISHED`),
通过 Server-Sent Events **流式传输** agent 的实时工作,因此你会看到 *"🔍 正在查看页面… 👆 正在点击…"* 在发生时实时出现,回复内容也会自行输入——
没有死板的加载指示器。当前的页面快照会预加载到 prompt 中,以便 agent 通常
可以跳过一次往返通信。
你还可以**与它对话**:点击 🎤 说出你的请求,并切换 🔊 听语音回复。这使用的是浏览器内置的 Web Speech API(Chrome)——
不需要额外的 key 或服务;语音只是进出*同一个* agent 的另一种方式,这表明
GuideBridge 是模态无关的。
## 🗓 路线图
- [x] **MCP server adapter** — `bridge.as_mcp_server()` 将页面控制权暴露给 Claude、
Cursor 和任何 MCP 客户端
- [ ] `spotlight` 操作(调暗目标以外的所有内容)+ 步骤序列化导览
- [ ] 人工确认策略钩子(针对每个目标/操作设置 `confirm: true`)
- [x] **沙盒化的 iframe 模式** — `guidebridge.iframe.inject_iframe_runtime()`(服务端)+ `useAgentFrame(iframeRef)`(React)在 `sandbox="allow-scripts"` iframe 中控制不受信任的生成 HTML
- [ ] 使用相同协议的 Vue / Svelte runtime
- [ ] 语音传输(LiveKit data channels、Vapi client messages)
## 🤖 面向 AI 编程 agent
此仓库已准备好迎接 agent —— 克隆它,你的编程 agent 就可以为你集成 GuideBridge:
- [`llms.txt`](llms.txt) — LLM 可读的文档、协议和示例索引
- [`.claude/skills/guidebridge/SKILL.md`](.claude/skills/guidebridge/SKILL.md) —
逐步的集成手册;Claude Code 在此仓库中会自动识别它,
或者将 `guidebridge/` 文件夹复制到你项目的 `.claude/skills/` 中
- [`AGENTS.md`](AGENTS.md) — 仓库地图、构建/测试命令和贡献规则
(Claude、Cursor、Codex 等在处理此代码库时会读取此文件)
告诉你的 agent:*"将 GuideBridge 添加到我的应用中,以便 AI 向导可以控制页面"* ——
该技能会引导它完成 provider 设置、目标命名、bridge 挂载和验证。
## 📄 许可证
[MIT](LICENSE) © Pramod Thebe
灵感来自 Hi-Tuto 中的 lesson bridge,
在那里,语音导师通过指点、滚动和点击在 AI 生成的课程之上进行教学——
在这里被泛化,以便任何 agent 都能在任何 React 应用中做到这一点。
标签:Python, React, SOC Prime, Syscalls, WebSocket, 人工智能, 人机协同, 依赖分析, 前端交互, 开发工具, 无后门, 用户模式Hook绕过, 逆向工具