import type { BrowserWindow } from 'electron'; import path from 'node:path'; import type { AgentBrowserBounds } from '../../../shared/agent-browser'; import { AgentBrowserModule } from '../../../electron/agent-browser/module'; import { ElectronAgentBrowserAdapter } from '../../../electron/agent-browser/electron-adapter'; import { CodingAttachmentStore } from '../../../electron/coding-projects/attachment-store'; import { PiAgentBrowserTool } from '../../../electron/coding-runtime/pi/extensions/agent-browser'; // Loaded in Electron Main by the E2E spec: use the production view, debugger and // Pi tool while the surrounding project/model APIs remain isolated fixtures. export class NativeAgentBrowserFixture { readonly browser: AgentBrowserModule; readonly tool: PiAgentBrowserTool; showRequests = 0; readonly context; constructor(window: BrowserWindow, projectPath: string, readonly url: string) { this.context = { projectId: 'project-pi-first-chat', projectPath, conversationId: 'conversation-pi-first-chat', runId: 'browser-e2e', }; this.browser = new AgentBrowserModule(new ElectronAgentBrowserAdapter(window)); this.tool = new PiAgentBrowserTool( this.browser, new CodingAttachmentStore(path.join(projectPath, 'attachments')), (snapshot) => { this.showRequests += 1; window.webContents.send('agent-browser:show', snapshot); }, (snapshot) => window.webContents.send('agent-browser:state', snapshot), ); } async execute(input: Record) { const result = await this.tool.execute(this.context, input); return { value: JSON.parse(result.content[0].text), showRequests: this.showRequests }; } async route(route: string, body?: Record) { const { projectId, projectPath } = this.context; if (route.startsWith('/api/agent-browser/state?')) { return { success: true, browser: await this.browser.getSnapshot(projectPath) }; } if (route === '/api/agent-browser/ensure-work') { const snapshot = await this.browser.getSnapshot(projectPath); return { success: true, status: 'ready', browser: snapshot.state === 'closed' ? await this.browser.open({ projectId, projectPath, url: this.url, visible: false }) : snapshot, }; } if (route === '/api/agent-browser/present') { return { success: true, browser: await this.browser.present({ projectPath, visible: body?.visible === true, bounds: body?.bounds as AgentBrowserBounds | undefined, }), }; } if (route === '/api/agent-browser/close') { return { success: true, browser: await this.browser.close(projectPath) }; } throw new Error('Unexpected native browser fixture route: ' + route); } async dispose() { await this.tool.releaseRun(this.context.conversationId, this.context.runId); await this.browser.close(this.context.projectPath); } }