feat: add computer control and managed browser

This commit is contained in:
lofyer
2026-08-05 12:55:24 +08:00
parent 2f549387a6
commit 38ac2206f2
92 changed files with 21028 additions and 766 deletions
+64 -1
View File
@@ -1,6 +1,25 @@
import { describe, expect, it } from 'vitest'
import { describe, expect, it, vi } from 'vitest'
import type { ResolvedRuntimeSettings } from '../runtime-settings-store'
import type { BrowserToolService } from '../browser/browser-model-tools'
import { createAgentRuntime } from './create-runtime'
import { AgentRuntimeController } from './runtime-controller'
function createBrowserService(): BrowserToolService & {
dispose: ReturnType<typeof vi.fn>
} {
return {
getOrigin: vi.fn(() => undefined),
navigate: vi.fn(),
snapshot: vi.fn(),
click: vi.fn(),
type: vi.fn(),
select: vi.fn(),
back: vi.fn(),
screenshot: vi.fn(),
releaseConversation: vi.fn(async () => undefined),
dispose: vi.fn(async () => undefined)
}
}
function settings(
overrides: Partial<ResolvedRuntimeSettings> = {}
@@ -41,6 +60,50 @@ describe('createAgentRuntime model compatibility', () => {
await runtime.dispose()
})
it('shares injected browser service without runtime-owned disposal', async () => {
const browserService = createBrowserService()
const first = createAgentRuntime(process.cwd(), settings(), {
browserService
})
const second = createAgentRuntime(process.cwd(), settings(), {
browserService
})
const controller = new AgentRuntimeController(first)
await controller.releaseConversation('conversation-one')
await controller.replace(second)
await controller.releaseConversation('conversation-two')
await controller.dispose()
expect(browserService.releaseConversation).toHaveBeenNthCalledWith(
1,
'conversation-one'
)
expect(browserService.releaseConversation).toHaveBeenNthCalledWith(
2,
'conversation-two'
)
expect(browserService.dispose).not.toHaveBeenCalled()
})
it('does not expose the browser service to OpenCode runtimes', async () => {
const browserService = createBrowserService()
const runtime = createAgentRuntime(
process.cwd(),
settings({
provider: 'opencode',
opencodeBaseUrl: 'http://127.0.0.1:4096'
}),
{ browserService }
)
await runtime.releaseConversation?.('opencode-conversation')
await runtime.dispose()
expect(browserService.releaseConversation).not.toHaveBeenCalled()
expect(browserService.dispose).not.toHaveBeenCalled()
})
it('keeps OpenCode independent profiles Anthropic API-key only', () => {
expect(() =>
createAgentRuntime(