Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

15 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🧭 GuideBridge

Give any Python agent eyes and hands inside your React app.

Your AI agent can see the page your user is looking at, point at things with a visible cursor, highlight, scroll, click, type, drag, and explain β€” live, in the user's own browser tab. No browser automation. No screenshots. No hosted service.

npm PyPI License: MIT Python TypeScript

Quickstart Β· How it works Β· Agent tools Β· React API Β· Python API Β· Frameworks Β· Protocol Β· Security Β· Demo

GuideBridge demo: an agent tours a storefront, highlights products, and fills the contact form with a visible cursor


Why GuideBridge?

Vision-based "computer use" agents drive a browser they own: screenshot β†’ vision model β†’ pixel coordinates β†’ click. That's slow (seconds per action), expensive (image tokens on every observation), brittle (pixel drift, re-renders), and can't touch the tab your user already has open.

When you own the app, you don't need vision. GuideBridge instruments your React app to expose a cooperative interface: the agent observes a compact semantic snapshot (a few KB of JSON, not a screenshot) and acts on named targets (not coordinates), over a WebSocket round trip measured in milliseconds. A visible animated cursor makes every action legible to the user β€” the agent doesn't just do things, it visibly shows and explains them.

GuideBridge Browser-use / computer use
Latency per action ~10–100 ms 2–10 s (vision inference)
Observation cost ~2–4 KB JSON thousands of image tokens
Targets semantic ids pixel coordinates
Runs in user's own tab βœ… ❌ (agent-owned browser)
Survives re-renders βœ… (id + retry) ❌
Arbitrary third-party sites ❌ βœ…

Use GuideBridge for your product: onboarding guides, in-app copilots, support agents that fix things while the user watches, AI tutors that teach on top of your UI.

πŸ“¦ What's in the box

