feat: add Chrome extension browser relay

This commit is contained in:
Peter Steinberger
2026-01-15 04:50:11 +00:00
parent 5fdaef3646
commit ef78b198cb
40 changed files with 2467 additions and 49 deletions

View File

@@ -20,6 +20,7 @@ const BROWSER_TOOL_ACTIONS = [
"status",
"start",
"stop",
"profiles",
"tabs",
"open",
"focus",

View File

@@ -4,6 +4,7 @@ const browserClientMocks = vi.hoisted(() => ({
browserCloseTab: vi.fn(async () => ({})),
browserFocusTab: vi.fn(async () => ({})),
browserOpenTab: vi.fn(async () => ({})),
browserProfiles: vi.fn(async () => []),
browserSnapshot: vi.fn(async () => ({
ok: true,
format: "ai",
@@ -113,6 +114,13 @@ describe("browser tool snapshot maxChars", () => {
const [, opts] = browserClientMocks.browserSnapshot.mock.calls.at(-1) ?? [];
expect(Object.hasOwn(opts ?? {}, "maxChars")).toBe(false);
});
it("lists profiles", async () => {
const tool = createBrowserTool();
await tool.execute?.(null, { action: "profiles" });
expect(browserClientMocks.browserProfiles).toHaveBeenCalledWith("http://127.0.0.1:18791");
});
});
describe("browser tool snapshot labels", () => {

View File

@@ -2,6 +2,7 @@ import {
browserCloseTab,
browserFocusTab,
browserOpenTab,
browserProfiles,
browserSnapshot,
browserStart,
browserStatus,
@@ -123,7 +124,7 @@ export function createBrowserTool(opts?: {
label: "Browser",
name: "browser",
description: [
"Control clawd's dedicated browser (status/start/stop/tabs/open/snapshot/screenshot/actions).",
"Control clawd's dedicated browser (status/start/stop/profiles/tabs/open/snapshot/screenshot/actions).",
"Use snapshot+act for UI automation. Avoid act:wait by default; use only in exceptional cases when no reliable UI state exists.",
`target selects browser location (sandbox|host|custom). Default: ${targetDefault}.`,
"controlUrl implies target=custom (remote control server).",
@@ -156,6 +157,8 @@ export function createBrowserTool(opts?: {
case "stop":
await browserStop(baseUrl, { profile });
return jsonResult(await browserStatus(baseUrl, { profile }));
case "profiles":
return jsonResult({ profiles: await browserProfiles(baseUrl) });
case "tabs":
return jsonResult({ tabs: await browserTabs(baseUrl, { profile }) });
case "open": {