From 3eed8c31a2f42030ba0010f146f83860f8834913 Mon Sep 17 00:00:00 2001 From: Mohamed Boudra Date: Thu, 2 Jul 2026 18:39:10 +0200 Subject: [PATCH] Fix browser tool workspace context --- .../src/browser-automation/handler.test.ts | 13 +- .../browser-automation/service.test.ts | 120 +++++++++-- .../features/browser-automation/service.ts | 16 +- .../src/server/browser-tools/tools.test.ts | 187 ++++++++++++------ .../server/src/server/browser-tools/tools.ts | 5 +- 5 files changed, 245 insertions(+), 96 deletions(-) diff --git a/packages/app/src/browser-automation/handler.test.ts b/packages/app/src/browser-automation/handler.test.ts index dd6a634cc..e147b95e1 100644 --- a/packages/app/src/browser-automation/handler.test.ts +++ b/packages/app/src/browser-automation/handler.test.ts @@ -70,8 +70,11 @@ function browserNewTabRequest(): BrowserAutomationExecuteRequest { type: "browser.automation.execute.request", requestId: "req-new", agentId: "agent-1", - workspaceId: "/repo", - command: { command: "new_tab", args: { workspaceId: "/repo", url: "https://example.com" } }, + workspaceId: "wks_workspace_a", + command: { + command: "new_tab", + args: { workspaceId: "wks_workspace_a", url: "https://example.com" }, + }, }; } @@ -108,7 +111,7 @@ function waitForAsyncWork(): Promise { function currentBrowserTabs() { return Object.values(useBrowserStore.getState().browsersById).map((browser) => ({ browserId: browser.browserId, - workspaceId: "/repo", + workspaceId: "wks_workspace_a", url: browser.url, title: browser.title, isActive: true, @@ -131,7 +134,7 @@ describe("mountBrowserAutomationHandler", () => { const executeAutomationCommand = vi.fn(async () => currentListTabsPayload()); const workspaceKey = buildWorkspaceTabPersistenceKey({ serverId: "server-1", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", }); if (!workspaceKey) throw new Error("expected workspace key"); const focusedTabId = useWorkspaceLayoutStore @@ -171,7 +174,7 @@ describe("mountBrowserAutomationHandler", () => { expect(layout.root.pane.focusedTabId).toBe(focusedTabId); expect(registerWorkspaceBrowser).toHaveBeenCalledWith({ browserId: payload.result.browserId, - workspaceId: "/repo", + workspaceId: "wks_workspace_a", }); expect(setAgentActiveBrowser).toHaveBeenCalledWith({ agentId: "agent-1", diff --git a/packages/desktop/src/features/browser-automation/service.test.ts b/packages/desktop/src/features/browser-automation/service.test.ts index 641c4105f..b53062da5 100644 --- a/packages/desktop/src/features/browser-automation/service.test.ts +++ b/packages/desktop/src/features/browser-automation/service.test.ts @@ -1495,6 +1495,7 @@ describe("executeAutomationCommand", () => { it("sets workspace files on a file input ref through CDP", async () => { const debugCommands: Array<{ command: string; params?: Record }> = []; const workspaceRoot = "/tmp/paseo-workspace-a"; + const workspaceOpaqueId = "wks_workspace_a"; const tab = fakeTab({ id: 25, executeJavaScript: async () => @@ -1519,18 +1520,20 @@ describe("executeAutomationCommand", () => { }, }); const registry = createRegistry({ - getWorkspaceActiveTabContents: (workspaceId) => - workspaceId === workspaceRoot ? tab : null, - getWorkspaceActiveBrowserId: (workspaceId) => (workspaceId === workspaceRoot ? "a" : null), - getBrowserWorkspaceId: (id) => (id === "a" ? workspaceRoot : null), + getWorkspaceActiveTabContents: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? tab : null, + getWorkspaceActiveBrowserId: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? "a" : null, + getBrowserWorkspaceId: (id) => (id === "a" ? workspaceOpaqueId : null), }); const snapshotEngine = new BrowserSnapshotEngine(); const snapshot = await executeAutomationCommand( { type: "browser.automation.execute.request", requestId: "r-snapshot-upload", - workspaceId: workspaceRoot, - command: { command: "snapshot", args: { workspaceId: workspaceRoot } }, + cwd: workspaceRoot, + workspaceId: workspaceOpaqueId, + command: { command: "snapshot", args: { workspaceId: workspaceOpaqueId } }, }, registry, { snapshotEngine }, @@ -1548,10 +1551,11 @@ describe("executeAutomationCommand", () => { { type: "browser.automation.execute.request", requestId: "r-upload", - workspaceId: workspaceRoot, + cwd: workspaceRoot, + workspaceId: workspaceOpaqueId, command: { command: "upload", - args: { workspaceId: workspaceRoot, ref, filePaths: ["uploads/file.txt"] }, + args: { workspaceId: workspaceOpaqueId, ref, filePaths: ["uploads/file.txt"] }, }, }, registry, @@ -1576,6 +1580,7 @@ describe("executeAutomationCommand", () => { it("rejects upload paths outside the workspace", async () => { const workspaceRoot = "/tmp/paseo-workspace-a"; + const workspaceOpaqueId = "wks_workspace_a"; const debugCommands: Array<{ command: string; params?: Record }> = []; const tab = fakeTab({ id: 26, @@ -1601,18 +1606,20 @@ describe("executeAutomationCommand", () => { }, }); const registry = createRegistry({ - getWorkspaceActiveTabContents: (workspaceId) => - workspaceId === workspaceRoot ? tab : null, - getWorkspaceActiveBrowserId: (workspaceId) => (workspaceId === workspaceRoot ? "a" : null), - getBrowserWorkspaceId: (id) => (id === "a" ? workspaceRoot : null), + getWorkspaceActiveTabContents: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? tab : null, + getWorkspaceActiveBrowserId: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? "a" : null, + getBrowserWorkspaceId: (id) => (id === "a" ? workspaceOpaqueId : null), }); const snapshotEngine = new BrowserSnapshotEngine(); const snapshot = await executeAutomationCommand( { type: "browser.automation.execute.request", requestId: "r-snapshot-upload-outside", - workspaceId: workspaceRoot, - command: { command: "snapshot", args: { workspaceId: workspaceRoot } }, + cwd: workspaceRoot, + workspaceId: workspaceOpaqueId, + command: { command: "snapshot", args: { workspaceId: workspaceOpaqueId } }, }, registry, { snapshotEngine }, @@ -1629,10 +1636,11 @@ describe("executeAutomationCommand", () => { { type: "browser.automation.execute.request", requestId: "r-upload-outside", - workspaceId: workspaceRoot, + cwd: workspaceRoot, + workspaceId: workspaceOpaqueId, command: { command: "upload", - args: { workspaceId: workspaceRoot, ref, filePaths: ["../secret.txt"] }, + args: { workspaceId: workspaceOpaqueId, ref, filePaths: ["../secret.txt"] }, }, }, registry, @@ -1652,6 +1660,86 @@ describe("executeAutomationCommand", () => { }, }); }); + + it("rejects upload when the request has no cwd", async () => { + const workspaceOpaqueId = "wks_workspace_a"; + const debugCommands: Array<{ command: string; params?: Record }> = []; + const tab = fakeTab({ + id: 28, + executeJavaScript: async () => + JSON.stringify([ + { + role: "textbox", + tagName: "input", + text: "", + selector: "#file", + attributes: { id: "file", type: "file" }, + }, + ]), + sendDebugCommand: async (command, params) => { + debugCommands.push({ command, params }); + if (command === "DOM.getDocument") { + return { root: { nodeId: 1 } }; + } + if (command === "DOM.querySelector") { + return { nodeId: 2 }; + } + return {}; + }, + }); + const registry = createRegistry({ + getWorkspaceActiveTabContents: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? tab : null, + getWorkspaceActiveBrowserId: (requestedWorkspaceId) => + requestedWorkspaceId === workspaceOpaqueId ? "a" : null, + getBrowserWorkspaceId: (id) => (id === "a" ? workspaceOpaqueId : null), + }); + const snapshotEngine = new BrowserSnapshotEngine(); + const snapshot = await executeAutomationCommand( + { + type: "browser.automation.execute.request", + requestId: "r-snapshot-upload-missing-cwd", + workspaceId: workspaceOpaqueId, + command: { command: "snapshot", args: { workspaceId: workspaceOpaqueId } }, + }, + registry, + { snapshotEngine }, + ); + if (!snapshot.ok || snapshot.result.command !== "snapshot") { + throw new Error("snapshot failed"); + } + const ref = snapshot.result.elements[0]?.ref; + if (!ref) { + throw new Error("missing upload ref"); + } + + const result = await executeAutomationCommand( + { + type: "browser.automation.execute.request", + requestId: "r-upload-missing-cwd", + workspaceId: workspaceOpaqueId, + command: { + command: "upload", + args: { workspaceId: workspaceOpaqueId, ref, filePaths: ["uploads/file.txt"] }, + }, + }, + registry, + { snapshotEngine }, + ); + + expect(debugCommands).not.toContainEqual( + expect.objectContaining({ command: "DOM.setFileInputFiles" }), + ); + expect(result).toEqual({ + requestId: "r-upload-missing-cwd", + ok: false, + error: { + code: "browser_unsupported", + message: "browser_upload requires request cwd", + retryable: false, + }, + }); + }); }); describe("navigation", () => { diff --git a/packages/desktop/src/features/browser-automation/service.ts b/packages/desktop/src/features/browser-automation/service.ts index 97b10afcb..38d2a8b74 100644 --- a/packages/desktop/src/features/browser-automation/service.ts +++ b/packages/desktop/src/features/browser-automation/service.ts @@ -319,6 +319,7 @@ const commandHandlers: Partial; return executeUpload( requestId, + request.cwd, workspaceId, uploadCommand.args.browserId ?? request.browserId, { ref: uploadCommand.args.ref, filePaths: uploadCommand.args.filePaths }, @@ -1273,6 +1274,7 @@ function isAllowedPageUrl(value: string): boolean { async function executeUpload( requestId: string, + cwd: string | undefined, workspaceId: string | undefined, browserId: string | undefined, input: { ref: string; filePaths: string[] }, @@ -1309,9 +1311,9 @@ async function executeUpload( if (typeof queried.nodeId !== "number" || queried.nodeId <= 0) { return staleRefFailure(requestId, input.ref); } - const workspaceRoot = resolveUploadWorkspaceRoot({ workspaceId, target, registry }); + const workspaceRoot = resolveUploadWorkspaceRoot(cwd); if (!workspaceRoot) { - return fail(requestId, "browser_unsupported", "browser_upload requires a workspace target"); + return fail(requestId, "browser_unsupported", "browser_upload requires request cwd"); } const filePaths = resolveWorkspaceFilePaths(input.filePaths, workspaceRoot); if (!filePaths) { @@ -1338,14 +1340,8 @@ async function executeUpload( }; } -function resolveUploadWorkspaceRoot(params: { - workspaceId: string | undefined; - target: ResolvedTabTarget; - registry: BrowserRegistry; -}): string | null { - const workspaceRoot = - params.workspaceId ?? params.registry.getBrowserWorkspaceId(params.target.browserId); - return workspaceRoot ? resolvePath(workspaceRoot) : null; +function resolveUploadWorkspaceRoot(cwd: string | undefined): string | null { + return cwd ? resolvePath(cwd) : null; } function resolveWorkspaceFilePaths(filePaths: string[], workspaceRoot: string): string[] | null { diff --git a/packages/server/src/server/browser-tools/tools.test.ts b/packages/server/src/server/browser-tools/tools.test.ts index 0ed8dbc36..88a88a90d 100644 --- a/packages/server/src/server/browser-tools/tools.test.ts +++ b/packages/server/src/server/browser-tools/tools.test.ts @@ -11,7 +11,11 @@ interface RegisteredTool { }>; } -function createHarness(options?: { brokerResponse?: BrowserToolsResponsePayload }) { +function createHarness(options?: { + brokerResponse?: BrowserToolsResponsePayload; + resolveCallerAgent?: RegisterBrowserToolsOptions["resolveCallerAgent"]; + callerAgentId?: string | null; +}) { const tools = new Map(); const execute = vi.fn(async () => { return ( @@ -43,8 +47,12 @@ function createHarness(options?: { brokerResponse?: BrowserToolsResponsePayload registerBrowserTools({ registerTool, broker: { execute } as unknown as BrowserToolsBroker, - callerAgentId: "agent-1", - resolveCallerAgent: () => ({ id: "agent-1", cwd: "/repo" }), + ...(options?.callerAgentId !== null + ? { callerAgentId: options?.callerAgentId ?? "agent-1" } + : {}), + resolveCallerAgent: + options?.resolveCallerAgent ?? + (() => ({ id: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" })), }); return { tools, execute }; @@ -67,8 +75,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "list_tabs", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "list_tabs", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([ { @@ -90,10 +98,39 @@ describe("registerBrowserTools", () => { }, ], }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); + it("omits workspaceId when the caller agent has no workspaceId", async () => { + const harness = createHarness({ + resolveCallerAgent: () => ({ id: "agent-1", cwd: "/repo" }), + }); + + const response = await tool(harness, "browser_list_tabs").handler({}); + + expect(harness.execute).toHaveBeenCalledWith({ + agentId: "agent-1", + cwd: "/repo", + command: { command: "list_tabs", args: {} }, + }); + expect(response.structuredContent?.context).toEqual({ agentId: "agent-1", cwd: "/repo" }); + }); + + it("uses empty browser context when there is no caller agent", async () => { + const harness = createHarness({ + callerAgentId: null, + resolveCallerAgent: () => null, + }); + + const response = await tool(harness, "browser_list_tabs").handler({}); + + expect(harness.execute).toHaveBeenCalledWith({ + command: { command: "list_tabs", args: {} }, + }); + expect(response.structuredContent?.context).toEqual({}); + }); + it("registers browser_new_tab and returns the created tab handle", async () => { const harness = createHarness({ brokerResponse: { @@ -102,7 +139,7 @@ describe("registerBrowserTools", () => { result: { command: "new_tab", browserId: "browser-new", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", url: "https://example.com", }, }, @@ -113,10 +150,10 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "new_tab", - args: { workspaceId: "/repo", url: "https://example.com" }, + args: { workspaceId: "wks_workspace_a", url: "https://example.com" }, }, }); expect(response.content).toEqual([ @@ -150,11 +187,11 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", browserId: "browser-2", command: { command: "page_info", - args: { workspaceId: "/repo", browserId: "browser-2" }, + args: { workspaceId: "wks_workspace_a", browserId: "browser-2" }, }, }); expect(response.content).toEqual([ @@ -172,7 +209,12 @@ describe("registerBrowserTools", () => { isLoading: false, }, }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo", browserId: "browser-2" }, + context: { + agentId: "agent-1", + cwd: "/repo", + workspaceId: "wks_workspace_a", + browserId: "browser-2", + }, }); }); @@ -184,7 +226,7 @@ describe("registerBrowserTools", () => { result: { command: "snapshot", browserId: "browser-1", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", url: "https://example.com/form", title: "Fixture", elements: [ @@ -206,8 +248,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "snapshot", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "snapshot", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([{ type: "text", text: "Snapshot captured 1 element." }]); expect(response.structuredContent).toEqual({ @@ -215,7 +257,7 @@ describe("registerBrowserTools", () => { result: { command: "snapshot", browserId: "browser-1", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", url: "https://example.com/form", title: "Fixture", elements: [ @@ -229,7 +271,7 @@ describe("registerBrowserTools", () => { }, ], }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); @@ -247,8 +289,11 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "set_background", args: { workspaceId: "/repo", color: "red" } }, + workspaceId: "wks_workspace_a", + command: { + command: "set_background", + args: { workspaceId: "wks_workspace_a", color: "red" }, + }, }); expect(response.content).toEqual([ { type: "text", text: "Set browser page background to red." }, @@ -269,14 +314,14 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "click", args: { workspaceId: "/repo", ref: "@e2" } }, + workspaceId: "wks_workspace_a", + command: { command: "click", args: { workspaceId: "wks_workspace_a", ref: "@e2" } }, }); expect(response.content).toEqual([{ type: "text", text: "Clicked browser element @e2." }]); expect(response.structuredContent).toEqual({ ok: true, result: { command: "click", browserId: "browser-1", ref: "@e2" }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); @@ -294,14 +339,17 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "fill", args: { workspaceId: "/repo", ref: "@e1", value: "Ada" } }, + workspaceId: "wks_workspace_a", + command: { + command: "fill", + args: { workspaceId: "wks_workspace_a", ref: "@e1", value: "Ada" }, + }, }); expect(response.content).toEqual([{ type: "text", text: "Filled browser element @e1." }]); expect(response.structuredContent).toEqual({ ok: true, result: { command: "fill", browserId: "browser-1", ref: "@e1" }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); @@ -322,18 +370,18 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", timeoutMs: 2000, command: { command: "wait", - args: { workspaceId: "/repo", text: "Ready", timeoutMs: 1000 }, + args: { workspaceId: "wks_workspace_a", text: "Ready", timeoutMs: 1000 }, }, }); expect(response.content).toEqual([{ type: "text", text: "Browser wait matched text." }]); expect(response.structuredContent).toEqual({ ok: true, result: { command: "wait", browserId: "browser-1", matched: "text" }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); @@ -351,8 +399,11 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "type", args: { workspaceId: "/repo", ref: "@e1", text: "Ada" } }, + workspaceId: "wks_workspace_a", + command: { + command: "type", + args: { workspaceId: "wks_workspace_a", ref: "@e1", text: "Ada" }, + }, }); expect(response.content).toEqual([{ type: "text", text: "Typed into browser element @e1." }]); }); @@ -374,10 +425,10 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "keypress", - args: { workspaceId: "/repo", ref: "@e1", key: "Enter" }, + args: { workspaceId: "wks_workspace_a", ref: "@e1", key: "Enter" }, }, }); expect(response.content).toEqual([ @@ -401,10 +452,10 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "navigate", - args: { workspaceId: "/repo", url: "https://example.com/next" }, + args: { workspaceId: "wks_workspace_a", url: "https://example.com/next" }, }, }); expect(response.content).toEqual([ @@ -426,8 +477,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "back", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "back", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([{ type: "text", text: "Browser back complete." }]); }); @@ -453,8 +504,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "screenshot", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "screenshot", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([ { type: "text", text: "Captured browser screenshot (100x50)." }, @@ -488,8 +539,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "logs", args: { workspaceId: "/repo", maxEntries: 25 } }, + workspaceId: "wks_workspace_a", + command: { command: "logs", args: { workspaceId: "wks_workspace_a", maxEntries: 25 } }, }); expect(response.content).toEqual([ { type: "text", text: "Read 1 console log and 1 network entry." }, @@ -517,8 +568,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "storage", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "storage", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([ { type: "text", text: "Read 1 cookie, 1 localStorage entry, and 1 sessionStorage entry." }, @@ -547,11 +598,11 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "environment", args: { - workspaceId: "/repo", + workspaceId: "wks_workspace_a", viewport: { width: 390, height: 844, deviceScaleFactor: 3 }, geolocation: { latitude: 37.7749, longitude: -122.4194, accuracy: 5 }, }, @@ -583,8 +634,8 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "full_page_screenshot", args: { workspaceId: "/repo" } }, + workspaceId: "wks_workspace_a", + command: { command: "full_page_screenshot", args: { workspaceId: "wks_workspace_a" } }, }); expect(response.content).toEqual([ { type: "text", text: "Captured full-page browser screenshot (390x1200)." }, @@ -611,10 +662,10 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "pdf", - args: { workspaceId: "/repo", landscape: true, printBackground: true }, + args: { workspaceId: "wks_workspace_a", landscape: true, printBackground: true }, }, }); expect(response.content).toEqual([{ type: "text", text: "Exported browser page PDF." }]); @@ -644,10 +695,14 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "download", - args: { workspaceId: "/repo", url: "https://example.com/file.txt", fileName: "file.txt" }, + args: { + workspaceId: "wks_workspace_a", + url: "https://example.com/file.txt", + fileName: "file.txt", + }, }, }); expect(response.content).toEqual([ @@ -677,10 +732,10 @@ describe("registerBrowserTools", () => { expect(harness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "upload", - args: { workspaceId: "/repo", ref: "@e1", filePaths: ["/tmp/file.txt"] }, + args: { workspaceId: "wks_workspace_a", ref: "@e1", filePaths: ["/tmp/file.txt"] }, }, }); expect(response.content).toEqual([ @@ -700,8 +755,8 @@ describe("registerBrowserTools", () => { expect(focusHarness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "focus", args: { workspaceId: "/repo", ref: "@e1" } }, + workspaceId: "wks_workspace_a", + command: { command: "focus", args: { workspaceId: "wks_workspace_a", ref: "@e1" } }, }); expect(focusResponse.content).toEqual([{ type: "text", text: "Focused browser element @e1." }]); @@ -719,8 +774,11 @@ describe("registerBrowserTools", () => { expect(checkHarness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "check", args: { workspaceId: "/repo", ref: "@e2", checked: false } }, + workspaceId: "wks_workspace_a", + command: { + command: "check", + args: { workspaceId: "wks_workspace_a", ref: "@e2", checked: false }, + }, }); expect(checkResponse.content).toEqual([ { type: "text", text: "Unchecked browser element @e2." }, @@ -740,8 +798,11 @@ describe("registerBrowserTools", () => { expect(selectHarness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "select", args: { workspaceId: "/repo", ref: "@e3", value: "us" } }, + workspaceId: "wks_workspace_a", + command: { + command: "select", + args: { workspaceId: "wks_workspace_a", ref: "@e3", value: "us" }, + }, }); expect(selectResponse.content).toEqual([ { type: "text", text: "Selected us in browser element @e3." }, @@ -758,8 +819,8 @@ describe("registerBrowserTools", () => { expect(hoverHarness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", - command: { command: "hover", args: { workspaceId: "/repo", ref: "@e4" } }, + workspaceId: "wks_workspace_a", + command: { command: "hover", args: { workspaceId: "wks_workspace_a", ref: "@e4" } }, }); expect(hoverResponse.content).toEqual([{ type: "text", text: "Hovered browser element @e4." }]); @@ -777,10 +838,10 @@ describe("registerBrowserTools", () => { expect(dragHarness.execute).toHaveBeenCalledWith({ agentId: "agent-1", cwd: "/repo", - workspaceId: "/repo", + workspaceId: "wks_workspace_a", command: { command: "drag", - args: { workspaceId: "/repo", sourceRef: "@e4", targetRef: "@e5" }, + args: { workspaceId: "wks_workspace_a", sourceRef: "@e4", targetRef: "@e5" }, }, }); expect(dragResponse.content).toEqual([ @@ -816,7 +877,7 @@ describe("registerBrowserTools", () => { message: "Browser tools are disabled. Enable daemon.browserTools.enabled to use them.", retryable: false, }, - context: { agentId: "agent-1", cwd: "/repo", workspaceId: "/repo" }, + context: { agentId: "agent-1", cwd: "/repo", workspaceId: "wks_workspace_a" }, }); }); diff --git a/packages/server/src/server/browser-tools/tools.ts b/packages/server/src/server/browser-tools/tools.ts index c78b12301..eed729a63 100644 --- a/packages/server/src/server/browser-tools/tools.ts +++ b/packages/server/src/server/browser-tools/tools.ts @@ -10,6 +10,7 @@ import type { interface CallerAgentContext { id: string; cwd: string; + workspaceId?: string; } export interface RegisterBrowserToolsOptions { @@ -839,10 +840,10 @@ function resolveBrowserToolContext(options: RegisterBrowserToolsOptions): { workspaceId?: string; } { const callerAgent = options.resolveCallerAgent(); - const cwd = callerAgent?.cwd; return { ...(options.callerAgentId ? { agentId: options.callerAgentId } : {}), - ...(cwd ? { cwd, workspaceId: cwd } : {}), + ...(callerAgent?.cwd ? { cwd: callerAgent.cwd } : {}), + ...(callerAgent?.workspaceId ? { workspaceId: callerAgent.workspaceId } : {}), }; }