Package Registry What it is
@guidebridge/react npm <AgentProvider>, <AgentCursor>, agentTarget(), useAgentAction() β€” the in-page runtime
guidebridge PyPI AgentBridge β€” FastAPI WebSocket endpoint, session manager, and tool adapters for LangChain / OpenAI / Anthropic / Google ADK
Protocol β€” A small, versioned JSON frame protocol connecting the two
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   tool calls     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”    WebSocket     β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  LLM agent    β”‚ ───────────────▢ β”‚  guidebridge  β”‚ ───────────────▢ β”‚  your React app β”‚
β”‚  (LangChain,  β”‚                  β”‚   (FastAPI)   β”‚                  β”‚  (user's tab)   β”‚
β”‚  OpenAI, ADK) β”‚ ◀─────────────── β”‚               β”‚ ◀─────────────── β”‚  cursor + DOM   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   observations    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜     frames       β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚑ Try it in one command

Both packages are published β€” guidebridge on PyPI and @guidebridge/react on npm. This scaffolds a complete working app (FastAPI backend + Vite React frontend + a no-API-key demo tour) into ./guidebridge-app:

curl -fsSL https://raw.githubusercontent.com/pramodthe/guidebridge/main/quickstart.sh | bash

Then run the two commands it prints, open http://localhost:5173, and press β–Ά Run demo tour β€” the agent cursor clicks, types, and explains its way around the page. Swap the scripted tour for a real LLM agent with one line (bridge.as_langchain_tools() β€” see Framework integrations).

Prefer to read before piping to bash? The script is quickstart.sh β€” download it and run bash quickstart.sh my-app.

πŸš€ Quickstart

1. Frontend β€” mark up your app

npm install @guidebridge/react
import { AgentProvider, AgentCursor, agentTarget, useAgentAction } from "@guidebridge/react";

function App() {
  return (
    <AgentProvider url="ws://localhost:8000/agent/ws">
      <AgentCursor label="Guide" />

      <section {...agentTarget("pricing", { label: "Pricing plans" })}>…</section>
      <button {...agentTarget("checkout")}>Buy now</button>
    </AgentProvider>
  );
}

Expose app-level actions the agent can call by name (navigation, anything a DOM event can't express):

function CheckoutShortcut() {
  const navigate = useNavigate();
  useAgentAction("go_to_checkout", "Navigate to the checkout page", () => navigate("/checkout"));
  return null;
}

2. Backend β€” mount the bridge, hand tools to your 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. Let the agent drive

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"}]})

The user watches a labeled cursor glide to the pricing section, highlight it, fill the form, and stop short of the Buy button β€” while the agent narrates.

πŸ” How it works

  1. <AgentProvider> opens a WebSocket to your backend and registers the page: every agentTarget() element, plus (by default) plain buttons/inputs/links inside the provider, becomes an addressable target with a stable id, role, label, and live value.
  2. Your agent calls a tool (e.g. click(target_id="checkout")). The AgentBridge turns it into a small JSON frame, sends it to the right browser session, and awaits the reply as the tool result.
  3. The in-page runtime executes it β€” cursor animates to the element first (~450 ms lead so intent reads before the change), then performs a real DOM interaction: full pointer-event sequences for clicks, native value setters for typing (so React controlled inputs actually update), smooth scrolling, animated drag.
  4. The agent observes with observe_page: a compact snapshot of targets, values, scroll state, registered app actions, and the user's recent clicks/inputs β€” so it can react to what the user just did.

πŸ›  The agent's tools

Every framework adapter exposes the same 11 tools:

Tool Arguments What the user sees
observe_page β€” nothing (returns the semantic snapshot)
point_at target_id cursor glides onto the element
highlight target_id, ms? cursor + colored outline while the agent explains
callout target_id, text, ms? highlight + a text bubble next to the element
click target_id cursor arrives, click ripple, real click fires
type_text target_id, value cursor arrives, value types in character by character
select_option target_id, value dropdown changes to the option (by value or label)
scroll_to target_id element scrolls smoothly into view, centered
scroll_by direction, amount? page scrolls a viewport (or half) up/down
drag target_id, to_target_id cursor drags one element onto another
app_action name, args whatever your useAgentAction handler does

Failed actions return structured errors (target not found: …) so the agent can re-observe and recover.

βš›οΈ React API

<AgentProvider>

Prop Type Default Description
url string β€” WebSocket URL of your AgentBridge endpoint
sessionId string "default" Stable id for this tab; use your user/tab id in multi-user apps
autoDiscover boolean true Also expose undecorated buttons/inputs/links. Set false for a strict allowlist of agentTargets only

Reconnects automatically with exponential backoff.

<AgentCursor>

Prop Type Default
label string "Agent"
color string "#2C50EE"

Render it once anywhere inside your app; it positions itself (position: fixed, pointer-events: none) and only appears while the agent is acting.

agentTarget(name, opts?)

Spread-props helper that names an element for the agent:

<button {...agentTarget("checkout", { label: "Complete the purchase" })}>Buy</button>

useAgentAction(name, description, handler)

Registers a custom action. It appears in observe_page under customActions, and the agent invokes it via the app_action tool. The handler's return value is serialized back to the agent. Unregisters automatically on unmount.

useAgentBridge()

Returns { status, sessionId, registerAction } β€” status is "connecting" | "connected" | "disconnected", handy for a status pill.

🐍 Python API

AgentBridge(path="/agent/ws", *, timeout_s=10.0, authorize=None)

Member Description
.router FastAPI APIRouter with the WebSocket endpoint β€” app.include_router(bridge.router)
.as_langchain_tools(session_id=None) list[StructuredTool] (async) for LangChain / LangGraph agents
.as_openai_tools(session_id=None) OpenAIToolset with .specs (JSON-schema function specs) and await .call(name, args)
.call_tool(name, args, session_id=None) Direct dispatch β€” build your own adapter on this
.get_session(session_id=None) / .sessions() Inspect connected browser tabs
.wait_for_session(session_id=None, timeout_s=30) Await a tab connecting (useful in scripts/tests)
authorize= async (websocket) -> bool β€” authenticate the socket (cookie, token, origin) before a session is accepted

session_id=None targets the most recent connected tab β€” fine for single-user apps; pass explicit ids in multi-user deployments.

If no tab is connected (or it doesn't answer within timeout_s), tools return a graceful sentinel telling the model to continue without the page β€” your agent never hangs or crashes on a closed tab.

πŸ”Œ Framework integrations

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

# or serve over HTTP alongside your FastAPI app:
app.mount("/mcp", server.streamable_http_app())

Any MCP client connected to this server gets all 11 page-control tools.

Google ADK / anything else

Any framework that consumes JSON-schema function specs works: feed it toolset.specs (or guidebridge.openai_tool_specs()) and route calls through await bridge.call_tool(name, args).

πŸ“‘ Protocol

Versioned JSON frames (current: v1) over one WebSocket per tab. TypeScript types live in packages/react/src/protocol.ts, the Pydantic mirror in 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 contains targets (id, role, label, current value, visibility), scroll state, customActions, and recentEvents (the user's last ~15 interactions).

πŸ”’ Security model

GuideBridge is cooperative by design β€” there is nothing to inject and no extension:

  • The agent reaches only pages that mount AgentProvider and connect out to your backend. It cannot touch other tabs or sites.
  • autoDiscover={false} turns the page into a strict allowlist: only elements you explicitly marked with agentTarget() are visible or actionable.
  • AgentBridge(authorize=…) authenticates the WebSocket (session cookie, JWT, origin check) before any session is accepted.
  • Keep destructive flows behind useAgentAction handlers β€” your code decides what actually happens and can require user confirmation before doing it.
  • The cursor overlay makes every agent action visible; nothing happens silently.

🌱 Run the demo

A plant storefront with a live AI agent in the corner β€” a real Claude agent that reads your natural-language request, calls observe_page to see the store, and drives the cursor to carry it out. (There's also a scripted, no-API-key tour to show the mechanics offline.)

# terminal 1 β€” backend
cd python && pip install -e ".[dev]"
pip install langchain langchain-openai            # for the live agent

# point at any Claude endpoint β€” an OpenAI-compatible gateway…
export TOKENROUTER_API_KEY=sk-...                 # model: anthropic/claude-sonnet-5
# …or Anthropic directly:  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

Open http://localhost:5173 and talk to the guide: "What's your cheapest plant? Point it out.", "Add the Monstera to my cart.", "Help me ask about shipping to Nepal." The agent observes the page and moves the cursor to highlight, click, and fill the form β€” all decided by the model, nothing hardcoded. No API key? Click β–Ά run the scripted tour for the fixed cursor demo instead.

The chat streams the agent's work live over Server-Sent Events using AG-UI-style event names (RUN_STARTED, TOOL_CALL_START/END, TEXT_MESSAGE_CONTENT deltas, RUN_FINISHED), so you see "πŸ” Looking at the page… πŸ‘† Clicking…" as it happens and the reply types itself in β€” no dead spinner. The current page snapshot is pre-loaded into the prompt so the agent can usually skip a round trip.

You can also talk to it: tap 🎀 to speak your request and toggle πŸ”Š to hear the reply spoken back. This uses the browser's built-in Web Speech API (Chrome) β€” no extra keys or services; voice is just another way in and out of the same agent, which shows GuideBridge is modality-agnostic.

πŸ—Ί Roadmap

  • MCP server adapter β€” bridge.as_mcp_server() exposes page control to Claude, Cursor, and any MCP client
  • spotlight action (dim everything except the target) + step-sequenced tours
  • Human-confirmation policy hooks (confirm: true per target/action)
  • Sandboxed-iframe mode β€” guidebridge.iframe.inject_iframe_runtime() (server-side) + useAgentFrame(iframeRef) (React) control untrusted generated HTML in sandbox="allow-scripts" iframes
  • Vue / Svelte runtimes speaking the same protocol
  • Voice transports (LiveKit data channels, Vapi client messages)

πŸ€– For AI coding agents

This repo is agent-ready β€” clone it and your coding agent can integrate GuideBridge for you:

  • llms.txt β€” LLM-readable index of docs, protocol, and examples
  • .claude/skills/guidebridge/SKILL.md β€” a step-by-step integration playbook; Claude Code picks it up automatically in this repo, or copy the guidebridge/ folder into your own project's .claude/skills/
  • AGENTS.md β€” repo map, build/test commands, and contribution rules (Claude, Cursor, Codex, etc. read this when working on the codebase)

Tell your agent: "Add GuideBridge to my app so an AI guide can control the page" β€” the skill walks it through provider setup, target naming, bridge mounting, and verification.

🀝 Contributing

Issues and PRs welcome. To develop locally:

# React package
cd packages/react && npm install && npm run typecheck && npm run build

# Python package + tests (includes real-WebSocket e2e tests)
cd python && pip install -e ".[dev]" && pytest

Keep the two protocol files in sync when adding frames or actions, and bump PROTOCOL_VERSION on breaking changes.

πŸ“„ License

MIT Β© Pramod Thebe


Inspired by the lesson bridge in Hi-Tuto, where a voice tutor teaches on top of AI-generated lessons by pointing, scrolling, and clicking β€” generalized here so any agent can do it in any React app.

About

VocalBridge-style Package for AI agent

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages