Skip to content

Commit 4645ba3

Browse files
GiniGini
authored andcommitted
fix: wait for sandbox agent bootstrap
1 parent c8ad5ea commit 4645ba3

3 files changed

Lines changed: 13 additions & 2 deletions

File tree

server/onecomputer-client.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ export type OneComputerSandbox = {
33
name?: string
44
state?: string
55
provider?: string
6+
bootstrapped?: boolean
7+
desktopReady?: boolean
68
}
79

810
export type OneComputerClientOptions = {

server/onecomputer-sandbox-runner.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ afterEach(async () => {
1212

1313
describe('OneComputerSandboxRuntimeAdapter', () => {
1414
it('only exposes browser MCP controls when the governed runtime explicitly enables them', async () => {
15-
const { GOVERNED_BROWSER_TOOLS, browserEvidenceFor, governedClaudeTools, isGovernedBrowserTool } = await import('./onecomputer-sandbox-runner.js')
15+
const { GOVERNED_BROWSER_TOOLS, browserEvidenceFor, governedClaudeTools, isGovernedBrowserTool, isSandboxRuntimeReady } = await import('./onecomputer-sandbox-runner.js')
1616
expect(governedClaudeTools(false)).toEqual(['Read', 'Write', 'Edit', 'Glob', 'Grep'])
1717
expect(governedClaudeTools(true)).toEqual(expect.arrayContaining([...GOVERNED_BROWSER_TOOLS]))
1818
expect(GOVERNED_BROWSER_TOOLS).toEqual(expect.arrayContaining(['mcp__playwright__browser_select_option', 'mcp__playwright__browser_wait_for']))
@@ -21,6 +21,9 @@ describe('OneComputerSandboxRuntimeAdapter', () => {
2121
expect(isGovernedBrowserTool('mcp__playwright__browser_evaluate')).toBe(false)
2222
expect(browserEvidenceFor('mcp__playwright__browser_navigate', { url: 'https://user:password@example.com/path?token=hidden#fragment' })).toEqual({ tool: 'browser_navigate', url: 'https://example.com/path' })
2323
expect(browserEvidenceFor('mcp__playwright__browser_navigate', { url: 'file:///tmp/onevibe/task/index.html' })).toEqual({ tool: 'browser_navigate', url: 'file://sandbox-local/index.html' })
24+
expect(isSandboxRuntimeReady({ state: 'started', bootstrapped: false })).toBe(false)
25+
expect(isSandboxRuntimeReady({ state: 'started', bootstrapped: true })).toBe(true)
26+
expect(isSandboxRuntimeReady({ state: 'started' })).toBe(true)
2427
})
2528

2629
it('builds generated projects only in the sandbox and disables install lifecycle scripts', async () => {

server/onecomputer-sandbox-runner.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ export const governedClaudeTools = (browserAutomation: boolean) => [
9090
]
9191

9292
export const isGovernedBrowserTool = (name: string) => (GOVERNED_BROWSER_TOOLS as readonly string[]).includes(name)
93+
export const isSandboxRuntimeReady = (sandbox: { state?: string; bootstrapped?: boolean }) => sandbox.state === 'started' && sandbox.bootstrapped !== false
9394

9495
export const sandboxBuildValidationCommand = (workspace: string) => [
9596
'set +e',
@@ -212,12 +213,17 @@ export class OneComputerSandboxRuntimeAdapter implements RuntimeAdapter {
212213
}
213214
let live = sandbox
214215
const deadline = Date.now() + 4 * 60_000
215-
while (live.state !== 'started') {
216+
while (!isSandboxRuntimeReady(live)) {
216217
if (live.state === 'error' || Date.now() >= deadline) throw new Error(`ONEComputer sandbox failed to start (state=${live.state ?? 'unknown'})`)
217218
await wait(this.options.pollMilliseconds ?? 2_000, signal)
218219
live = await this.client.getSandbox(sandbox.id, signal)
219220
await recordSandboxState(live)
220221
}
222+
await store.appendEvent(task.id, {
223+
type: 'activity_delta', lane: 'control', label: 'ONEComputer agent runtime bootstrapped',
224+
content: 'The provider reported the retained sandbox ready for Claude execution.',
225+
payload: { sandboxId: sandbox.id, state: live.state, bootstrapped: live.bootstrapped ?? 'legacy_unspecified', desktopReady: live.desktopReady },
226+
})
221227
await store.updateTask(task.id, {
222228
securityContext: {
223229
mode: 'onecomputer', sandboxId: sandbox.id, provider: sandbox.provider,

0 commit comments

Comments
 (0)