rename 'browser_agent' to 'browser'

This commit is contained in:
Cynthia Long
2026-04-02 16:36:34 +00:00
parent d9d51ba15b
commit 3ba2de01cc
18 changed files with 133 additions and 100 deletions
+5 -5
View File
@@ -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",
@@ -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}}]}
@@ -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}}]}
@@ -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}}]}
@@ -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}}]}
@@ -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}}]}
+43 -19
View File
@@ -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',
},
+1 -1
View File
@@ -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}}]}
+9 -6
View File
@@ -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,
},
},
@@ -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.
@@ -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,
}),
@@ -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,
@@ -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,
@@ -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' },
},
});
@@ -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',
});
});
});
+8 -8
View File
@@ -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();
});
});
});
+2 -2
View File
@@ -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,
},
},
+7 -1
View File
@@ -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) {