贵宾
一个开源的,由WebMCP驱动的GUI代理,它生活在您的网络应用中.
让一个自然语言代理来操作你的UI——点击,填充,导航,调用你的应用程序自己的动作——由你带来的任何LLM驱动.
可选 可视化器 动作中:每个工具呼叫的状态芯片,一个动画的梯度发光来巡视代理所接触的每一个元素,以及一个背景面纱来保持用户对动作的关注.
灵感来自 页面代理,但建立在新兴 网络MCP 标准通过多填充.
- 📦 只是一个npm包.
npm i @aralroca/gui-agent财务报告和审定财务报表import。没有脚本注入,没有浏览器扩展,也没有无头浏览器. - 🧩 以标准为主. 工具注册于
document.modelContext(网络MCP). 多元填充( E)@mcp-b/webmcp-polyfill)安装在浏览器尚未本土支持的地方. - 🎯 生产者+消费者在一中. 显示您的应用操作作为精确的工具 财务报告和审定财务报表 回到基于文本的 DOM 驱动其他一切.
- 🧠 带上你的LLM. 一个微小的提供者-不可知界面,加上一个现成的Vercel AI SDK适配器.
- 🪶 无头核. 没有强制的UI——把它连接到你自己的聊天,命令栏,或者声音.
- ✨ 央视网. 每个动作的状态芯片,动画梯度会围绕被操作的元素发光,背景模糊而突出(
@aralroca/gui-agent/ui) (中文(简体) ).
早期/实验性。 WebMCP 是一个移动 W3C草案; APIs可能改变.
思取取而为便宜. 但是如果你的特工们 不必那么想... 反而有.. 控制共计 您的应用程序当然{\fn黑体\fs22\bord1\shad0\3aHBE\4aH00\fscx67\fscy66\2cHFFFFFF\3cH808080}你觉得呢? 来看看 Janux 框架 超过gui -agent lib 的
目录
安装
npm i @aralroca/gui-agent
# optional peers, depending on what you use:
npm i ai zod # for the AI SDK adapter / Zod schemas
快开始
import { defineTool, GuiAgent } from "@aralroca/gui-agent";
import { createAiSdkLlm } from "@aralroca/gui-agent/ai-sdk";
// 1. Expose your app's actions as tools (producer side, optional).
defineTool({
name: "go_to_tab",
description: "Switch the console to a tab.",
inputSchema: { type: "object", properties: { tab: { type: "string" } }, required: ["tab"] },
annotations: { readOnlyHint: true },
execute: ({ tab }) => router.push(`/${tab}`),
});
// 2. Run the agent. It discovers your tools + synthesizes DOM tools (click/fill/read).
const agent = new GuiAgent({
llm: createAiSdkLlm({ model: "anthropic/claude-opus-4-8" }),
confirm: async (call) => window.confirm(`Allow "${call.name}"?`), // HITL gate
});
await agent.run("Invite [email protected] to the team as admin");
导入软件包会自动安装 WebMCP 多填充 - 没有 <script> 标签。 。 。 .
如何运作
gui-agent 统一两种办法:
- 出品人 (WebMCP). 你的应用电话
defineTool(...)以登记可靠、结构化的行动document.modelContext. 任何WebMCP代理——包括浏览器的本地代理——都可以使用. - DOM倒置 (页面代理样式). 对于任何没有暴露的东西, 代理构建紧凑 文本快照 (作用、标签、值、稳定参考,例如
e7)并被合成read_page编号 :click编号 :fill编号 :select_option编号 :drag编号 :wait_for_text工具。 没有截图,也不需要多式联运模式.
内置循环会发现所有可用的工具, 询问您的 LLM 该怎么办, 运行调用( 由您的可选选项决定 ) confirm),反馈结果,并重复到完成.
代理如何选择工具
对于每一步,代理更喜欢 专门设计的 WebMCP 工具 如果一个适合,而且只有 推断DOM 当没有工作暴露时:
flowchart TD
Goal["🗣️ Goal in natural language"] --> Loop["🧠 Agent loop · bring your own LLM<br/>(AI SDK adapter · remote LLM · React bindings)"]
Loop --> Discover["🔍 Discover the available tools"]
Discover --> Decide{"Is there a purpose-built<br/>WebMCP tool for this step?"}
Decide -- "Yes · preferred" --> WebMCP["⚙️ Call the WebMCP tool<br/>structured & reliable"]
Decide -- "No · fallback" --> DOM["🖱️ Infer from the DOM<br/>read_page → click / fill / select_option / drag / wait_for_text"]
WebMCP --> Gate{"Does the tool have<br/>readOnlyHint?"}
DOM --> Gate
Gate -- "No · write action" --> Confirm["🙋 Human-in-the-loop confirm()"]
Gate -- "Yes · read-only" --> Run["Execute"]
Confirm -- "approved" --> Run
Confirm -- "denied" --> Feed
Run --> Feed["Feed the result back to the LLM"]
Feed --> Loop
Loop -. "no more tool calls · maxSteps" .-> Done["🏁 Done"]
subgraph MC["document.modelContext · WebMCP (polyfilled — no server, no browser extension)"]
direction LR
App["Your app's own actions<br/>defineTool() / useTool()"]
Ext["Tools registered by other code<br/>discoverExternalTools() · opt-in"]
end
Discover -. reads .-> App
Discover -. reads .-> Ext
特工被交给了 单一合并工具列表 并被指示更偏好您的应用程序的WebMCP工具;被合成的DOM工具是总是倒置(一个同名的应用程序工具获胜). WebMCP 工具在线
document.modelContext——您的应用程序注册(因此任何WebMCP代理,包括浏览器的本地代理,都可以调用)和discoverExternalTools()能够调出其他登记代码的工具.upload_file财务报告和审定财务报表navigateDOM工具是选入的.
与页面代理相比
gui - agent 的灵感来自 页面代理 并分享其核心思想——一种自然语言的代理,驱动着一个真实的网页 基于文本的 DOM 带有自带LLM设计的快照(没有截图,没有多式模型). 不同之处在于Gui -agent通过在新兴的的基础上 来补充什么 网络MCP 标准而不是仅驱动 DOM :
| 能力 | 贵宾 | 页面代理 |
|---|---|---|
WebMCP 标准 (单位:千美元)document.modelContext(中文(简体) ) | * 建于该地 W3C WebMCP草案 + 多填充 | QQ Not WebMCP — 它的"MCP"是一个单独的节点服务器, 允许 外部 代理驱动浏览器 |
| 应用动作作为标准工具 | ✅ defineTool 登记册结构化行动 document.modelContext可调用 任意 WebMCP 代理商——包括浏览器的本地代理商 | QQ 自定义工具是客户端配置, 标记 @experimental,而不通过页面标准曝光 |
| 与其他页面工具接口 | ✅ discoverExternalTools() 抓取其他已注册代码的工具 document.modelContext | 不详 |
| 人行道安全门 | * 内建 confirm() 门 - 所有非readOnlyHint 工具在运行前通过批准进行路由 | 没有强制性的审批门,也没有只读/写区分(自动运行至 maxSteps(b) 提议 ask_user、生命周期钩和数据假冒 |
| 一等反应装订 | ✅ GuiAgentProvider, (中文(简体) ), useGuiAgent, (中文(简体) ), useTool, (中文(简体) ), <AgentSteps /> | 无( vanilla 面板 UI) |
| 提供者不可知LLM | 任何形状通过一个函数 Llm 接口,加上一个 Vercel AI SDK 适配器和一个远程 LLM 帮助器 | 带上你的,但终点必须是 OpenAI 兼容 |
| 生产者+消费单位 | 精准结构化制作工具 财务报告和审定财务报表 a DOM 在一个循环中倒置 | 主要为DOM驱动程序(海关工具实验) |
当页面代理更适合. 页面代理非常出色,而且有真正的优势 gui代理没有: 它驱动 任何现有网站的DOM,没有选择的应用程序,因此它在遗产或第三方应用(ERP,CRM,admin boards)上工作,你并不控制——而gui-agent的制作工具需要应用来注册它们(它的DOM回落仍然在任何地方工作,但是WebMCP值来自仪器). 页面代理也运送可选 色调扩展 用于交叉任务和 a 节点 MCP 服务器 因此外部代理(Claude Desktop, Cursor)可以驱动真正的浏览器. 这两个项目都是麻省理工学院许可,TypeScript,以文字为基础,并运送活动可视化器.
简而言之:达到 页面代理 实现网站自动化 别 自有; 达到 贵宾 当你 对 拥有应用程序并想要基于标准,结构化,人性化的工具——其他所有工具都有DOM回落.
API 密码
核心项目@aralroca/gui-agent(中文(简体) )
| 导出 | 目的 |
|---|---|
defineTool(def, opts?) → dispose | 注册一个WebMCP工具. def数字 : { name, description, inputSchema?, annotations?, execute }。 。 。 . inputSchema 接受JSON Schema或Zod计划 通过返回的函数取消注册或 opts.signal。 。 。 . |
new GuiAgent(options) 编号 : agent.run(goal, signal?) | 代理环. 选项 : { llm, systemPrompt?, maxSteps?, domFallback?, confirm?, onStep?, domTools? }。 。 。 . |
runAgent(goal, options) | 一发方便. |
registry 编号 : ToolRegistry | 工具登记册(真实来源,缩写为 document.modelContext) (中文(简体) ). |
discoverExternalTools() | 读取已注册的工具 document.modelContext 根据其他代码. |
ensureModelContext() 编号 : hasModelContext() | 多填靴子的帮手. |
DomSnapshotter 编号 : createDomTools() | DOM倒地的原始人, 如果你想要他们独立. |
dragAndDrop(source, target, timing?) → { dropped, refused } | 通过点出页面的 HTML5 拖放事件将一个元素拖放到另一个元素上 ()dragstart → dragenter → dragover → drop → dragend,一个共享 DataTransfer) (中文(简体) ). 页面本身的规则决定:不取消的目标 dragover 得到没有 drop。通过 VISIBLE_DRAG 像视觉器的指针一样加快速度. |
GuiAgentOptions.domTools 转发 DomToolsOptions (单位:千美元)root, (中文(简体) ), maxNodes, (中文(简体) ), allowNavigation, (中文(简体) ), onTarget)到每个运行的DOM工具. 每次点击/ 填充/ 选择前, 解析的活性元素会被重新发送到 onStep 作为 tool-target 步( 携带原出处) ToolCall)——是视觉器发光的动力.
* 视同代理(@aralroca/gui-agent/ui(中文(简体) )
向用户显示代理在做时正在做什么:每个工具呼叫的状态芯片("点击"带有回旋器 ~","错误"上,被拒绝时被封"),转弯之间的"想..."指示器,以及一个 动画渐变发光环 围绕DOM要素采取行动——而其余部分 模糊的背景面纱 目标很突出 零依赖性,在阴影DOM中实现 所以样式永远不会漏出.
import { GuiAgent } from "@aralroca/gui-agent";
import { createAgentVisualizer } from "@aralroca/gui-agent/ui";
const viz = createAgentVisualizer({
container: document.querySelector("#agent-steps")!, // where the chips go
});
// `bind` composes the visualizer into your agent options (it never replaces
// your own `onStep` — it chains it).
const agent = new GuiAgent(viz.bind({ llm }));
await agent.run("Invite [email protected] as admin");
一切都是可塑的:
createAgentVisualizer({
chips: true, // action chip list
highlight: true, // glow ring on the target element
cursor: false, // simulated mouse pointer travelling to each target
showThinking: true, // "Thinking…" indicator between LLM turns
locateButton: true, // ◎ button on chips to re-flash the target
glowDuration: 1200, // ms the ring holds on the last target before fading
glowDwell: 500, // min ms per target when several highlights queue up
backdrop: { // blur/dim the page around the target (or false)
blur: 3, // px
exclude: ["chat-panel"], // element ids (or Elements) to keep sharp
},
labels: { // per-tool chip labels (string or fn)
click: "Clicking",
invite_member: (call) => `Inviting ${call.arguments.email}`,
},
theme: { // maps to --gua-* CSS custom properties
accent: "#2563eb",
chipBg: "#f4f4f5",
chipBorder: "#e4e4e7",
chipText: "#3f3f46",
font: "system-ui, sans-serif",
glowColors: ["#7c8cf8", "#f0a6c8", "#7ee0c3"],
},
});
DOM回落工具的发光自动跟踪(click, (中文(简体) ), fill, (中文(简体) ), select_option) (中文(简体) ). 制作工具通过自己的代码操作,所以他们选择通过调用 viz.highlight(target) 从他们的 execute ——每被你触摸的元素拨打一次并按顺序进行环行(代理动作跑得快于人类感知,因此要将亮点排入每个目标的最小活度).
target 可以是一个元素 或 CSS 选择器当工具同步创建目标时,通过一个选择器——反应流(@xyflow/react)节点,一个出入口,一个懒惰地倒行相接的行——和环等(最多~2s)它挂起,而不是在缺失的元素上不放:
const id = graph.addNode({ label }); // returns synchronously…
viz.highlight(`.react-flow__node[data-id="${id}"]`); // …DOM node mounts a tick later; the ring waits for it
设定 cursor: true 添加一个 模拟鼠标指针 在巡演的顶上,一个箭头 飞向每个目标 环访问和波纹 它降落的地方,所以用户看到 地点 事情发生了,而不只是它做到了。 它和戒指一样排队——包括: viz.highlight() 从自己的工具打来的电话——如果页面在它下面滚动,就跟随目标,在下面没有波纹的电信端口 prefers-reduced-motion。它是被拉平的,不是OS指针,它不开火 :hover 或真实的指向事件, 并且它从不拖延它所显示的动作.
拖来拖去. DOM倒计时器 drag 工具 ({ ref, to }拖动 a draggable="true" 元素到投放目标; 页面大纲可拖放的标记元素和投放目标(droptarget在他们自己的作用旁边)——要素 aria-dropeffect (例如:. aria-dropeffect="move" 或一个 ondrop 处理者。 与 cursor: true 指向者降落在被拖走的东西上,并携带一个惰性的复制品(没有ID,处理器,帧或活的自定义元素)到目标,它放任去——在屏幕上的目标方面,像滴出事件一样,高柱从不取出一滴从折叠下. 你自己的工具显示的一样 viz.drag(from, to) 并进行它 dragAndDrop(from, to, VISIBLE_DRAG)数字 :
defineTool({
name: "move_card",
description: "Move a card to another column.",
inputSchema: { type: "object", properties: { card: { type: "string" }, column: { type: "string" } }, required: ["card", "column"] },
execute: async ({ card, column }) => {
const from = document.getElementById(String(card))!;
const to = document.querySelector(`[aria-label="${column}"]`)!;
viz.drag(from, to);
const { dropped } = await dragAndDrop(from, to, VISIBLE_DRAG);
return dropped ? `Moved to ${column}.` : `${column} doesn't take that card.`;
},
});
已知限制:上层的元素(<dialog showModal>,全屏)上方涂料.
带上你的LLM
执行 Llm 接口——一个自动同步函数,一个转弯:
import type { Llm } from "@aralroca/gui-agent";
const llm: Llm = async ({ messages, tools, signal }) => {
// call your model with `messages` + `tools`; return one turn
return { text: "...", toolCalls: [{ id, name, arguments }] };
};
AI SDK适配器(@aralroca/gui-agent/ai-sdk(中文(简体) )
import { createAiSdkLlm, createRemoteLlm } from "@aralroca/gui-agent/ai-sdk";
// Run the model in-process (client key, demo, or server agent):
const llm = createAiSdkLlm({ model: "anthropic/claude-opus-4-8" });
// …or keep the model server-side and execute tools in the browser:
const llm = createRemoteLlm({ api: "/api/chat" });
// endpoint receives { messages, tools } and returns { text?, toolCalls? }
反应( E)@aralroca/gui-agent/react(中文(简体) )
import { useTool, GuiAgentProvider, useGuiAgent, AgentSteps } from "@aralroca/gui-agent/react";
function UsersPage() {
// Registered while mounted; auto-unregistered (AbortSignal) on unmount.
useTool({
name: "search_users",
description: "Search users by name or id",
inputSchema: { type: "object", properties: { query: { type: "string" } }, required: ["query"] },
annotations: { readOnlyHint: true },
execute: ({ query }) => store.search(query),
});
return /* … */;
}
function Chat() {
const { run, running, steps, visualizer } = useGuiAgent();
// wire to your own chat UI; <AgentSteps /> renders the visualizer's chips
}
// Enable the visualizer on the provider (true, or AgentVisualizerOptions):
<GuiAgentProvider llm={llm} visualizer>
<Chat />
<AgentSteps />
</GuiAgentProvider>
安全问题
WebMCP工具与用户现有的会话/cookie一起运行,因此一个工具可以做真实的,特权的事情. gui-agent 给你一个 confirm 门: 任何工具 无 annotations.readOnlyHint 通过您的路径 confirm(call, tool) 运行前的回调——插入人入地的自然站. 使用 readOnlyHint: true 这样他们就不会迅速了 参见 WebMCP 规格 安全考虑。 。 。 .
演示
npm run demo # opens a mini "console" you can drive in natural language
尝试: "邀请 [email protected] (英语) 作为管理员", (中文(简体) ), "寻找健二", (中文(简体) ), "把我的展示名称改为尼欧" (上一个使用DOM倒置——没有暴露), 将“ Fix” 登录重定向到 Done 编辑 董事会 选项卡(一个普通的 HTML5 拖放 kanban : 代理拖取带有 DOM 后退的卡片) drag 工具,指针将其带入柱子,或 "建立一个工作流程" 编辑 工作流量 选项卡——一个反应流布,其中的发光会随着代理器的添加而跟随每个节点(选择器突出显示,因为节点同步挂起)。 带可视化器的演示船 默认情况下,你可以看到芯片, 发光之旅, 和背景面纱 完全如上面的GIF.
开发
npm install
npm test # vitest + jsdom
npm run build # tsup → ESM + .d.ts for all entry points
npm run typecheck
许可证
麻省理工学院 咸罗迦