From 3ba2de01ccce7a421d4dbb239736e11d21df3b02 Mon Sep 17 00:00:00 2001 From: Cynthia Long Date: Thu, 2 Apr 2026 16:36:34 +0000 Subject: [PATCH] rename 'browser_agent' to 'browser' --- docs/core/subagents.md | 10 +-- .../browser-agent.cleanup.responses | 2 +- .../browser-agent.interaction.responses | 2 +- .../browser-agent.navigate-snapshot.responses | 2 +- .../browser-agent.screenshot.responses | 2 +- .../browser-agent.sequential.responses | 2 +- integration-tests/browser-agent.test.ts | 62 +++++++++++++------ integration-tests/browser-policy.responses | 2 +- integration-tests/browser-policy.test.ts | 15 +++-- .../agents/browser/browserAgentDefinition.ts | 2 +- .../browser/browserAgentFactory.test.ts | 24 +++---- .../browser/browserAgentInvocation.test.ts | 36 +++++------ .../agents/browser/browserAgentInvocation.ts | 2 +- .../src/agents/browser/browserManager.test.ts | 36 +++++------ .../mcpToolWrapperConfirmation.test.ts | 6 +- packages/core/src/agents/registry.test.ts | 16 ++--- packages/core/src/config/config.test.ts | 4 +- packages/core/src/config/config.ts | 8 ++- 18 files changed, 133 insertions(+), 100 deletions(-) diff --git a/docs/core/subagents.md b/docs/core/subagents.md index a789e0f741..e8887ff8c5 100644 --- a/docs/core/subagents.md +++ b/docs/core/subagents.md @@ -104,7 +104,7 @@ Gemini CLI comes with the following built-in subagents: ### Browser Agent (experimental) -- **Name:** `browser_agent` +- **Name:** `browser` - **Purpose:** Automate web browser tasks — navigating websites, filling forms, clicking buttons, and extracting information from web pages — using the accessibility tree. @@ -133,7 +133,7 @@ The browser agent is disabled by default. Enable it in your `settings.json`: { "agents": { "overrides": { - "browser_agent": { + "browser": { "enabled": true } } @@ -150,7 +150,7 @@ under `agents.browser`: { "agents": { "overrides": { - "browser_agent": { + "browser": { "enabled": true } }, @@ -201,7 +201,7 @@ can enable the visual agent by setting a `visualModel`: { "agents": { "overrides": { - "browser_agent": { + "browser": { "enabled": true } }, @@ -261,7 +261,7 @@ To use the browser agent in a Docker sandbox: { "agents": { "overrides": { - "browser_agent": { "enabled": true } + "browser": { "enabled": true } }, "browser": { "sessionMode": "existing", diff --git a/integration-tests/browser-agent.cleanup.responses b/integration-tests/browser-agent.cleanup.responses index 9cf7a7b356..2156bf02f7 100644 --- a/integration-tests/browser-agent.cleanup.responses +++ b/integration-tests/browser-agent.cleanup.responses @@ -1,4 +1,4 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll open https://example.com and check the page title for you."},{"functionCall":{"name":"browser_agent","args":{"task":"Open https://example.com and get the page title"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":35,"totalTokenCount":135}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll open https://example.com and check the page title for you."},{"functionCall":{"name":"browser","args":{"task":"Open https://example.com and get the page title"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":35,"totalTokenCount":135}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I have opened the page and the title is 'Example Domain'."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":30,"totalTokenCount":230}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"The task is complete. The page title is 'Example Domain'."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":300,"candidatesTokenCount":20,"totalTokenCount":320}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"Done."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":400,"candidatesTokenCount":5,"totalTokenCount":405}}]} diff --git a/integration-tests/browser-agent.interaction.responses b/integration-tests/browser-agent.interaction.responses index 98474d6b59..344701f965 100644 --- a/integration-tests/browser-agent.interaction.responses +++ b/integration-tests/browser-agent.interaction.responses @@ -1,2 +1,2 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll navigate to https://example.com and analyze the links on the page."},{"functionCall":{"name":"browser_agent","args":{"task":"Go to https://example.com and find all links on the page, then describe them"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":40,"totalTokenCount":140}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll navigate to https://example.com and analyze the links on the page."},{"functionCall":{"name":"browser","args":{"task":"Go to https://example.com and find all links on the page, then describe them"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":40,"totalTokenCount":140}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"After analyzing https://example.com, I found the following links:\n\n1. **\"More information...\"** - This is the main link on the page that points to the IANA (Internet Assigned Numbers Authority) website for more details about reserved domains.\n\nThe page is quite minimal with just this single informational link, which is typical for example domains used in documentation."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":70,"totalTokenCount":270}}]} diff --git a/integration-tests/browser-agent.navigate-snapshot.responses b/integration-tests/browser-agent.navigate-snapshot.responses index 481520234d..7597583400 100644 --- a/integration-tests/browser-agent.navigate-snapshot.responses +++ b/integration-tests/browser-agent.navigate-snapshot.responses @@ -1,2 +1,2 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you open https://example.com and analyze the page. Let me use the browser agent to navigate and capture the page information."},{"functionCall":{"name":"browser_agent","args":{"task":"Navigate to https://example.com and capture the accessibility tree to get the page title and main content"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you open https://example.com and analyze the page. Let me use the browser agent to navigate and capture the page information."},{"functionCall":{"name":"browser","args":{"task":"Navigate to https://example.com and capture the accessibility tree to get the page title and main content"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"Based on the browser analysis of https://example.com:\n\n**Page Title**: Example Domain\n\n**Main Content**: The page contains a simple heading \"Example Domain\" and explanatory text stating \"This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.\"\n\nThe page has a clean, minimal layout typical of placeholder domains used for documentation and examples."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":80,"totalTokenCount":280}}]} diff --git a/integration-tests/browser-agent.screenshot.responses b/integration-tests/browser-agent.screenshot.responses index c9abaa4268..58b4fd11cf 100644 --- a/integration-tests/browser-agent.screenshot.responses +++ b/integration-tests/browser-agent.screenshot.responses @@ -1,2 +1,2 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll navigate to https://example.com and take a screenshot for you."},{"functionCall":{"name":"browser_agent","args":{"task":"Navigate to https://example.com and take a screenshot of the page"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":40,"totalTokenCount":140}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll navigate to https://example.com and take a screenshot for you."},{"functionCall":{"name":"browser","args":{"task":"Navigate to https://example.com and take a screenshot of the page"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":40,"totalTokenCount":140}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I've successfully navigated to https://example.com and captured a screenshot. The page shows the familiar \"Example Domain\" header with explanatory text below it. The screenshot captures the clean, minimal layout of this demonstration website."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":50,"totalTokenCount":250}}]} diff --git a/integration-tests/browser-agent.sequential.responses b/integration-tests/browser-agent.sequential.responses index 74732998aa..9f212bcae6 100644 --- a/integration-tests/browser-agent.sequential.responses +++ b/integration-tests/browser-agent.sequential.responses @@ -1,2 +1,2 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you navigate to https://example.com and perform both operations - capturing the accessibility tree and taking a screenshot."},{"functionCall":{"name":"browser_agent","args":{"task":"Navigate to https://example.com, take a snapshot of the accessibility tree, then take a screenshot"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":45,"totalTokenCount":145}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you navigate to https://example.com and perform both operations - capturing the accessibility tree and taking a screenshot."},{"functionCall":{"name":"browser","args":{"task":"Navigate to https://example.com, take a snapshot of the accessibility tree, then take a screenshot"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":45,"totalTokenCount":145}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I've successfully completed both operations on https://example.com:\n\n**Accessibility Tree Snapshot**: The page has a clear structure with the main heading \"Example Domain\" and descriptive text about the domain's purpose for documentation examples.\n\n**Screenshot**: Captured a visual representation of the page showing the clean, minimal layout with the heading and explanatory text.\n\nBoth the accessibility data and visual screenshot confirm this is the standard example domain page used for documentation purposes."}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":200,"candidatesTokenCount":80,"totalTokenCount":280}}]} diff --git a/integration-tests/browser-agent.test.ts b/integration-tests/browser-agent.test.ts index f9f07d4c9e..de9ae0e044 100644 --- a/integration-tests/browser-agent.test.ts +++ b/integration-tests/browser-agent.test.ts @@ -8,7 +8,7 @@ * Integration tests for the browser agent. * * These tests verify the complete end-to-end flow from CLI prompt through - * browser_agent delegation to MCP/Chrome DevTools and back. Unlike the unit + * browser delegation to MCP/Chrome DevTools and back. Unlike the unit * tests in packages/core/src/agents/browser/ which mock all MCP components, * these tests launch real Chrome instances in headless mode. * @@ -77,7 +77,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { ), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, @@ -93,12 +98,9 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { const toolLogs = rig.readToolLogs(); const browserAgentCall = toolLogs.find( - (t) => t.toolRequest.name === 'browser_agent', + (t) => t.toolRequest.name === 'browser', ); - expect( - browserAgentCall, - 'Expected browser_agent to be called', - ).toBeDefined(); + expect(browserAgentCall, 'Expected browser to be called').toBeDefined(); }); it('should take screenshots of web pages', async () => { @@ -106,7 +108,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { fakeResponsesPath: join(__dirname, 'browser-agent.screenshot.responses'), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, @@ -120,7 +127,7 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { const toolLogs = rig.readToolLogs(); const browserCalls = toolLogs.filter( - (t) => t.toolRequest.name === 'browser_agent', + (t) => t.toolRequest.name === 'browser', ); expect(browserCalls.length).toBeGreaterThan(0); @@ -132,7 +139,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { fakeResponsesPath: join(__dirname, 'browser-agent.interaction.responses'), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, @@ -146,12 +158,9 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { const toolLogs = rig.readToolLogs(); const browserAgentCall = toolLogs.find( - (t) => t.toolRequest.name === 'browser_agent', + (t) => t.toolRequest.name === 'browser', ); - expect( - browserAgentCall, - 'Expected browser_agent to be called', - ).toBeDefined(); + expect(browserAgentCall, 'Expected browser to be called').toBeDefined(); assertModelHasOutput(result); }); @@ -161,7 +170,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { fakeResponsesPath: join(__dirname, 'browser-agent.cleanup.responses'), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, @@ -182,7 +196,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { fakeResponsesPath: join(__dirname, 'browser-agent.sequential.responses'), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, @@ -196,7 +215,7 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { const toolLogs = rig.readToolLogs(); const browserCalls = toolLogs.filter( - (t) => t.toolRequest.name === 'browser_agent', + (t) => t.toolRequest.name === 'browser', ); expect(browserCalls.length).toBeGreaterThan(0); @@ -212,7 +231,12 @@ describe.skipIf(!chromeAvailable)('browser-agent', () => { ), settings: { agents: { - browser_agent: { + overrides: { + browser: { + enabled: true, + }, + }, + browser: { headless: true, sessionMode: 'isolated', }, diff --git a/integration-tests/browser-policy.responses b/integration-tests/browser-policy.responses index 23d14e0cb3..3f87e586f8 100644 --- a/integration-tests/browser-policy.responses +++ b/integration-tests/browser-policy.responses @@ -1,4 +1,4 @@ -{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you with that."},{"functionCall":{"name":"browser_agent","args":{"task":"Open https://example.com and check if there is a heading"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} +{"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"text":"I'll help you with that."},{"functionCall":{"name":"browser","args":{"task":"Open https://example.com and check if there is a heading"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"new_page","args":{"url":"https://example.com"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"take_snapshot","args":{}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} {"method":"generateContentStream","response":[{"candidates":[{"content":{"parts":[{"functionCall":{"name":"complete_task","args":{"success":true,"summary":"SUCCESS_POLICY_TEST_COMPLETED"}}}],"role":"model"},"finishReason":"STOP","index":0}],"usageMetadata":{"promptTokenCount":100,"candidatesTokenCount":50,"totalTokenCount":150}}]} diff --git a/integration-tests/browser-policy.test.ts b/integration-tests/browser-policy.test.ts index 4fbfc5db01..de45856dd1 100644 --- a/integration-tests/browser-policy.test.ts +++ b/integration-tests/browser-policy.test.ts @@ -72,7 +72,7 @@ describe.skipIf(!chromeAvailable)('browser-policy', () => { settings: { agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -111,8 +111,8 @@ describe.skipIf(!chromeAvailable)('browser-policy', () => { policyFile, ` [[rule]] -name = "Force confirm browser_agent" -toolName = "browser_agent" +name = "Force confirm browser" +toolName = "browser" decision = "ask_user" priority = 200 `, @@ -145,7 +145,7 @@ priority = 200 await run.sendKeys('\r'); // Handle confirmations. - // 1. Initial browser_agent delegation (likely only 3 options, so use option 1: Allow once) + // 1. Initial browser delegation (likely only 3 options, so use option 1: Allow once) await poll( () => stripAnsi(run.output).toLowerCase().includes('action required'), 60000, @@ -194,7 +194,7 @@ priority = 200 const output = stripAnsi(run.output).toLowerCase(); - expect(output).toContain('browser_agent'); + expect(output).toContain('browser'); // The test validates that "Allow all server tools" skips subsequent // tool confirmations — the browser agent may still fail due to // Chrome/MCP issues in CI, which is acceptable for this policy test. @@ -209,12 +209,15 @@ priority = 200 rig.setup('browser-session-warning', { fakeResponsesPath: join(__dirname, 'browser-agent.cleanup.responses'), settings: { + model: { + name: 'gemini-2.5-pro', + }, general: { enableAutoUpdateNotification: false, }, agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, diff --git a/packages/core/src/agents/browser/browserAgentDefinition.ts b/packages/core/src/agents/browser/browserAgentDefinition.ts index f7bf3258ec..f3466340ef 100644 --- a/packages/core/src/agents/browser/browserAgentDefinition.ts +++ b/packages/core/src/agents/browser/browserAgentDefinition.ts @@ -24,7 +24,7 @@ import { } from '../../config/models.js'; /** Canonical agent name — used for routing and configuration lookup. */ -export const BROWSER_AGENT_NAME = 'browser_agent'; +export const BROWSER_AGENT_NAME = 'browser'; /** * Output schema for browser agent results. diff --git a/packages/core/src/agents/browser/browserAgentFactory.test.ts b/packages/core/src/agents/browser/browserAgentFactory.test.ts index 79e38c5361..66c8995f3a 100644 --- a/packages/core/src/agents/browser/browserAgentFactory.test.ts +++ b/packages/core/src/agents/browser/browserAgentFactory.test.ts @@ -96,7 +96,7 @@ describe('browserAgentFactory', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -133,7 +133,7 @@ describe('browserAgentFactory', () => { const headlessConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -205,7 +205,7 @@ describe('browserAgentFactory', () => { const configWithVision = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -230,7 +230,7 @@ describe('browserAgentFactory', () => { const configWithVision = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -369,7 +369,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_fill', + toolName: 'mcp_browser_fill', decision: PolicyDecision.ASK_USER, priority: 999, }), @@ -377,7 +377,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_upload_file', + toolName: 'mcp_browser_upload_file', decision: PolicyDecision.ASK_USER, priority: 999, }), @@ -385,7 +385,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_evaluate_script', + toolName: 'mcp_browser_evaluate_script', decision: PolicyDecision.ASK_USER, priority: 999, }), @@ -397,13 +397,13 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_fill', + toolName: 'mcp_browser_fill', }), ); expect(mockPolicyEngine.addRule).not.toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_upload_file', + toolName: 'mcp_browser_upload_file', }), ); }); @@ -429,7 +429,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_take_snapshot', + toolName: 'mcp_browser_take_snapshot', decision: PolicyDecision.ALLOW, priority: PRIORITY_SUBAGENT_TOOL, }), @@ -437,7 +437,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_take_screenshot', + toolName: 'mcp_browser_take_screenshot', decision: PolicyDecision.ALLOW, priority: PRIORITY_SUBAGENT_TOOL, }), @@ -445,7 +445,7 @@ describe('browserAgentFactory', () => { expect(mockPolicyEngine.addRule).toHaveBeenCalledWith( expect.objectContaining({ - toolName: 'mcp_browser_agent_list_pages', + toolName: 'mcp_browser_list_pages', decision: PolicyDecision.ALLOW, priority: PRIORITY_SUBAGENT_TOOL, }), diff --git a/packages/core/src/agents/browser/browserAgentInvocation.test.ts b/packages/core/src/agents/browser/browserAgentInvocation.test.ts index d8dbc69b43..5c08a01226 100644 --- a/packages/core/src/agents/browser/browserAgentInvocation.test.ts +++ b/packages/core/src/agents/browser/browserAgentInvocation.test.ts @@ -59,7 +59,7 @@ describe('BrowserAgentInvocation', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -96,14 +96,14 @@ describe('BrowserAgentInvocation', () => { expect(invocation.params).toEqual(mockParams); }); - it('should use browser_agent as default tool name', () => { + it('should use browser as default tool name', () => { const invocation = new BrowserAgentInvocation( mockConfig, mockParams, mockMessageBus, ); - expect(invocation['_toolName']).toBe('browser_agent'); + expect(invocation['_toolName']).toBe('browser'); }); it('should use custom tool name if provided', () => { @@ -172,7 +172,7 @@ describe('BrowserAgentInvocation', () => { beforeEach(() => { vi.mocked(createBrowserAgentDefinition).mockResolvedValue({ definition: { - name: 'browser_agent', + name: 'browser', description: 'mock definition', kind: 'local', inputConfig: {} as never, @@ -331,7 +331,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'THOUGHT_CHUNK', data: { text: 'Navigating to the page...' }, }); @@ -374,13 +374,13 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'THOUGHT_CHUNK', data: { text: 'I am thinking.' }, }); fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'THOUGHT_CHUNK', data: { text: 'Now I will act.' }, }); @@ -420,7 +420,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_START', data: { name: 'navigate_browser', @@ -431,7 +431,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_END', data: { name: 'navigate_browser', id: 'call-1' }, }); @@ -471,7 +471,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_START', data: { name: 'fill_form', @@ -515,14 +515,14 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_START', data: { name: 'click_element', callId: 'call-3', args: {} }, }); fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'ERROR', data: { error: 'Element not found', callId: 'call-3' }, }); @@ -560,7 +560,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'ERROR', data: { error: 'Auth failed: api_key=sk-secret-abc1234567890' }, }); @@ -600,7 +600,7 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'ERROR', data: { error: @@ -643,14 +643,14 @@ describe('BrowserAgentInvocation', () => { fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_START', data: { name: 'tool_a', callId: 'c1', args: {} }, }); fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'TOOL_CALL_START', data: { name: 'tool_b', callId: 'c2', args: {} }, }); @@ -658,7 +658,7 @@ describe('BrowserAgentInvocation', () => { // ERROR with no callId should mark ALL running tools as error fireActivity({ isSubagentActivityEvent: true, - agentName: 'browser_agent', + agentName: 'browser', type: 'ERROR', data: { error: 'Agent crashed' }, }); @@ -699,7 +699,7 @@ describe('BrowserAgentInvocation', () => { vi.mocked(createBrowserAgentDefinition).mockResolvedValue({ definition: { - name: 'browser_agent', + name: 'browser', description: 'mock definition', kind: 'local', inputConfig: {} as never, diff --git a/packages/core/src/agents/browser/browserAgentInvocation.ts b/packages/core/src/agents/browser/browserAgentInvocation.ts index 17912e5354..c53b57dd44 100644 --- a/packages/core/src/agents/browser/browserAgentInvocation.ts +++ b/packages/core/src/agents/browser/browserAgentInvocation.ts @@ -66,7 +66,7 @@ export class BrowserAgentInvocation extends BaseToolInvocation< _toolName?: string, _toolDisplayName?: string, ) { - const resolvedName = _toolName ?? 'browser_agent'; + const resolvedName = _toolName ?? 'browser'; // Note: BrowserAgentDefinition is a factory function, so we use hardcoded names super( params, diff --git a/packages/core/src/agents/browser/browserManager.test.ts b/packages/core/src/agents/browser/browserManager.test.ts index 6814a279f3..4df985db20 100644 --- a/packages/core/src/agents/browser/browserManager.test.ts +++ b/packages/core/src/agents/browser/browserManager.test.ts @@ -97,7 +97,7 @@ describe('BrowserManager', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -419,7 +419,7 @@ describe('BrowserManager', () => { const headlessConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -444,7 +444,7 @@ describe('BrowserManager', () => { const profileConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -469,7 +469,7 @@ describe('BrowserManager', () => { const isolatedConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -492,7 +492,7 @@ describe('BrowserManager', () => { const existingConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -531,7 +531,7 @@ describe('BrowserManager', () => { const existingConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -628,7 +628,7 @@ describe('BrowserManager', () => { const privacyDisabledConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -730,7 +730,7 @@ describe('BrowserManager', () => { it('should return different instances for different session modes', () => { const isolatedConfig = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { sessionMode: 'isolated' }, }, }); @@ -744,13 +744,13 @@ describe('BrowserManager', () => { it('should return different instances for different profile paths', () => { const config1 = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { profilePath: '/path/a' }, }, }); const config2 = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { profilePath: '/path/b' }, }, }); @@ -769,7 +769,7 @@ describe('BrowserManager', () => { const isolatedConfig = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { sessionMode: 'isolated' }, }, }); @@ -879,7 +879,7 @@ describe('BrowserManager', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -901,7 +901,7 @@ describe('BrowserManager', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -923,7 +923,7 @@ describe('BrowserManager', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -969,7 +969,7 @@ describe('BrowserManager', () => { it('should NOT re-inject overlay when headless is true', async () => { const headlessConfig = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { headless: true }, }, }); @@ -1001,7 +1001,7 @@ describe('BrowserManager', () => { mockConfig = makeFakeConfig({ agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, @@ -1098,7 +1098,7 @@ describe('BrowserManager', () => { vi.stubEnv('SANDBOX', 'sandbox-exec'); const existingConfig = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { sessionMode: 'existing' }, }, }); @@ -1127,7 +1127,7 @@ describe('BrowserManager', () => { .mockImplementation(() => {}); const existingConfig = makeFakeConfig({ agents: { - overrides: { browser_agent: { enabled: true } }, + overrides: { browser: { enabled: true } }, browser: { sessionMode: 'existing' }, }, }); diff --git a/packages/core/src/agents/browser/mcpToolWrapperConfirmation.test.ts b/packages/core/src/agents/browser/mcpToolWrapperConfirmation.test.ts index 2dcbc21538..e01a5ba408 100644 --- a/packages/core/src/agents/browser/mcpToolWrapperConfirmation.test.ts +++ b/packages/core/src/agents/browser/mcpToolWrapperConfirmation.test.ts @@ -61,7 +61,7 @@ describe('mcpToolWrapper Confirmation', () => { expect(details).toEqual( expect.objectContaining({ type: 'mcp', - serverName: 'browser_agent', + serverName: 'browser', toolName: 'test_tool', }), ); @@ -76,7 +76,7 @@ describe('mcpToolWrapper Confirmation', () => { expect(mockMessageBus.publish).toHaveBeenCalledWith( expect.objectContaining({ type: MessageBusType.UPDATE_POLICY, - mcpName: 'browser_agent', + mcpName: 'browser', persist: false, }), ); @@ -94,7 +94,7 @@ describe('mcpToolWrapper Confirmation', () => { ); expect(options).toEqual({ - mcpName: 'browser_agent', + mcpName: 'browser', }); }); }); diff --git a/packages/core/src/agents/registry.test.ts b/packages/core/src/agents/registry.test.ts index 55517a20d5..17eb585785 100644 --- a/packages/core/src/agents/registry.test.ts +++ b/packages/core/src/agents/registry.test.ts @@ -1549,7 +1549,7 @@ describe('AgentRegistry', () => { const config = makeMockedConfig({ agents: { overrides: { - browser_agent: { enabled: true }, + browser: { enabled: true }, }, browser: { sessionMode: 'persistent', @@ -1559,7 +1559,7 @@ describe('AgentRegistry', () => { const registry = new TestableAgentRegistry(config); await registry.initialize(); - expect(registry.getDefinition('browser_agent')).toBeUndefined(); + expect(registry.getDefinition('browser')).toBeUndefined(); expect(feedbackSpy).toHaveBeenCalledWith( 'info', expect.stringContaining('Browser agent disabled in container sandbox'), @@ -1572,7 +1572,7 @@ describe('AgentRegistry', () => { const config = makeMockedConfig({ agents: { overrides: { - browser_agent: { enabled: true }, + browser: { enabled: true }, }, browser: { sessionMode: 'existing', @@ -1582,7 +1582,7 @@ describe('AgentRegistry', () => { const registry = new TestableAgentRegistry(config); await registry.initialize(); - expect(registry.getDefinition('browser_agent')).toBeDefined(); + expect(registry.getDefinition('browser')).toBeDefined(); }); it('should register browser agent normally in seatbelt sandbox', async () => { @@ -1591,14 +1591,14 @@ describe('AgentRegistry', () => { const config = makeMockedConfig({ agents: { overrides: { - browser_agent: { enabled: true }, + browser: { enabled: true }, }, }, }); const registry = new TestableAgentRegistry(config); await registry.initialize(); - expect(registry.getDefinition('browser_agent')).toBeDefined(); + expect(registry.getDefinition('browser')).toBeDefined(); }); it('should register browser agent normally when not in sandbox', async () => { @@ -1607,14 +1607,14 @@ describe('AgentRegistry', () => { const config = makeMockedConfig({ agents: { overrides: { - browser_agent: { enabled: true }, + browser: { enabled: true }, }, }, }); const registry = new TestableAgentRegistry(config); await registry.initialize(); - expect(registry.getDefinition('browser_agent')).toBeDefined(); + expect(registry.getDefinition('browser')).toBeDefined(); }); }); }); diff --git a/packages/core/src/config/config.test.ts b/packages/core/src/config/config.test.ts index d79f218744..aa60cdcfd4 100644 --- a/packages/core/src/config/config.test.ts +++ b/packages/core/src/config/config.test.ts @@ -1505,7 +1505,7 @@ describe('Server Config (config.ts)', () => { ...baseParams, agents: { overrides: { - browser_agent: { + browser: { enabled: true, modelConfig: { model: 'custom-model' }, }, @@ -1552,7 +1552,7 @@ describe('Server Config (config.ts)', () => { ...baseParams, agents: { overrides: { - browser_agent: { + browser: { enabled: true, }, }, diff --git a/packages/core/src/config/config.ts b/packages/core/src/config/config.ts index f01b4bbd93..b1966620c9 100644 --- a/packages/core/src/config/config.ts +++ b/packages/core/src/config/config.ts @@ -3385,7 +3385,7 @@ export class Config implements McpContext, AgentLoopContext { model?: string; customConfig: BrowserAgentCustomConfig; } { - const override = this.getAgentOverride('browser_agent'); + const override = this.getAgentOverride('browser'); const customConfig = this.getAgentsSettings()?.browser ?? {}; return { enabled: override?.enabled ?? false, @@ -3591,9 +3591,15 @@ export class Config implements McpContext, AgentLoopContext { !this.isAgentsEnabled() || agentsOverrides[definition.name]?.enabled === false ) { + process.stderr.write( + `[Config] Skipping disabled subagent tool: ${definition.name}\n`, + ); continue; } + process.stderr.write( + `[Config] Registering subagent tool: ${definition.name}\n`, + ); const tool = new SubagentTool(definition, this, this.messageBus); registry.registerTool(tool); } catch (e: unknown) {