perf(agent-tools): shrink MCP tool catalog context cost (#1939)

Drop advertised MCP output schemas (no supported harness forwards them to the model) and remove the redundant wait_for_agent tool. Core agent tool catalog drops ~20.5k -> ~5.6k estimated tokens; ~24.9k -> ~9k with browser tools. Runtime structuredContent is preserved via server-side text serialization. Also corrects the agent-wait timeout guidance for blocking callers.
This commit is contained in:
Mohamed Boudra
2026-07-08 11:39:39 +02:00
committed by GitHub
parent 4fb70668f2
commit 5ec7ef9771
13 changed files with 451 additions and 297 deletions
@@ -146,24 +146,21 @@ function createMcpRecordingAgentClients(recorder: LaunchRecorder) {
};
}
async function waitForAgentCompletion(options: {
async function assertAgentNotRunning(options: {
client: McpClient;
agentId: string;
}): Promise<void> {
const waitResult = await options.client.callTool({
name: "wait_for_agent",
const statusResult = await options.client.callTool({
name: "get_agent_status",
args: { agentId: options.agentId },
});
const payload = getStructuredContent(waitResult);
const payload = getStructuredContent(statusResult);
if (!payload) {
throw new Error("wait_for_agent returned no structured payload");
}
if (payload.permission) {
throw new Error(`Unexpected permission while waiting: ${JSON.stringify(payload.permission)}`);
throw new Error("get_agent_status returned no structured payload");
}
const status = payload.status;
if (status === "running" || status === "initializing") {
throw new Error(`Agent still running after wait_for_agent (status=${status})`);
throw new Error(`Agent still running after blocking create_agent (status=${status})`);
}
}
@@ -218,7 +215,7 @@ describe("agent MCP end-to-end (offline)", () => {
agentId = typeof payload?.agentId === "string" ? payload.agentId : null;
expect(agentId).toBeTruthy();
await waitForAgentCompletion({ client, agentId: agentId! });
await assertAgentNotRunning({ client, agentId: agentId! });
if (existsSync(filePath)) {
const contents = await readFile(filePath, "utf8");
@@ -703,7 +700,7 @@ describe("agent MCP end-to-end (offline)", () => {
agentId = typeof payload?.agentId === "string" ? payload.agentId : null;
expect(agentId).toBeTruthy();
await waitForAgentCompletion({ client, agentId: agentId! });
await assertAgentNotRunning({ client, agentId: agentId! });
const statusResult = await client.callTool({
name: "get_agent_status",
args: { agentId },
@@ -6,12 +6,10 @@ import { realpathSync, rmSync } from "node:fs";
import { access, mkdtemp, mkdir, rm, writeFile } from "node:fs/promises";
import { join, resolve as resolvePath } from "node:path";
import { tmpdir } from "node:os";
import Ajv from "ajv";
import { z } from "zod";
import { createTestLogger } from "../../test-utils/test-logger.js";
import { createAgentMcpServer } from "./mcp-server.js";
import { createPaseoToolCatalog } from "./tools/paseo-tools.js";
import { AgentManager, type ManagedAgent } from "./agent-manager.js";
import { AgentStorage, type StoredAgentRecord } from "./agent-storage.js";
import { createTestAgentClients } from "../test-utils/fake-agent-client.js";
@@ -83,7 +81,6 @@ interface LooseContentBlock {
interface RegisteredMcpTool {
inputSchema: LooseInputSchema;
outputSchema?: unknown;
callback?: (
input: unknown,
extra?: unknown,
@@ -136,24 +133,20 @@ async function invokeToolWithParsedInput(
return tool.handler(parsed.data);
}
function expectOutputSchemaAccepts(tool: RegisteredMcpTool, data: unknown): void {
expect(tool.outputSchema).toBeDefined();
const jsonSchema = z.toJSONSchema(tool.outputSchema as z.ZodType, {
target: "draft-07",
unrepresentable: "any",
io: "input",
});
const ajv = new Ajv({ allErrors: true, strict: false });
const validate = ajv.compile(jsonSchema);
expect(validate(data), JSON.stringify(validate.errors, null, 2)).toBe(true);
}
function agentsOf(response: {
structuredContent: LooseStructuredContent;
}): Array<Record<string, unknown>> {
return z.array(z.record(z.string(), z.unknown())).parse(response.structuredContent.agents);
}
function expectSingleTextContent(response: { content?: LooseContentBlock[] }): string {
const content = response.content ?? [];
expect(content).toHaveLength(1);
const block = content[0];
expect(block?.type).toBe("text");
return z.string().min(1).parse(block?.text);
}
async function waitForWorkspaceTitle(
workspaceRecords: Map<string, PersistedWorkspaceRecord>,
workspaceId: string,
@@ -753,7 +746,7 @@ function createPaseoWorktreeForMcpTest(options: {
describe("browser MCP tools", () => {
const logger = createTestLogger();
it("calls registered tools through the MCP SDK with listed output schemas", async () => {
it("omits output schemas from tools/list and keeps tool call content model-visible", async () => {
const agentManager = new BoundaryAgentManagerFake();
const agentStorage = new BoundaryAgentStorageFake();
const broker = new FakeBrowserToolsBroker({
@@ -802,17 +795,15 @@ describe("browser MCP tools", () => {
expect(listAgentsResult.structuredContent).toEqual({
agents: [],
});
expectSingleTextContent(browserResult);
expect(expectSingleTextContent(listAgentsResult)).toContain('"agents": []');
const listedTools = await client.listTools();
const toolsByName = new Map(listedTools.tools.map((tool) => [tool.name, tool]));
const catalog = createPaseoToolCatalog(serverOptions);
for (const tool of catalog.tools.values()) {
if (tool.outputSchema !== undefined) {
expect(toolsByName.get(tool.name)?.outputSchema, `${tool.name} outputSchema`).toEqual(
expect.objectContaining({ type: "object" }),
);
}
expect(listedTools.tools.map((tool) => tool.name)).toEqual(
expect.arrayContaining(["browser_list_tabs", "list_agents"]),
);
for (const tool of listedTools.tools) {
expect(tool, `${tool.name} outputSchema`).not.toHaveProperty("outputSchema");
}
} finally {
await client.close();
@@ -1308,7 +1299,7 @@ describe("create_agent MCP tool", () => {
);
});
it("advertises create_agent output schema that accepts full provider modes", async () => {
it("returns create_agent structured content with full provider modes", async () => {
const { agentManager, agentStorage, spies } = createTestDeps();
spies.agentManager.createAgent.mockResolvedValue({
id: "mode-agent",
@@ -1344,7 +1335,24 @@ describe("create_agent MCP tool", () => {
background: true,
});
expectOutputSchemaAccepts(tool, response.structuredContent);
expect(response.structuredContent).toEqual(
expect.objectContaining({
agentId: "mode-agent",
type: "codex",
status: "idle",
cwd: REPO_CWD,
currentModeId: "build",
availableModes: [
{
id: "build",
label: "Build",
description: null,
icon: "hammer",
colorTier: "dangerous",
},
],
}),
);
});
it("requires provider as provider/model and rejects the old model field", async () => {
@@ -2904,7 +2912,7 @@ describe("create_agent MCP tool", () => {
});
expect(response.structuredContent.guidance).toBe(
"You will get notified when the created agent finishes, errors, or needs permission. Do not call wait_for_agent or poll for status; continue with other work until the notification arrives.",
"You will get notified when the created agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.",
);
});
@@ -3364,7 +3372,7 @@ describe("send_agent_prompt MCP tool", () => {
expect(spies.agentManager.subscribe).toHaveBeenCalledTimes(1);
expect(spies.agentManager.waitForAgentEvent).not.toHaveBeenCalled();
expect(response.structuredContent.guidance).toBe(
"You will get notified when the prompted agent finishes, errors, or needs permission. Do not call wait_for_agent or poll for status; continue with other work until the notification arrives.",
"You will get notified when the prompted agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.",
);
});
@@ -3816,7 +3824,7 @@ describe("create_schedule MCP tool", () => {
);
});
it("advertises create_schedule output schema that accepts inherited feature values", async () => {
it("returns create_schedule structured content with inherited feature values", async () => {
const { agentManager, agentStorage, spies } = createTestDeps();
spies.agentManager.getAgent.mockReturnValue({
id: "parent-agent",
@@ -3854,7 +3862,6 @@ describe("create_schedule MCP tool", () => {
type: "new-agent",
config: { featureValues: { auto_accept: true } },
});
expectOutputSchemaAccepts(tool, response.structuredContent);
});
it("passes timezone through cron create_schedule input", async () => {
@@ -4872,7 +4879,6 @@ describe("agent snapshot MCP serialization", () => {
`get_agent_status response failed AgentSnapshotPayloadSchema: ${JSON.stringify(parsed.error.issues, null, 2)}`,
);
}
expectOutputSchemaAccepts(tool, response.structuredContent);
expect(response.structuredContent.status).toBe("idle");
expect(snapshot).toEqual(
expect.objectContaining({
@@ -5200,7 +5206,7 @@ describe("agent snapshot MCP serialization", () => {
]);
});
it("emits list_agents payloads that satisfy the declared output schema", async () => {
it("emits list_agents payloads that satisfy the agent list schema", async () => {
const { agentManager, agentStorage, spies } = createTestDeps();
const now = new Date().toISOString();
spies.agentManager.listAgents.mockReturnValue([createManagedAgent()]);
@@ -5231,7 +5237,7 @@ describe("agent snapshot MCP serialization", () => {
}
});
it("emits list_pending_permissions payloads that satisfy the declared output schema", async () => {
it("emits list_pending_permissions payloads that satisfy the permission schema", async () => {
const { agentManager, agentStorage, spies } = createTestDeps();
spies.agentManager.listAgents.mockReturnValue([
createManagedAgent({
@@ -5288,7 +5294,6 @@ describe("agent snapshot MCP serialization", () => {
},
},
]);
expectOutputSchemaAccepts(tool, response.structuredContent);
});
it("loads archived agents before reading get_agent_activity", async () => {
@@ -85,7 +85,6 @@ export async function createAgentMcpServer(options: AgentMcpServerOptions): Prom
title: tool.title,
description: tool.description,
inputSchema: tool.inputSchema,
outputSchema: tool.outputSchema,
},
async (args: unknown, context?: McpToolContext) =>
toMcpToolResult(await catalog.executeTool(tool.name, args, { signal: context?.signal })),
@@ -145,7 +145,7 @@ export async function waitForAgentWithTimeout(
});
const recentActivity = curateAgentActivity(recent.items);
const waitedSeconds = Math.round(AGENT_WAIT_TIMEOUT_MS / 1000);
const message = `Awaiting the agent timed out after ${waitedSeconds}s. This does not mean the agent failed - call wait_for_agent again to continue waiting.\n\nRecent activity:\n${recentActivity}`;
const message = `Awaiting the agent timed out after ${waitedSeconds}s. This does not mean the agent failed - it is still running. Call get_agent_status to check on it, or continue with other work if you will receive a finish notification.\n\nRecent activity:\n${recentActivity}`;
return {
status: snapshot?.lifecycle ?? "idle",
permission: null,
@@ -3,7 +3,7 @@ import { ensureValidJson } from "../../json-utils.js";
import type { Logger } from "pino";
import type { AgentMode, AgentProvider } from "../agent-sdk-types.js";
import type { AgentManager, WaitForAgentResult } from "../agent-manager.js";
import type { AgentManager } from "../agent-manager.js";
import {
AgentFeatureSchema,
AgentPermissionRequestPayloadSchema,
@@ -26,7 +26,6 @@ import {
killTerminalsForWorkspace,
type ArchiveDependencies,
} from "../../workspace-archive-service.js";
import { WaitForAgentTracker } from "../wait-for-agent-tracker.js";
import { createAgentCommand, type CreateAgentFromMcpInput } from "../create-agent/create.js";
import type { VoiceCallerContext, VoiceSpeakHandler } from "../../voice-types.js";
import type { FirstAgentContext } from "../../messages.js";
@@ -436,7 +435,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
logger,
} = options;
const childLogger = logger.child({ module: "agent", component: "paseo-tool-catalog" });
const waitTracker = new WaitForAgentTracker(logger);
const callerContext = callerAgentId ? (resolveCallerContext?.(callerAgentId) ?? null) : null;
const parseToolInput = async (tool: PaseoToolDefinition, input: unknown): Promise<unknown> => {
@@ -1145,7 +1143,7 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
const currentSnapshot = agentManager.getAgent(snapshot.id) ?? snapshot;
const guidance =
callerAgentId && notifyOnFinish && initialPromptStarted
? "You will get notified when the created agent finishes, errors, or needs permission. Do not call wait_for_agent or poll for status; continue with other work until the notification arrives."
? "You will get notified when the created agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives."
: undefined;
const response = {
content: [],
@@ -1409,83 +1407,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
}
}
registerTool(
"wait_for_agent",
{
title: "Wait for agent",
description:
"Block until the agent requests permission or the current run completes. Returns the pending permission (if any) and recent activity summary.",
inputSchema: {
agentId: z.string().describe("Agent identifier returned by the create_agent tool"),
},
outputSchema: {
agentId: z.string(),
status: AgentStatusEnum,
permission: AgentPermissionRequestPayloadSchema.nullable(),
lastMessage: z.string().nullable(),
},
},
async ({ agentId }, { signal }) => {
const abortController = new AbortController();
const cleanupFns: Array<() => void> = [];
const cleanup = () => {
while (cleanupFns.length) {
const fn = cleanupFns.pop();
try {
fn?.();
} catch {
// ignore cleanup errors
}
}
};
const forwardExternalAbort = () => {
if (!abortController.signal.aborted) {
const reason = signal?.reason ?? new Error("wait_for_agent aborted");
abortController.abort(reason);
}
};
if (signal) {
if (signal.aborted) {
forwardExternalAbort();
} else {
signal.addEventListener("abort", forwardExternalAbort, { once: true });
cleanupFns.push(() => signal.removeEventListener("abort", forwardExternalAbort));
}
}
const unregister = waitTracker.register(agentId, (reason) => {
if (!abortController.signal.aborted) {
abortController.abort(new Error(reason ?? "wait_for_agent cancelled"));
}
});
cleanupFns.push(unregister);
try {
const result: WaitForAgentResult = await waitForAgentWithTimeout(agentManager, agentId, {
signal: abortController.signal,
});
const validJson = ensureValidJson({
agentId,
status: result.status,
permission: sanitizePermissionRequest(result.permission),
lastMessage: result.lastMessage,
});
const response = {
content: [],
structuredContent: validJson,
};
return response;
} finally {
cleanup();
}
},
);
registerTool(
"send_agent_prompt",
{
@@ -1508,9 +1429,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
background = Boolean(callerAgentId),
notifyOnFinish = Boolean(callerAgentId),
}) => {
if (agentManager.hasInFlightRun(agentId)) {
waitTracker.cancel(agentId, "Agent run interrupted by new prompt");
}
const shouldNotifyOnFinish = Boolean(callerAgentId && notifyOnFinish && background);
await sendPromptToAgent({
@@ -1565,7 +1483,7 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
...(shouldNotifyOnFinish
? {
guidance:
"You will get notified when the prompted agent finishes, errors, or needs permission. Do not call wait_for_agent or poll for status; continue with other work until the notification arrives.",
"You will get notified when the prompted agent finishes, errors, or needs permission. Do not poll for status; continue with other work until the notification arrives.",
}
: {}),
};
@@ -1705,9 +1623,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
{ agentManager, logger: childLogger },
agentId,
);
if (cancelled) {
waitTracker.cancel(agentId, "Agent run cancelled");
}
return {
content: [],
structuredContent: ensureValidJson({ success: cancelled }),
@@ -1737,7 +1652,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
},
agentId,
);
waitTracker.cancel(agentId, "Agent archived");
return {
content: [],
structuredContent: ensureValidJson({ success: true }),
@@ -1759,7 +1673,6 @@ export function createPaseoToolCatalog(options: PaseoToolHostDependencies): Pase
},
async ({ agentId }) => {
await closeAgentCommand({ agentManager }, agentId);
waitTracker.cancel(agentId, "Agent terminated");
return {
content: [],
structuredContent: ensureValidJson({ success: true }),
@@ -1,43 +0,0 @@
import { describe, expect, it, vi } from "vitest";
import { createTestLogger } from "../../test-utils/test-logger.js";
import { WaitForAgentTracker } from "./wait-for-agent-tracker.js";
describe("WaitForAgentTracker", () => {
const logger = createTestLogger();
it("registers and cancels waiters per agent", () => {
const tracker = new WaitForAgentTracker(logger);
const cancelA = vi.fn();
const cancelB = vi.fn();
tracker.register("agent-a", cancelA);
tracker.register("agent-a", cancelB);
expect(tracker.cancel("agent-a", "test")).toBe(true);
expect(cancelA).toHaveBeenCalledWith("test");
expect(cancelB).toHaveBeenCalledWith("test");
// Subsequent cancels should no-op once cleared
expect(tracker.cancel("agent-a")).toBe(false);
// Unregister removes callback without triggering it
const cancelC = vi.fn();
const unregisterC = tracker.register("agent-b", cancelC);
unregisterC();
expect(tracker.cancel("agent-b")).toBe(false);
expect(cancelC).not.toHaveBeenCalled();
});
it("supports cancelling all waiters", () => {
const tracker = new WaitForAgentTracker(logger);
const cancelA = vi.fn();
const cancelB = vi.fn();
tracker.register("agent-a", cancelA);
tracker.register("agent-b", cancelB);
expect(tracker.cancelAll()).toBe(2);
expect(cancelA).toHaveBeenCalled();
expect(cancelB).toHaveBeenCalled();
});
});
@@ -1,62 +0,0 @@
import type { Logger } from "pino";
export type WaitForAgentCanceler = (agentId: string, reason?: string) => boolean;
/**
* Tracks long-running wait_for_agent tool calls so they can be cancelled
* explicitly (e.g., when a voice barge-in aborts the current turn).
*/
export class WaitForAgentTracker {
private waiters = new Map<string, Set<(reason?: string) => void>>();
private logger: Logger;
constructor(logger: Logger) {
this.logger = logger.child({ module: "agent", component: "wait-for-agent-tracker" });
}
register(agentId: string, cancel: (reason?: string) => void): () => void {
if (!this.waiters.has(agentId)) {
this.waiters.set(agentId, new Set());
}
const waitersForAgent = this.waiters.get(agentId)!;
waitersForAgent.add(cancel);
return () => {
const current = this.waiters.get(agentId);
if (!current) {
return;
}
current.delete(cancel);
if (current.size === 0) {
this.waiters.delete(agentId);
}
};
}
cancel(agentId: string, reason?: string): boolean {
const waitersForAgent = this.waiters.get(agentId);
if (!waitersForAgent || waitersForAgent.size === 0) {
return false;
}
this.waiters.delete(agentId);
for (const cancel of waitersForAgent) {
try {
cancel(reason);
} catch (error) {
this.logger.warn({ err: error, agentId }, "Cancel callback failed");
}
}
return true;
}
cancelAll(reason?: string): number {
let cancelled = 0;
for (const agentId of Array.from(this.waiters.keys())) {
if (this.cancel(agentId, reason)) {
cancelled += 1;
}
}
return cancelled;
}
}
@@ -35,38 +35,6 @@ const WORKSPACE_CONTEXT_MESSAGE =
const URL_WHITESPACE_PATTERN = /\s/;
const NON_HTTP_EXPLICIT_SCHEME_PATTERN = /^(?!https?:\/\/)[a-z][a-z0-9+.-]*:\/\//i;
const BrowserToolOutputSchema = {
ok: z.boolean(),
result: z.unknown().optional(),
error: z
.object({
code: z.string(),
message: z.string(),
retryable: z.boolean(),
})
.optional(),
dialogs: z
.array(
z.object({
type: z.enum(["alert", "confirm", "prompt", "beforeunload"]),
message: z.string(),
defaultValue: z.string().optional(),
action: z.enum(["accepted", "dismissed"]),
promptText: z.string().optional(),
timestamp: z.number(),
}),
)
.optional(),
context: z
.object({
agentId: z.string().optional(),
cwd: z.string().optional(),
workspaceId: z.string().optional(),
browserId: z.string().optional(),
})
.optional(),
};
const BrowserHttpUrlInputSchema = z
.string()
.trim()
@@ -103,7 +71,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
description:
"List open Paseo browser tabs for this agent's workspace across connected browser automation hosts. Use returned browserId values with tab-scoped tools.",
inputSchema: {},
outputSchema: BrowserToolOutputSchema,
},
async () => {
const context = resolveBrowserToolContext(options);
@@ -133,7 +100,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
inputSchema: {
url: BrowserHttpUrlInputSchema.optional(),
},
outputSchema: BrowserToolOutputSchema,
},
async ({ url }) => {
const context = resolveBrowserToolContext(options);
@@ -163,7 +129,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
inputSchema: {
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -196,7 +161,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
doubleClick: z.boolean().optional(),
modifiers: z.array(BrowserClickModifierInputSchema).optional(),
},
outputSchema: BrowserToolOutputSchema,
},
async ({ ref, browserId, button, doubleClick, modifiers }) => {
const context = resolveBrowserToolContext(options);
@@ -231,7 +195,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
value: z.string(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ ref, value, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -260,7 +223,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
description:
"Wait until a Paseo browser tab contains text or reaches a URL fragment. Use browserId from browser_new_tab or browser_list_tabs; waits up to 5s by default on the browser host.",
inputSchema: BrowserWaitInputSchema,
outputSchema: BrowserToolOutputSchema,
},
async ({ text, url, timeoutMs, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -295,7 +257,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
ref: BrowserRefInputSchema.optional(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ text, ref, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -328,7 +289,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
ref: BrowserRefInputSchema.optional(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ key, ref, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -357,7 +317,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
description:
"Navigate a Paseo browser tab to a URL. Use browserId from browser_new_tab or browser_list_tabs; pass an http(s) URL or a scheme-less host URL, which is treated as http.",
inputSchema: { url: BrowserHttpUrlInputSchema, browserId: BrowserAutomationBrowserIdSchema },
outputSchema: BrowserToolOutputSchema,
},
async ({ url, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -407,7 +366,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
title: toolConfig.title,
description: toolConfig.description,
inputSchema: { browserId: BrowserAutomationBrowserIdSchema },
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -438,7 +396,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
browserId: BrowserAutomationBrowserIdSchema,
fullPage: z.boolean().default(false),
},
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId, fullPage }) => {
const context = resolveBrowserToolContext(options);
@@ -470,7 +427,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
filePaths: z.array(z.string().min(1)).min(1),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ ref, filePaths, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -507,7 +463,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
title: toolConfig.title,
description: toolConfig.description,
inputSchema: { ref: BrowserRefInputSchema, browserId: BrowserAutomationBrowserIdSchema },
outputSchema: BrowserToolOutputSchema,
},
async ({ ref, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -540,7 +495,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
value: z.string(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ ref, value, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -573,7 +527,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
targetRef: BrowserRefInputSchema,
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ sourceRef, targetRef, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -605,7 +558,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
maxEntries: z.number().int().positive().max(200).optional(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ maxEntries, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -637,7 +589,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
ref: BrowserRefInputSchema.optional(),
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ function: functionSource, ref, browserId }) => {
const context = resolveBrowserToolContext(options);
@@ -671,7 +622,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
deltaX: z.number(),
deltaY: z.number(),
},
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId, ref, deltaX, deltaY }) => {
const context = resolveBrowserToolContext(options);
@@ -705,7 +655,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
width: z.number().int().positive(),
height: z.number().int().positive(),
},
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId, width, height }) => {
const context = resolveBrowserToolContext(options);
@@ -736,7 +685,6 @@ export function registerBrowserTools(options: RegisterBrowserToolsOptions): void
inputSchema: {
browserId: BrowserAutomationBrowserIdSchema,
},
outputSchema: BrowserToolOutputSchema,
},
async ({ browserId }) => {
const context = resolveBrowserToolContext(options);