feat: auto-start sandbox browser
This commit is contained in:
@@ -55,6 +55,8 @@ export type SandboxBrowserConfig = {
|
||||
noVncPort: number;
|
||||
headless: boolean;
|
||||
enableNoVnc: boolean;
|
||||
autoStart: boolean;
|
||||
autoStartTimeoutMs: number;
|
||||
};
|
||||
|
||||
export type SandboxDockerConfig = {
|
||||
@@ -159,6 +161,7 @@ const DEFAULT_SANDBOX_BROWSER_PREFIX = "clawdbot-sbx-browser-";
|
||||
const DEFAULT_SANDBOX_BROWSER_CDP_PORT = 9222;
|
||||
const DEFAULT_SANDBOX_BROWSER_VNC_PORT = 5900;
|
||||
const DEFAULT_SANDBOX_BROWSER_NOVNC_PORT = 6080;
|
||||
const DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS = 12_000;
|
||||
const SANDBOX_AGENT_WORKSPACE_MOUNT = "/agent";
|
||||
|
||||
const SANDBOX_STATE_DIR = path.join(STATE_DIR_CLAWDBOT, "sandbox");
|
||||
@@ -307,9 +310,38 @@ export function resolveSandboxBrowserConfig(params: {
|
||||
headless: agentBrowser?.headless ?? globalBrowser?.headless ?? false,
|
||||
enableNoVnc:
|
||||
agentBrowser?.enableNoVnc ?? globalBrowser?.enableNoVnc ?? true,
|
||||
autoStart: agentBrowser?.autoStart ?? globalBrowser?.autoStart ?? true,
|
||||
autoStartTimeoutMs:
|
||||
agentBrowser?.autoStartTimeoutMs ??
|
||||
globalBrowser?.autoStartTimeoutMs ??
|
||||
DEFAULT_SANDBOX_BROWSER_AUTOSTART_TIMEOUT_MS,
|
||||
};
|
||||
}
|
||||
|
||||
async function waitForSandboxCdp(params: {
|
||||
cdpPort: number;
|
||||
timeoutMs: number;
|
||||
}): Promise<boolean> {
|
||||
const deadline = Date.now() + Math.max(0, params.timeoutMs);
|
||||
const url = `http://127.0.0.1:${params.cdpPort}/json/version`;
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
const ctrl = new AbortController();
|
||||
const t = setTimeout(() => ctrl.abort(), 1000);
|
||||
try {
|
||||
const res = await fetch(url, { signal: ctrl.signal });
|
||||
if (res.ok) return true;
|
||||
} finally {
|
||||
clearTimeout(t);
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, 150));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function resolveSandboxPruneConfig(params: {
|
||||
scope: SandboxScope;
|
||||
globalPrune?: Partial<SandboxPruneConfig>;
|
||||
@@ -921,12 +953,31 @@ async function ensureSandboxBrowser(params: {
|
||||
if (shouldReuse && existing) {
|
||||
bridge = existing.bridge;
|
||||
} else {
|
||||
const onEnsureAttachTarget = params.cfg.browser.autoStart
|
||||
? async () => {
|
||||
const state = await dockerContainerState(containerName);
|
||||
if (state.exists && !state.running) {
|
||||
await execDocker(["start", containerName]);
|
||||
}
|
||||
const ok = await waitForSandboxCdp({
|
||||
cdpPort: mappedCdp,
|
||||
timeoutMs: params.cfg.browser.autoStartTimeoutMs,
|
||||
});
|
||||
if (!ok) {
|
||||
throw new Error(
|
||||
`Sandbox browser CDP did not become reachable on 127.0.0.1:${mappedCdp} within ${params.cfg.browser.autoStartTimeoutMs}ms.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
: undefined;
|
||||
|
||||
bridge = await startBrowserBridgeServer({
|
||||
resolved: buildSandboxBrowserResolvedConfig({
|
||||
controlPort: 0,
|
||||
cdpPort: mappedCdp,
|
||||
headless: params.cfg.browser.headless,
|
||||
}),
|
||||
onEnsureAttachTarget,
|
||||
});
|
||||
}
|
||||
if (!shouldReuse) {
|
||||
|
||||
Reference in New Issue
Block a user