Fix browser tool workspace context

This commit is contained in:
Mohamed Boudra
2026-07-02 18:39:10 +02:00
parent 58fce6622b
commit 3eed8c31a2
5 changed files with 245 additions and 96 deletions

View File

@@ -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<void> {
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",

View File

@@ -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<string, unknown> }> = [];
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<string, unknown> }> = [];
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<string, unknown> }> = [];
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", () => {

View File

@@ -319,6 +319,7 @@ const commandHandlers: Partial<Record<BrowserAutomationCommand["command"], Comma
const uploadCommand = command as Extract<BrowserAutomationCommand, { command: "upload" }>;
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 {

View File

@@ -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<string, RegisteredTool>();
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" },
});
});

View File

@@ -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 } : {}),
};
}