fix(browser): preserve chat focus during agent browsing

This commit is contained in:
2026-09-27 15:23:23 +08:00
parent 220e89992b
commit a52e747a00
10 changed files with 323 additions and 16 deletions

View File

@@ -0,0 +1,72 @@
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<string, unknown>) {
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<string, unknown>) {
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);
}
}