import { getActiveBackend } from "../backend-registry/active-store"; import type { Backend } from "../backend-registry/types"; import { callCloudProxy } from "./proxy"; import type { V1SandboxInfo } from "./sandbox-service.types"; function getActiveCloudBackend(): Backend { const active = getActiveBackend().backend; if (active.kind !== "cloud") { throw new Error("Cloud sandboxes call requires a cloud backend."); } return active; } /** * Batch-fetch cloud sandboxes by id. Mirrors OpenHands' * `SandboxService.batchGetSandboxes` by calling * `GET /api/v1/sandboxes?id=...` on the cloud backend, returning each * `SandboxInfo` (or null if not found). * * The returned `SandboxInfo.exposed_urls` carry the cloud-computed, * publicly-reachable URLs for the sandbox's services (VSCODE, * AGENT_SERVER, WORKER_*) — the GUI reads them directly instead of * asking the runtime for `/api/vscode/url`, which only knows its * internal localhost address. */ export async function batchGetCloudSandboxes( ids: string[], ): Promise<(V1SandboxInfo | null)[]> { if (ids.length === 0) return []; const backend = getActiveCloudBackend(); const params = new URLSearchParams(); for (const id of ids) params.append("id", id); const data = await callCloudProxy<(V1SandboxInfo | null)[]>({ backend, method: "GET", path: `/api/v1/sandboxes?${params.toString()}`, }); return data ?? []; }