fix(agent-browser): restore bounded presentation lifecycle
This commit is contained in:
@@ -7,6 +7,7 @@ import path from 'node:path';
|
||||
import { promisify } from 'node:util';
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||
import type { AgentBrowserModule } from '../../electron/agent-browser';
|
||||
import { AgentBrowserFault } from '../../electron/agent-browser/fault';
|
||||
import { CodingAttachmentStore } from '../../electron/coding-projects/attachment-store';
|
||||
import {
|
||||
ConversationChangeTracker,
|
||||
@@ -395,6 +396,99 @@ describe('PI-090 product tools', () => {
|
||||
}));
|
||||
});
|
||||
|
||||
it('presents an agent-opened browser before returning and releases diagnostics with the run', async () => {
|
||||
const root = await temporaryRoot('makelore-pi-browser-present-');
|
||||
const hidden = {
|
||||
browserId: 'browser-a', projectId: 'project-a', projectPath: root,
|
||||
state: 'attached' as const, generation: 3, url: 'http://127.0.0.1:4173/', title: 'App',
|
||||
visible: false, bounds: null, canGoBack: false, canGoForward: false, eventCursor: 0,
|
||||
};
|
||||
const visible = {
|
||||
...hidden,
|
||||
visible: true,
|
||||
bounds: { x: 10, y: 20, width: 800, height: 600 },
|
||||
};
|
||||
const order: string[] = [];
|
||||
const browser = {
|
||||
open: vi.fn(async () => {
|
||||
order.push('open');
|
||||
return hidden;
|
||||
}),
|
||||
waitForPresentation: vi.fn(async () => {
|
||||
order.push('wait');
|
||||
return visible;
|
||||
}),
|
||||
setDiagnostics: vi.fn(async () => visible),
|
||||
} as unknown as AgentBrowserModule;
|
||||
const requestAgentBrowserPresentation = vi.fn(() => {
|
||||
order.push('show');
|
||||
});
|
||||
const tools = new PiProductTools({
|
||||
browser,
|
||||
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
|
||||
bundledSkillsDir: path.resolve('resources/coding-skills'),
|
||||
requestAgentBrowserPresentation,
|
||||
});
|
||||
const result = await tools.execute('agent_browser', {
|
||||
conversationId: 'conversation-a', runId: 'run-a', resourceId: 'browser-a',
|
||||
projectId: 'project-a', projectPath: root, skillIds: [],
|
||||
}, { action: 'open', url: 'http://127.0.0.1:4173/' });
|
||||
|
||||
expect(order).toEqual(['open', 'show', 'wait']);
|
||||
expect(browser.open).toHaveBeenCalledWith(expect.objectContaining({
|
||||
diagnosticsOwner: 'agent:conversation-a:run-a',
|
||||
}));
|
||||
expect(browser.waitForPresentation).toHaveBeenCalledWith({
|
||||
projectPath: root,
|
||||
generation: 3,
|
||||
timeoutMs: 5_000,
|
||||
});
|
||||
expect(JSON.parse(result.content[0].text)).toMatchObject({ visible: true });
|
||||
|
||||
await tools.settleRun('conversation-a', 'run-a');
|
||||
expect(browser.setDiagnostics).toHaveBeenCalledWith({
|
||||
projectPath: root,
|
||||
enabled: false,
|
||||
owner: 'agent:conversation-a:run-a',
|
||||
});
|
||||
});
|
||||
|
||||
it('closes an agent-opened browser when presentation times out', async () => {
|
||||
const root = await temporaryRoot('makelore-pi-browser-timeout-');
|
||||
const hidden = {
|
||||
browserId: 'browser-a', projectId: 'project-a', projectPath: root,
|
||||
state: 'attached' as const, generation: 4, url: 'http://127.0.0.1:4173/', title: 'App',
|
||||
visible: false, bounds: null, canGoBack: false, canGoForward: false, eventCursor: 0,
|
||||
};
|
||||
const close = vi.fn(async () => ({ ...hidden, state: 'closed' as const }));
|
||||
const browser = {
|
||||
open: vi.fn(async () => hidden),
|
||||
waitForPresentation: vi.fn(async () => {
|
||||
throw new AgentBrowserFault(
|
||||
'VIEWPORT_NOT_READY',
|
||||
'开发浏览器显示区域没有及时准备好。',
|
||||
true,
|
||||
hidden.generation,
|
||||
);
|
||||
}),
|
||||
close,
|
||||
} as unknown as AgentBrowserModule;
|
||||
const tools = new PiProductTools({
|
||||
browser,
|
||||
attachments: new CodingAttachmentStore(path.join(root, 'attachments')),
|
||||
bundledSkillsDir: path.resolve('resources/coding-skills'),
|
||||
requestAgentBrowserPresentation: vi.fn(),
|
||||
});
|
||||
|
||||
await expect(tools.execute('agent_browser', {
|
||||
conversationId: 'conversation-a', runId: 'run-a', resourceId: 'browser-a',
|
||||
projectId: 'project-a', projectPath: root, skillIds: [],
|
||||
}, { action: 'open', url: 'http://127.0.0.1:4173/' })).rejects.toMatchObject({
|
||||
code: 'VIEWPORT_NOT_READY',
|
||||
});
|
||||
expect(close).toHaveBeenCalledWith(root);
|
||||
});
|
||||
|
||||
it('dispatches all Data Service tools only through the capability registry', async () => {
|
||||
const root = await temporaryRoot('makelore-pi-data-tools-');
|
||||
const invoke = vi.fn().mockImplementation(({ toolName, context }) => Promise.resolve({
|
||||
|
||||
Reference in New Issue
Block a user