@finalai/final-agent-provider 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/modules/sandboxes/computer.mjs +17 -0
- package/dist/modules/sandboxes/computer.mjs.map +2 -2
- package/dist/modules/sandboxes/computers-api.d.mts +5 -1
- package/dist/modules/sandboxes/computers-api.mjs +19 -1
- package/dist/modules/sandboxes/computers-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device.mjs +4 -12
- package/dist/modules/sandboxes/device.mjs.map +2 -2
- package/dist/modules/sandboxes/mcp-pipe.d.mts +1 -0
- package/dist/modules/sandboxes/mcp-pipe.mjs +18 -3
- package/dist/modules/sandboxes/mcp-pipe.mjs.map +2 -2
- package/dist/modules/sandboxes/testing/fake-backends.d.mts +1 -0
- package/dist/modules/sandboxes/testing/fake-backends.mjs +2 -0
- package/dist/modules/sandboxes/testing/fake-backends.mjs.map +2 -2
- package/dist/modules/sandboxes/tool-catalog.d.mts +2 -0
- package/dist/modules/sandboxes/tool-catalog.mjs +14 -0
- package/dist/modules/sandboxes/tool-catalog.mjs.map +7 -0
- package/package.json +4 -4
|
@@ -46,6 +46,7 @@ import {
|
|
|
46
46
|
DEFAULT_COMPUTER_IMAGE
|
|
47
47
|
} from "./environment.mjs";
|
|
48
48
|
import { createTransportSession, readOnlySession } from "./session.mjs";
|
|
49
|
+
import { toolDescriptorsOf } from "./tool-catalog.mjs";
|
|
49
50
|
import { COMPUTER_PROVIDER as COMPUTER_PROVIDER2 } from "./environment.mjs";
|
|
50
51
|
const WORKSPACE_ROOT = "/workspaces";
|
|
51
52
|
const DEFAULT_IDLE_TIMEOUT_SECONDS = 15 * 60;
|
|
@@ -606,6 +607,22 @@ ${step.run}`,
|
|
|
606
607
|
[Capability.Shell]: ShellAccess.Execute,
|
|
607
608
|
[Capability.ComputerUse]: ScreenAccess.Control
|
|
608
609
|
}),
|
|
610
|
+
// The computer-use tools of this environment's image, from the Computers
|
|
611
|
+
// API without a computer, so a sandbox lists them before its first attach.
|
|
612
|
+
// Unknown when the API cannot tell: the first attach learns them.
|
|
613
|
+
mcpCatalog: async (ctx) => {
|
|
614
|
+
let tools;
|
|
615
|
+
try {
|
|
616
|
+
tools = await clientFor(ctx).computerUseCatalog({ image });
|
|
617
|
+
} catch (error) {
|
|
618
|
+
log("computer_use_catalog_unavailable", {
|
|
619
|
+
image,
|
|
620
|
+
error: error instanceof Error ? error.message : String(error)
|
|
621
|
+
});
|
|
622
|
+
return null;
|
|
623
|
+
}
|
|
624
|
+
return tools == null ? null : { computerUse: toolDescriptorsOf(tools), localMcp: null };
|
|
625
|
+
},
|
|
609
626
|
processes: async (ctx, rawState, request) => {
|
|
610
627
|
const state = stateOf(rawState);
|
|
611
628
|
if (state.computerId == null) throw new Error("this computer has not started yet");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/computer.ts"],
|
|
4
|
-
"sourcesContent": ["import { Capability, FilesAccess, ScreenAccess, ShellAccess } from '@finalai/agent-protocol';\nimport { NetworkPolicy, type JsonValue } from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n materializeSandboxSeeds,\n platformProcessEnvironment,\n PortProtocol,\n reportPlatformNetworkPolicy,\n SandboxCapability,\n sandboxSeedArtifact,\n sandboxSeedArtifactSchema,\n sandboxSeedFiles,\n sandboxSeedFilesForAttach,\n sandboxSeedIdentity,\n withPlatformEgressHosts,\n writePlatformFiles,\n type NetworkPolicyIface,\n type NetworkSandboxSessionIface,\n type SandboxEnvironmentImplementationIface,\n type SandboxPrepareContextIface,\n type SandboxProviderContextIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxResourceContextIface,\n type SandboxSetupIface,\n} from '@finalai/agent-provider/sandbox';\nimport {\n ComputerBaseState,\n ComputerCommandMode,\n ComputerEgressPolicy,\n ComputerIdlePolicy,\n ComputerImageState,\n ComputerState,\n type ComputerBaseIface,\n type ComputerImageIface,\n type ComputerInfoIface,\n} from '@finalai/computers';\nimport * as z from 'zod';\nimport {\n HOME_BASELINE_MISSING_EXIT_CODE,\n HOME_BASELINE_ROOT,\n homeBaselineScript,\n homeContentScript,\n} from \"./build-scripts.mjs\";\nimport { canonicalJson, sleep as defaultSleep, sha256Hex } from \"./bytes.mjs\";\nimport { computerEditor } from \"./computer-editor.mjs\";\nimport { readComputerSnapshot } from \"./computer-snapshots.mjs\";\nimport {\n createComputersApiClient,\n isComputersApiError,\n isComputersApiStatus,\n type ComputersApiClientIface,\n type ComputersApiConfigIface,\n type ComputersApiCredentialsIface,\n type CreateComputerBodyIface,\n} from \"./computers-api.mjs\";\nimport { createComputerUseEndpoint } from \"./computers-api-mcp.mjs\";\nimport { createComputersApiTransport } from \"./computers-api-transport.mjs\";\nimport {\n COMPUTER_PROVIDER,\n computerEnvironmentSchema,\n DEFAULT_COMPUTER_IMAGE,\n type ComputerBuildIface,\n type ComputerEnvironmentIface,\n} from \"./environment.mjs\";\nimport { createTransportSession, readOnlySession } from \"./session.mjs\";\nimport type { SandboxTransportIface } from \"./transport.mjs\";\n\nexport type { ComputersApiConfigIface } from \"./computers-api.mjs\";\nexport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nexport { COMPUTER_PROVIDER } from \"./environment.mjs\";\n\n// The `computer` sandbox: a Final computer from the public Computers API, with\n// lifecycle, files and processes all through that API, exactly as a\n// third-party provider drives its vendor. Like every provider, the host runs\n// this handle and serves the handle RPC and MCP projection from it.\n//\n// A sandbox is one computer, named after the sandbox's id: `create` records\n// it and the first `attach` makes it, so creating a sandbox boots nothing. An\n// environment with build or verify steps is built once on a builder computer\n// and captured as a base (POST /v1/computers/:id/capture) that its computers\n// are created from. The sandbox setup's network policy is a create option, as\n// for any API customer; its repositories, steps and services are applied by\n// the platform through the handle.\n\nexport const WORKSPACE_ROOT = '/workspaces';\n\nconst DEFAULT_IDLE_TIMEOUT_SECONDS = 15 * 60;\nconst IDLE_TIMEOUT_MARGIN_SECONDS = 5 * 60;\n\nexport interface ComputerSandboxLogIface {\n (message: string, fields?: Record<string, string | number | boolean | null>): void;\n}\n\nexport interface ComputerSandboxProviderConfigIface {\n // The Computers API origin. Requests authenticate with the provider's\n // platform identity for it (ctx.identity), which the registration must be\n // granted.\n computersApiUrl: string;\n // Transport options.\n computersApi?: ComputersApiConfigIface;\n // A registry credential (`creg_...`) stored for private image references.\n registryCredentialId?: string;\n // Image for an environment that names none.\n defaultImage?: string;\n // Defaults for what an environment leaves out.\n regionSlug?: string;\n machine?: { vcpu?: number; memoryMb?: number; diskGb?: number };\n // How long attach waits for a registered image version to finish building.\n imageWaitMs?: number;\n imagePollMs?: number;\n // How long `prepare` waits for a base capture to publish.\n buildWaitMs?: number;\n buildPollMs?: number;\n // How long attach and a build wait for a computer to run before touching it\n // (default 5 min); polled from runningPollMs (default 250 ms), doubling to 5 s.\n runningWaitMs?: number;\n runningPollMs?: number;\n log?: ComputerSandboxLogIface;\n randomUuid?: () => string;\n now?: () => number;\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n}\n\n// An `image` base: `imageVersionId` is the registered version (`cimv_...`) of an\n// image reference, registered at prepare; a `lineage:` image resolves its newest\n// version at attach. A `captured` base is the environment's build, captured as\n// a base (`part_...`) that computers are created from.\nconst computerArtifactSchema = sandboxSeedArtifactSchema.extend({\n version: z.literal(1),\n key: z.string(),\n image: z.string(),\n diskGb: z.number().nullable(),\n base: z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('image'),\n image: z.string(),\n imageVersionId: z.string().nullable().default(null),\n }),\n z.object({ kind: z.literal('captured'), baseId: z.string() }),\n ]),\n});\n\nconst networkPolicySchema = z.object({\n mode: z.nativeEnum(NetworkPolicy),\n allow: z.array(z.string()).optional(),\n});\n\nconst computerStateSchema = z.object({\n version: z.literal(2),\n computerName: z.string(),\n // Null until the first attach creates the computer.\n computerId: z.string().nullable(),\n // The sandbox setup's network policy, enforced from the computer's first boot.\n network: networkPolicySchema,\n // Ports the setup's services listen on.\n ports: z.array(z.number().int()).default([]),\n});\n\nexport type ComputerSandboxArtifact = z.infer<typeof computerArtifactSchema>;\nexport type ComputerSandboxState = z.infer<typeof computerStateSchema>;\n\nexport interface ComputerSandboxSessionIface extends NetworkSandboxSessionIface {\n // What this computer's handle offers (the host reports it).\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type ComputerSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n ComputerSandboxArtifact,\n ComputerSandboxState,\n ComputerSandboxSessionIface\n>;\n\nexport interface ComputerSandboxErrorIface extends Error {\n code:\n | 'artifact_unavailable'\n | 'computer_gone'\n | 'computer_not_running'\n | 'invalid_environment'\n | 'build_failed';\n}\n\nconst computerSandboxError = (\n code: ComputerSandboxErrorIface['code'],\n message: string,\n): ComputerSandboxErrorIface =>\n Object.assign(new Error(message), { name: 'ComputerSandboxError', code });\n\nconst HTTP_TOKEN_LIFETIME_MS = 60 * 60_000;\nconst HTTP_TOKEN_RENEW_MS = 5 * 60_000;\n\n// Builds run from here; the capture scrub removes /tmp/*.\nconst BUILD_ROOT = '/tmp/final-build';\n// What the Computers API's capture scrub removes, so the home check skips it.\nconst CAPTURE_SCRUBBED_PATHS = [\n '/home/user/.bash_history',\n '/home/user/.zsh_history',\n '/home/user/.sh_history',\n '/home/user/.git-credentials',\n '/home/user/.config/gh/hosts.yml',\n '/home/user/.npmrc',\n '/home/user/.pypirc',\n '/home/user/.cargo/credentials',\n '/home/user/.cargo/credentials.toml',\n '/home/user/.aws',\n '/home/user/.config/gcloud',\n '/home/user/.azure',\n '/home/user/.docker/config.json',\n '/home/user/.netrc',\n '/home/user/.ssh',\n];\nconst BUILDER_IDLE_TIMEOUT_SECONDS = 2 * 60 * 60;\n// Bumped when the meaning of the build inputs changes (forces rebuilds).\nconst ARTIFACT_KEY_VERSION = 1;\n// Part of a built base's key; bumping it rebuilds every base.\nconst PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION = 2;\n\ninterface ComputerEgressConfigIface {\n egress: ComputerEgressPolicy;\n allow?: string[];\n}\nconst computerEgressOf = (policy: NetworkPolicyIface): ComputerEgressConfigIface => {\n if (policy.mode === NetworkPolicy.AllowAll) return { egress: ComputerEgressPolicy.Internet };\n if (policy.mode === NetworkPolicy.DenyAll) return { egress: ComputerEgressPolicy.None };\n return { egress: ComputerEgressPolicy.Allowlist, allow: policy.allow ?? [] };\n};\n\n// An allowlist also admits the platform's egress hosts, so its proxy stays reachable.\nconst egressFor = (\n ctx: Pick<SandboxResourceContextIface, 'platformEgressHosts'>,\n requested: NetworkPolicyIface,\n): ComputerEgressConfigIface => computerEgressOf(withPlatformEgressHosts(ctx, requested));\n\n// The setup's network as a computer can enforce it from boot: every host, none,\n// or an allowlist. A computer has no per-host deny list, so a setup naming one\n// is refused at create rather than run unenforced.\nexport const computerNetworkPolicyOf = (setup: SandboxSetupIface | null): NetworkPolicyIface => {\n const network = setup?.network;\n if (network == null) return { mode: NetworkPolicy.AllowAll };\n if ((network.deny ?? []).length > 0)\n throw computerSandboxError(\n 'invalid_environment',\n 'A Final computer cannot deny individual hosts; list the hosts to allow instead',\n );\n if (network.allow == null) return { mode: NetworkPolicy.AllowAll };\n return network.allow.length === 0\n ? { mode: NetworkPolicy.DenyAll }\n : { mode: NetworkPolicy.Allowlist, allow: [...network.allow] };\n};\n\nconst LINEAGE_PREFIX = 'lineage:';\n\nconst compactId = (id: string): string => id.replaceAll('-', '');\n\n// The computer's name: stable for the sandbox, so an attach retried after a\n// lost answer finds the computer it already created.\nexport const computerNameFor = async (sandboxId: string): Promise<string> =>\n `as-${(await sha256Hex(sandboxId)).slice(0, 24)}`;\n\nconst isRunningState = (state: ComputerState): boolean =>\n state === ComputerState.Running ||\n state === ComputerState.Paused ||\n state === ComputerState.Resuming;\n\n// Nothing runs on these to pause, and the Computers API refuses a pause of them:\n// stopped or shelved (the disk at rest), errored (resume reports it gone), or deleted.\nconst hasNothingToPause = (state: ComputerState): boolean =>\n state === ComputerState.Stopped ||\n state === ComputerState.Shelved ||\n state === ComputerState.Error ||\n state === ComputerState.Deleted;\n\n// A refusal (409), a missing computer (404) or a failed host command (5xx) can\n// mean the computer came to rest on its own; a request or auth failure cannot.\nconst pauseMayHaveSettled = (error: unknown): boolean =>\n isComputersApiError(error) &&\n error.statusCode != null &&\n (error.statusCode === 404 || error.statusCode === 409 || error.statusCode >= 500);\n\nconst RUNNING_POLL_MAX_MS = 5_000;\n\nexport const computerNeedsBuild = (build: ComputerBuildIface | undefined): boolean =>\n build != null && (build.steps.length > 0 || build.verify.length > 0);\n\n// The base's identity: a hash of the build-time inputs only, so identical\n// environments share one base.\nexport const computeComputerArtifactKey = async (inputs: {\n image: string;\n build: ComputerBuildIface | undefined;\n diskGb: number | null;\n}): Promise<string> => {\n if (!computerNeedsBuild(inputs.build)) {\n const hex = await sha256Hex(canonicalJson({ v: ARTIFACT_KEY_VERSION, image: inputs.image }));\n return `img-${hex.slice(0, 16)}`;\n }\n const hex = await sha256Hex(\n canonicalJson({\n v: ARTIFACT_KEY_VERSION,\n image: inputs.image,\n build: { steps: inputs.build?.steps ?? [], verify: inputs.build?.verify ?? [] },\n diskGb: inputs.diskGb,\n }),\n );\n return `pa-g${hex.slice(0, 16)}-c${PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION}`;\n};\n\n// What a computer's handle needs beyond the client: the sandbox it serves and\n// the platform's egress hosts its allowlist keeps.\ntype HandleContextIface = Pick<SandboxResourceContextIface, 'sandboxId' | 'platformEgressHosts'>;\n\nexport const createComputerSandboxProvider = (\n config: ComputerSandboxProviderConfigIface,\n): ComputerSandboxProviderIface => {\n const log: ComputerSandboxLogIface = config.log ?? (() => undefined);\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const sleep = config.sleep ?? defaultSleep;\n const runningWaitMs = config.runningWaitMs ?? 5 * 60_000;\n\n // An assertion for the Computers API before each request, and a new one\n // after a rejection.\n const credentialsFor = (ctx: SandboxProviderContextIface): ComputersApiCredentialsIface => ({\n computersAccess: async (args) => ({\n baseUrl: config.computersApiUrl,\n token: (\n await ctx.identity({ audience: config.computersApiUrl, refresh: args?.refresh === true })\n ).token,\n }),\n });\n\n const clientFor = (ctx: SandboxProviderContextIface): ComputersApiClientIface =>\n createComputersApiClient({\n config: config.computersApi ?? {},\n credentials: credentialsFor(ctx),\n });\n\n const registerImage = (client: ComputersApiClientIface, reference: string) =>\n client.registerImage(\n config.registryCredentialId == null\n ? { reference }\n : { reference, registryCredentialId: config.registryCredentialId },\n );\n\n // Computers are created from registered image versions, as any API customer's are.\n // A `lineage:` image is the newest ready version of that lineage; a reference\n // is registered once, at prepare, and registered again here when its version expired.\n const readyImageVersion = async (\n client: ComputersApiClientIface,\n base: { image: string; imageVersionId: string | null },\n ): Promise<string> => {\n if (base.image.startsWith(LINEAGE_PREFIX)) {\n const lineage = base.image.slice(LINEAGE_PREFIX.length);\n const [newest] = await client.listImages({ lineage, state: ComputerImageState.Ready });\n if (newest == null) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `the Computers API has no ready image version in lineage ${lineage}`,\n );\n }\n return newest.id;\n }\n let version: ComputerImageIface | null = null;\n if (base.imageVersionId != null) {\n try {\n version = await client.getImage(base.imageVersionId);\n } catch (error) {\n if (!isComputersApiStatus(error, 404)) throw error;\n }\n }\n if (version == null || version.state === ComputerImageState.Expired) {\n version = await registerImage(client, base.image);\n }\n const deadline = now() + (config.imageWaitMs ?? 15 * 60_000);\n while (\n version.state === ComputerImageState.Pending ||\n version.state === ComputerImageState.Building\n ) {\n if (now() >= deadline) throw new Error(`image ${base.image} is still building`);\n await sleep(config.imagePollMs ?? 5_000);\n version = await client.getImage(version.id);\n }\n if (version.state !== ComputerImageState.Ready) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `image ${base.image} is ${version.state}${version.error == null ? '' : `: ${version.error}`}`,\n );\n }\n return version.id;\n };\n\n const mcpClosers = new Map<string, Set<() => Promise<void>>>();\n const closeComputerMcp = async (computerId: string) => {\n const results = await Promise.allSettled(\n [...(mcpClosers.get(computerId) ?? [])].map((close) => close()),\n );\n for (const result of results) if (result.status === 'rejected') throw result.reason;\n };\n const deletedAfterFenceError = async (options: {\n client: ComputersApiClientIface;\n computerId: string;\n cause: unknown;\n }): Promise<boolean> => {\n if (isComputersApiStatus(options.cause, 404)) return true;\n if (!isComputersApiStatus(options.cause, 409)) return false;\n try {\n const current = await options.client.getComputer(options.computerId);\n return current == null || current.state === ComputerState.Deleted;\n } catch (lookup) {\n throw new AggregateError(\n [options.cause, lookup],\n 'Computer fence and deletion lookup failed',\n );\n }\n };\n\n // The provider's own session on a computer: the platform's files and seeds\n // are written through it, never through a host's grant.\n const setupSession = (args: {\n client: ComputersApiClientIface;\n info: ComputerInfoIface;\n env: () => Promise<Record<string, string>>;\n }): { sandbox: NetworkSandboxSessionIface; transport: SandboxTransportIface } => {\n const transport = createComputersApiTransport({\n client: args.client,\n computerId: args.info.id,\n });\n const sandbox = createTransportSession({\n id: args.info.id,\n description: `setup of ${args.info.name}`,\n workspaceRoot: WORKSPACE_ROOT,\n transport,\n baseEnv: args.env,\n randomUuid,\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('setup sessions expose no ports');\n },\n stop: async () => undefined,\n destroy: async () => undefined,\n },\n });\n return { sandbox, transport };\n };\n\n const buildHandle = async (args: {\n ctx: HandleContextIface;\n client: ComputersApiClientIface;\n info: ComputerInfoIface;\n env: () => Promise<Record<string, string>>;\n ports: readonly number[];\n // A viewer's handle: it changes nothing, and stopping it leaves the computer alone.\n passive: boolean;\n closeSetup?: () => void;\n }): Promise<SandboxProviderHandleIface<ComputerSandboxSessionIface>> => {\n const { client, info } = args;\n const transport = createComputersApiTransport({ client, computerId: info.id });\n let httpToken: { token: string; expiresAtMs: number } | null = null;\n const session = createTransportSession({\n id: info.id,\n description: `Final computer ${info.name}`,\n workspaceRoot: WORKSPACE_ROOT,\n transport,\n baseEnv: args.env,\n randomUuid,\n network: {\n ports: [...args.ports],\n // The computer's hostname with a preview token, which opens its HTTP ports only.\n getPortEndpoint: async ({ port, protocol }) => {\n const hostname = info.hostname ?? (await client.getComputer(info.id))?.hostname ?? null;\n if (hostname == null) throw new Error(`computer ${info.name} has no public hostname`);\n if (httpToken == null || httpToken.expiresAtMs - now() < HTTP_TOKEN_RENEW_MS) {\n const expiresAtMs = now() + HTTP_TOKEN_LIFETIME_MS;\n const token = await client.createPreviewToken({\n computerId: info.id,\n name: `agent sandbox ${args.ctx.sandboxId}`,\n expiresAt: new Date(expiresAtMs),\n });\n httpToken = { token, expiresAtMs };\n }\n const scheme = protocol === PortProtocol.Ws ? 'wss' : 'https';\n return {\n url: `${scheme}://${port === 443 ? hostname : `${hostname}:${port}`}`,\n headers: { authorization: `Bearer ${httpToken.token}` },\n };\n },\n stop: async () => {\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(info.id);\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n try {\n await client.action(info.id, 'stop');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n transport.close();\n args.closeSetup?.();\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer stop or MCP cleanup failed');\n },\n destroy: async () => {\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(info.id);\n } catch (cause) {\n failures.push(cause);\n }\n transport.close();\n try {\n await client.action(info.id, 'delete');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n },\n });\n let computerUseInstalled: boolean | null = null;\n if (!args.passive) {\n try {\n computerUseInstalled = (await client.computerUseStatus(info.id, AbortSignal.timeout(1000)))\n .installed;\n } catch {\n /* Optional discovery must never fail the sandbox. */\n }\n }\n const computerUse =\n args.passive || computerUseInstalled === false\n ? null\n : createComputerUseEndpoint({ client, computerId: info.id, cwd: WORKSPACE_ROOT });\n const closeMcp = async () => {\n try {\n await computerUse?.close();\n } catch (error) {\n log('computer_use.close_failed', {\n computerId: info.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const closers = mcpClosers.get(info.id);\n closers?.delete(closeMcp);\n if (closers?.size === 0) mcpClosers.delete(info.id);\n };\n if (computerUse != null) {\n const closers = mcpClosers.get(info.id) ?? new Set<() => Promise<void>>();\n closers.add(closeMcp);\n mcpClosers.set(info.id, closers);\n }\n const capabilities = [SandboxCapability.Files, SandboxCapability.Ports];\n let screenAvailable = false;\n try {\n screenAvailable = (await client.screenStatus(info.id, AbortSignal.timeout(1000))).available;\n } catch {\n /* Optional desktop discovery leaves headless computers usable. */\n }\n if (screenAvailable) capabilities.push(SandboxCapability.Screen);\n if (computerUse != null) capabilities.push(SandboxCapability.ComputerUse);\n if (!args.passive)\n capabilities.push(\n SandboxCapability.Process,\n SandboxCapability.DurableProcesses,\n SandboxCapability.NetworkPolicy,\n );\n const full: ComputerSandboxSessionIface = {\n ...session,\n setNetworkPolicy: async (policy) => {\n if (args.passive) throw new Error('this sandbox handle is read-only');\n await client.setNetworkPolicy(info.id, egressFor(args.ctx, policy));\n },\n capabilities,\n };\n if (computerUse != null) full.computerUse = async () => computerUse.endpoint;\n if (screenAvailable) full.screen = (options) => client.openScreen(info.id, options);\n return {\n sandbox: args.passive ? readOnlySession(full) : full,\n onSandboxStop: async () => {\n const failures: unknown[] = [];\n for (const finish of [closeMcp, () => transport.close(), () => args.closeSetup?.()]) {\n try {\n await finish();\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'Computer MCP cleanup failed');\n },\n onSandboxDelete: async () => {\n const failures: unknown[] = [];\n try {\n await closeMcp();\n } catch (cause) {\n failures.push(cause);\n }\n transport.close();\n args.closeSetup?.();\n try {\n await client.action(info.id, 'delete');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n onRuntimeShutdown: async () => {\n try {\n await closeMcp();\n } finally {\n transport.close();\n args.closeSetup?.();\n }\n },\n };\n };\n\n // A captured base, once it is ready; a failed or expired one must be built again.\n const awaitBase = async (\n client: ComputersApiClientIface,\n baseId: string,\n key: string,\n ): Promise<ComputerBaseIface> => {\n const deadline = now() + (config.buildWaitMs ?? 30 * 60_000);\n for (;;) {\n const base = await client.getBase(baseId);\n if (base == null || base.state === ComputerBaseState.Expired) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `computer base ${key} (${baseId}) is ${base == null ? 'gone' : 'expired'}; prepare it again`,\n );\n }\n if (base.state === ComputerBaseState.Ready) return base;\n if (base.state === ComputerBaseState.Failed) {\n throw computerSandboxError(\n 'build_failed',\n `computer base ${key} failed to capture: ${base.error ?? 'unknown error'}`,\n );\n }\n if (now() >= deadline) throw new Error(`computer base ${key} is still capturing`);\n await sleep(config.buildPollMs ?? 5_000);\n }\n };\n\n // The Computers API answers a computer it created or started before the\n // computer has a host, and refuses commands and file writes until it runs\n // (`autoResume: false`), so nothing touches it before this resolves. Only\n // Running counts: a paused computer still refuses them.\n const awaitComputerRunning = async (\n client: ComputersApiClientIface,\n computerId: string,\n timeoutMs: number,\n ): Promise<ComputerInfoIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = config.runningPollMs ?? 250;\n for (;;) {\n const computer = await client.getComputer(computerId);\n if (computer == null || computer.state === ComputerState.Deleted)\n throw computerSandboxError('computer_gone', `computer ${computerId} is gone`);\n if (computer.state === ComputerState.Error)\n throw computerSandboxError(\n 'computer_gone',\n `computer ${computer.name} is in the Error state`,\n );\n if (computer.state === ComputerState.Running) return computer;\n const left = deadline - now();\n if (left <= 0)\n throw computerSandboxError(\n 'computer_not_running',\n `computer ${computer.name} was not running within ${Math.round(timeoutMs / 1000)} s (it is ${ComputerState[computer.state]})`,\n );\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, RUNNING_POLL_MAX_MS);\n }\n };\n\n // Run build.steps, then build.verify, on a builder computer of the\n // environment's image, captured as a base its computers are created from.\n const build = async (args: {\n ctx: SandboxPrepareContextIface;\n image: string;\n build: ComputerBuildIface;\n machine: ComputerEnvironmentIface['machine'];\n region: string | null;\n key: string;\n }): Promise<ComputerSandboxArtifact> => {\n const { ctx, key } = args;\n const client = clientFor(ctx);\n const diskGb = args.machine?.diskGb ?? null;\n const imageVersionId = await readyImageVersion(client, {\n image: args.image,\n imageVersionId: null,\n });\n const body: CreateComputerBodyIface = {\n name: `ag-${key.slice(4, 20)}-${compactId(randomUuid()).slice(0, 8)}`,\n imageVersionId,\n ...args.machine,\n // The base is the root disk; a user volume would keep /home and /workspaces off it.\n userVolumeGb: null,\n // Nothing secret at create: the create env lands in the guest.\n env: {},\n commandMode: ComputerCommandMode.Custom,\n customCommand: 'sleep infinity',\n autoResume: false,\n idleTimeoutSeconds: BUILDER_IDLE_TIMEOUT_SECONDS,\n tags: ['final-agent-sandbox-build'],\n };\n if (args.region != null) body.regionSlug = args.region;\n // One builder per attempt: a retry after a failed build starts clean.\n const builder = await client.createComputer(\n body,\n `agent-guide-build-${(await sha256Hex(`${key}:${randomUuid()}`)).slice(0, 32)}`,\n );\n ctx.log?.(`building computer base ${key} on ${builder.name}`);\n try {\n await awaitComputerRunning(client, builder.id, runningWaitMs);\n const sandbox = setupSession({ client, info: builder, env: async () => ({}) }).sandbox;\n const prepared = await sandbox.run({\n command: '/bin/sh',\n args: ['-c', `mkdir -p ${BUILD_ROOT}\\n${homeBaselineScript()}`],\n cwd: '/',\n });\n if (prepared.exitCode !== 0) {\n throw computerSandboxError('build_failed', 'failed to record the pre-build home baseline');\n }\n const steps = [\n ...args.build.steps.map((step) => ({ step, label: 'build step' })),\n ...args.build.verify.map((step) => ({ step, label: 'verify step' })),\n ];\n for (const [index, { step, label }] of steps.entries()) {\n ctx.log?.(`${label} ${index + 1}/${steps.length}`);\n const result = await sandbox.run({\n command: `set -eu\\n${step.run}`,\n shell: true,\n cwd: BUILD_ROOT,\n timeoutMs: step.timeoutMinutes * 60_000,\n });\n if (result.exitCode !== 0) {\n throw computerSandboxError(\n 'build_failed',\n `${label} ${index + 1} failed (exit ${result.exitCode}): ${result.stderr.trim().slice(-2000)}`,\n );\n }\n }\n const homeContent = await sandbox.run({\n command: '/bin/sh',\n args: ['-c', homeContentScript({ excludedPaths: CAPTURE_SCRUBBED_PATHS })],\n cwd: '/',\n });\n if (homeContent.exitCode === HOME_BASELINE_MISSING_EXIT_CODE) {\n throw computerSandboxError(\n 'build_failed',\n `build steps removed ${HOME_BASELINE_ROOT}, which the home content check needs; leave /var/tmp/final-template-build in place.`,\n );\n }\n if (homeContent.exitCode !== 0) {\n const offending = homeContent.stdout\n .trim()\n .split('\\n')\n .filter((line) => line !== '');\n throw computerSandboxError(\n 'build_failed',\n `build steps left content under /home or /workspaces, which each computer's own volume hides: ${offending.join(', ')}. Install tools and configuration to system paths such as /usr/local, or point the tool's home there (for example CARGO_HOME=/usr/local/cargo, RUSTUP_HOME=/usr/local/rustup, NVM_DIR=/usr/local/nvm), put home files in /usr/share/final-vm/home-skel, and use /etc/gitconfig instead of git config --global.`,\n );\n }\n const captured = await client.captureComputer(builder.id, { retained: true });\n if (!captured.retained)\n throw computerSandboxError(\n 'build_failed',\n 'the Computers API did not retain the built base',\n );\n ctx.log?.(`capturing computer base ${key} as ${captured.id}`);\n const base = await awaitBase(client, captured.id, key);\n return {\n version: 1,\n key,\n image: args.image,\n diskGb: diskGb ?? base.diskGb,\n seedFiles: {},\n base: { kind: 'captured', baseId: base.id },\n };\n } finally {\n // The capture stopped the builder; it is not part of the base.\n try {\n await client.action(builder.id, 'delete');\n } catch (error) {\n log('computer_sandbox.builder_delete_failed', {\n computerId: builder.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxEnvironmentImplementationIface<\n ComputerSandboxArtifact,\n ComputerSandboxState,\n ComputerSandboxSessionIface\n > => {\n const parsed = computerEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) {\n throw computerSandboxError(\n 'invalid_environment',\n `invalid computer environment: ${parsed.error.message}`,\n );\n }\n const options = parsed.data;\n const image = options.image ?? config.defaultImage ?? DEFAULT_COMPUTER_IMAGE;\n const machine = options.machine ?? config.machine;\n const region = options.region ?? config.regionSlug ?? null;\n // Outlasts the platform's own idle parking, so the platform parks first.\n const idleTimeoutFor = (ctx: SandboxResourceContextIface): number =>\n options.idleTimeoutSeconds ??\n (ctx.lifecycle.parkAfterIdleMs == null\n ? DEFAULT_IDLE_TIMEOUT_SECONDS\n : Math.ceil(ctx.lifecycle.parkAfterIdleMs / 1000) + IDLE_TIMEOUT_MARGIN_SECONDS);\n const seedsFor = (ctx: SandboxPrepareContextIface): Record<string, string> =>\n sandboxSeedFiles({ files: ctx.files, resources: ctx.resources });\n const keyFor = async (files: Record<string, string>): Promise<string> => {\n const baseKey = await computeComputerArtifactKey({\n image,\n build: options.build,\n diskGb: machine?.diskGb ?? null,\n });\n return Object.keys(files).length === 0\n ? baseKey\n : `${baseKey}-s${await sha256Hex(sandboxSeedIdentity(files))}`;\n };\n const retainedBase = async (\n ctx: SandboxPrepareContextIface,\n baseKey: string,\n ): Promise<ComputerSandboxArtifact | null> => {\n const cached = computerArtifactSchema.safeParse(await ctx.artifacts?.get(baseKey));\n if (!cached.success || cached.data.key !== baseKey || cached.data.base.kind !== 'captured')\n return null;\n const client = clientFor(ctx);\n const base = await client.getBase(cached.data.base.baseId);\n if (base?.state !== ComputerBaseState.Ready) return null;\n if (!base.retained && !(await client.setBaseRetention(base.id, true)).retained)\n throw computerSandboxError(\n 'build_failed',\n 'the Computers API did not retain the prepared base',\n );\n return cached.data;\n };\n\n const stateOf = (raw: JsonValue): ComputerSandboxState => {\n const state = computerStateSchema.safeParse(raw);\n if (!state.success)\n throw computerSandboxError(\n 'computer_gone',\n 'this sandbox was recorded by an older computer provider; create it again',\n );\n return state.data;\n };\n\n // The computer the state names, else one an interrupted attach created\n // under the sandbox's name; null when none exists.\n const findComputer = async (\n client: ComputersApiClientIface,\n state: ComputerSandboxState,\n ): Promise<ComputerInfoIface | null> => {\n const found = await client.getComputer(state.computerId ?? state.computerName);\n return found == null || found.state === ComputerState.Deleted ? null : found;\n };\n\n return {\n capabilities: async () => ({\n [Capability.Files]: FilesAccess.Write,\n [Capability.Shell]: ShellAccess.Execute,\n [Capability.ComputerUse]: ScreenAccess.Control,\n }),\n processes: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n if (state.computerId == null) throw new Error('this computer has not started yet');\n return clientFor(ctx).inspectProcesses(state.computerId, request);\n },\n editor: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n const computerId = state.computerId;\n if (computerId == null) {\n if (request.operation === 'available') return { available: false };\n throw new Error('this computer has not started yet');\n }\n const client = clientFor(ctx);\n const open = (expiresAtMs?: number) =>\n computerEditor({\n client,\n computerId,\n request,\n randomUuid,\n expiresAtMs,\n });\n return open();\n },\n readSnapshot: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n if (state.computerId == null) return null;\n return readComputerSnapshot({\n client: clientFor(ctx),\n computerId: state.computerId,\n request,\n });\n },\n artifactKey: async (ctx) => keyFor(seedsFor(ctx)),\n // Builds the base an environment with build steps needs, or registers an\n // image reference so its version builds ahead of the first attach (a\n // lineage needs nothing until then).\n prepare: async (ctx) => {\n const seedFiles = seedsFor(ctx);\n const key = await keyFor(seedFiles);\n const seedArtifact = await sandboxSeedArtifact(ctx, seedFiles);\n if (options.build != null && computerNeedsBuild(options.build)) {\n const baseKey = await keyFor({});\n const retained = await retainedBase(ctx, baseKey);\n if (retained != null) return { ...retained, key, ...seedArtifact };\n const built = await build({\n ctx,\n image,\n build: options.build,\n machine,\n region,\n key: baseKey,\n });\n await ctx.artifacts?.put(baseKey, built);\n return { ...built, key, ...seedArtifact };\n }\n const imageVersionId = image.startsWith(LINEAGE_PREFIX)\n ? null\n : (await registerImage(clientFor(ctx), image)).id;\n ctx.log?.(`computer base ${key} is image ${image}`);\n return {\n version: 1,\n key,\n image,\n diskGb: machine?.diskGb ?? null,\n ...seedArtifact,\n base: { kind: 'image', image, imageVersionId },\n };\n },\n // Records the computer; the first attach creates it. The setup's network\n // policy is checked now so a policy a computer cannot enforce never boots.\n create: async (ctx, { setup }) => {\n const network = computerNetworkPolicyOf(setup);\n const ports = [\n ...new Set(\n (setup?.services ?? []).flatMap((service) =>\n service.port == null ? [] : [service.port],\n ),\n ),\n ];\n return {\n state: {\n version: 2,\n computerName: await computerNameFor(ctx.sandboxId),\n computerId: null,\n network,\n ports,\n },\n region,\n };\n },\n awaitRunning: async (ctx, rawState, options) => {\n const state = stateOf(rawState);\n await awaitComputerRunning(\n clientFor(ctx),\n state.computerId ?? state.computerName,\n options.timeoutMs,\n );\n },\n attach: async (ctx, { artifact: rawArtifact, state: rawState }) => {\n const state = stateOf(rawState);\n const artifact = computerArtifactSchema.safeParse(rawArtifact);\n if (!artifact.success)\n throw computerSandboxError(\n 'artifact_unavailable',\n 'this computer base predates the current computer provider; prepare it again',\n );\n const base = artifact.data.base;\n if (computerNeedsBuild(options.build) && base.kind !== 'captured')\n throw computerSandboxError(\n 'artifact_unavailable',\n `computer base ${artifact.data.key} was prepared without its build steps; prepare it again`,\n );\n const client = clientFor(ctx);\n const env = platformProcessEnvironment(ctx, {});\n const policy = withPlatformEgressHosts(ctx, state.network);\n const egress = computerEgressOf(policy);\n const existing = await findComputer(client, state);\n if (existing?.state === ComputerState.Error)\n throw computerSandboxError(\n 'computer_gone',\n `Computer ${existing.id} (${existing.name}) is in the Error state. Recover it through the Computers API before retrying; its disk is preserved.`,\n );\n let info: ComputerInfoIface;\n let booted: boolean;\n if (existing != null) {\n info = existing;\n // A paused computer resumes with its processes; a stopped or shelved one boots.\n booted = !isRunningState(existing.state);\n if (existing.state === ComputerState.Paused) await client.action(existing.id, 'resume');\n else if (booted) await client.action(existing.id, 'start');\n } else {\n // A computer the state named but that no longer exists comes back\n // empty: the attach reports a fresh disk.\n booted = true;\n const source: Pick<CreateComputerBodyIface, 'baseId' | 'imageVersionId'> =\n base.kind === 'captured'\n ? { baseId: (await awaitBase(client, base.baseId, artifact.data.key)).id }\n : { imageVersionId: await readyImageVersion(client, base) };\n const body: CreateComputerBodyIface = {\n name: state.computerName,\n ...source,\n ...machine,\n env: {},\n autoResume: true,\n idleTimeoutSeconds: idleTimeoutFor(ctx),\n // The sandbox owns deletion; VM-level ephemeral disks cannot be paused.\n ephemeral: false,\n network: egress,\n tags: [\n 'final-agent-sandbox',\n `agent-sandbox:${ctx.sandboxId}`,\n 'agent-runtime-attachment:v1',\n 'agent-runtime-role:sandbox',\n ],\n };\n // Idle must preserve files: the sandbox is deleted only by its owner.\n body.idlePolicy = ComputerIdlePolicy.Pause;\n if (region != null) body.regionSlug = region;\n // A retry of this attach makes the same request; one after the\n // computer was deleted, or after re-registering the image, a new one.\n const idempotencyKey = `agent-sandbox-${(await sha256Hex(`${ctx.sandboxId}:${state.computerName}:${state.computerId ?? 'first'}:${source.baseId ?? source.imageVersionId}:false`)).slice(0, 32)}`;\n info = await client.createComputer(body, idempotencyKey);\n }\n const fresh = existing == null;\n log('computer_sandbox.attached', { computerId: info.id, fresh, booted });\n let cleanup: (() => Promise<void>) | null = null;\n try {\n info = await awaitComputerRunning(client, info.id, runningWaitMs);\n // A reused computer keeps whatever policy it last ran under; it gets the setup's again.\n if (!fresh) await client.setNetworkPolicy(info.id, egress);\n await reportPlatformNetworkPolicy(ctx, policy);\n const setup = setupSession({ client, info, env });\n cleanup = async () => setup.transport.close();\n await writePlatformFiles(ctx, setup.sandbox);\n // A new disk gets the workspace seeds once.\n if (fresh) {\n const seedMarker = `${WORKSPACE_ROOT}/.final/workspace-prepared/${await sha256Hex(artifact.data.key)}`;\n if ((await setup.sandbox.stat({ path: seedMarker })) == null) {\n await materializeSandboxSeeds({\n sandbox: setup.sandbox,\n root: WORKSPACE_ROOT,\n files: await sandboxSeedFilesForAttach(ctx, artifact.data),\n });\n await setup.sandbox.writeTextFile({ path: seedMarker, content: 'complete' });\n }\n }\n const handle = await buildHandle({\n ctx,\n client,\n info,\n env,\n ports: state.ports,\n passive: false,\n closeSetup: () => setup.transport.close(),\n });\n return {\n handle,\n region: info.regionSlug ?? region,\n state: { ...state, computerId: info.id },\n fresh,\n booted,\n };\n } catch (error) {\n let cause = error;\n try {\n await cleanup?.();\n } catch (cleanupError) {\n cause = new AggregateError(\n [error, cleanupError],\n 'Computer attach and setup cleanup failed',\n );\n }\n // No state reaches the caller on failure; remove only a computer this attach created.\n if (fresh) {\n try {\n await client.action(info.id, 'delete');\n } catch (cleanupError) {\n throw new AggregateError(\n [cause, cleanupError],\n `computer ${info.name} attach and cleanup failed`,\n );\n }\n }\n throw cause;\n }\n },\n attachPassive: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n const client = clientFor(ctx);\n const info = await findComputer(client, state);\n if (info == null || info.state !== ComputerState.Running)\n throw computerSandboxError(\n 'computer_not_running',\n 'computer is not running for passive access',\n );\n return buildHandle({\n ctx,\n client,\n info: await awaitComputerRunning(client, info.id, runningWaitMs),\n env: platformProcessEnvironment(ctx, {}),\n ports: state.ports,\n passive: true,\n });\n },\n // The computer pauses on its own idle policy; nothing to do.\n detach: async (_ctx, { state }) => stateOf(state),\n park: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n if (state.computerId == null) return state;\n const computerId = state.computerId;\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(computerId);\n } catch (cause) {\n failures.push(cause);\n }\n try {\n const client = clientFor(ctx);\n // Park reads the computer's state rather than trusting a pause's status\n // alone: a pause that cannot land would otherwise fail on every retry.\n let current: ComputerInfoIface | null | undefined;\n try {\n current = await client.getComputer(computerId);\n } catch (cause) {\n failures.push(cause);\n }\n if (current !== undefined && (current == null || hasNothingToPause(current.state))) {\n log('computer_sandbox.park_at_rest', {\n computerId,\n state: current?.state ?? null,\n });\n } else {\n // A paused computer is paused again: a resume may be in flight.\n try {\n await client.action(computerId, 'pause');\n } catch (error) {\n if (!pauseMayHaveSettled(error)) throw error;\n // Parked if it came to rest meanwhile (an idle pause or stop, a delete);\n // otherwise the pause did not happen and park is retried.\n const settled = await client.getComputer(computerId);\n if (\n settled != null &&\n settled.state !== ComputerState.Paused &&\n !hasNothingToPause(settled.state)\n )\n throw error;\n log('computer_sandbox.park_at_rest', {\n computerId,\n state: settled?.state ?? null,\n });\n }\n }\n } catch (cause) {\n failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'Computer pause failed');\n return state;\n },\n delete: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n const client = clientFor(ctx);\n const computer = await findComputer(client, state);\n if (computer == null) return;\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(computer.id);\n } catch (cause) {\n failures.push(cause);\n }\n log('computer_sandbox.delete', { computerId: computer.id });\n try {\n await client.action(computer.id, 'delete');\n } catch (error) {\n // A conflict is done only when the computer is already gone; one\n // mid-transition (an idle pause committing) is retried.\n if (!(await deletedAfterFenceError({ client, computerId: computer.id, cause: error })))\n failures.push(error);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n };\n };\n\n return defineSandboxProvider({\n name: COMPUTER_PROVIDER,\n stateProtocolVersion: 2,\n environment,\n });\n};\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import { Capability, FilesAccess, ScreenAccess, ShellAccess } from '@finalai/agent-protocol';\nimport { NetworkPolicy, type JsonValue } from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n materializeSandboxSeeds,\n platformProcessEnvironment,\n PortProtocol,\n reportPlatformNetworkPolicy,\n SandboxCapability,\n sandboxSeedArtifact,\n sandboxSeedArtifactSchema,\n sandboxSeedFiles,\n sandboxSeedFilesForAttach,\n sandboxSeedIdentity,\n withPlatformEgressHosts,\n writePlatformFiles,\n type NetworkPolicyIface,\n type NetworkSandboxSessionIface,\n type SandboxEnvironmentImplementationIface,\n type SandboxPrepareContextIface,\n type SandboxProviderContextIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxResourceContextIface,\n type SandboxSetupIface,\n} from '@finalai/agent-provider/sandbox';\nimport {\n ComputerBaseState,\n ComputerCommandMode,\n ComputerEgressPolicy,\n ComputerIdlePolicy,\n ComputerImageState,\n ComputerState,\n type ComputerBaseIface,\n type ComputerImageIface,\n type ComputerInfoIface,\n} from '@finalai/computers';\nimport * as z from 'zod';\nimport {\n HOME_BASELINE_MISSING_EXIT_CODE,\n HOME_BASELINE_ROOT,\n homeBaselineScript,\n homeContentScript,\n} from \"./build-scripts.mjs\";\nimport { canonicalJson, sleep as defaultSleep, sha256Hex } from \"./bytes.mjs\";\nimport { computerEditor } from \"./computer-editor.mjs\";\nimport { readComputerSnapshot } from \"./computer-snapshots.mjs\";\nimport {\n createComputersApiClient,\n isComputersApiError,\n isComputersApiStatus,\n type ComputersApiClientIface,\n type ComputersApiConfigIface,\n type ComputersApiCredentialsIface,\n type CreateComputerBodyIface,\n} from \"./computers-api.mjs\";\nimport { createComputerUseEndpoint } from \"./computers-api-mcp.mjs\";\nimport { createComputersApiTransport } from \"./computers-api-transport.mjs\";\nimport {\n COMPUTER_PROVIDER,\n computerEnvironmentSchema,\n DEFAULT_COMPUTER_IMAGE,\n type ComputerBuildIface,\n type ComputerEnvironmentIface,\n} from \"./environment.mjs\";\nimport { createTransportSession, readOnlySession } from \"./session.mjs\";\nimport { toolDescriptorsOf } from \"./tool-catalog.mjs\";\nimport type { SandboxTransportIface } from \"./transport.mjs\";\n\nexport type { ComputersApiConfigIface } from \"./computers-api.mjs\";\nexport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nexport { COMPUTER_PROVIDER } from \"./environment.mjs\";\n\n// The `computer` sandbox: a Final computer from the public Computers API, with\n// lifecycle, files and processes all through that API, exactly as a\n// third-party provider drives its vendor. Like every provider, the host runs\n// this handle and serves the handle RPC and MCP projection from it.\n//\n// A sandbox is one computer, named after the sandbox's id: `create` records\n// it and the first `attach` makes it, so creating a sandbox boots nothing. An\n// environment with build or verify steps is built once on a builder computer\n// and captured as a base (POST /v1/computers/:id/capture) that its computers\n// are created from. The sandbox setup's network policy is a create option, as\n// for any API customer; its repositories, steps and services are applied by\n// the platform through the handle.\n\nexport const WORKSPACE_ROOT = '/workspaces';\n\nconst DEFAULT_IDLE_TIMEOUT_SECONDS = 15 * 60;\nconst IDLE_TIMEOUT_MARGIN_SECONDS = 5 * 60;\n\nexport interface ComputerSandboxLogIface {\n (message: string, fields?: Record<string, string | number | boolean | null>): void;\n}\n\nexport interface ComputerSandboxProviderConfigIface {\n // The Computers API origin. Requests authenticate with the provider's\n // platform identity for it (ctx.identity), which the registration must be\n // granted.\n computersApiUrl: string;\n // Transport options.\n computersApi?: ComputersApiConfigIface;\n // A registry credential (`creg_...`) stored for private image references.\n registryCredentialId?: string;\n // Image for an environment that names none.\n defaultImage?: string;\n // Defaults for what an environment leaves out.\n regionSlug?: string;\n machine?: { vcpu?: number; memoryMb?: number; diskGb?: number };\n // How long attach waits for a registered image version to finish building.\n imageWaitMs?: number;\n imagePollMs?: number;\n // How long `prepare` waits for a base capture to publish.\n buildWaitMs?: number;\n buildPollMs?: number;\n // How long attach and a build wait for a computer to run before touching it\n // (default 5 min); polled from runningPollMs (default 250 ms), doubling to 5 s.\n runningWaitMs?: number;\n runningPollMs?: number;\n log?: ComputerSandboxLogIface;\n randomUuid?: () => string;\n now?: () => number;\n sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;\n}\n\n// An `image` base: `imageVersionId` is the registered version (`cimv_...`) of an\n// image reference, registered at prepare; a `lineage:` image resolves its newest\n// version at attach. A `captured` base is the environment's build, captured as\n// a base (`part_...`) that computers are created from.\nconst computerArtifactSchema = sandboxSeedArtifactSchema.extend({\n version: z.literal(1),\n key: z.string(),\n image: z.string(),\n diskGb: z.number().nullable(),\n base: z.discriminatedUnion('kind', [\n z.object({\n kind: z.literal('image'),\n image: z.string(),\n imageVersionId: z.string().nullable().default(null),\n }),\n z.object({ kind: z.literal('captured'), baseId: z.string() }),\n ]),\n});\n\nconst networkPolicySchema = z.object({\n mode: z.nativeEnum(NetworkPolicy),\n allow: z.array(z.string()).optional(),\n});\n\nconst computerStateSchema = z.object({\n version: z.literal(2),\n computerName: z.string(),\n // Null until the first attach creates the computer.\n computerId: z.string().nullable(),\n // The sandbox setup's network policy, enforced from the computer's first boot.\n network: networkPolicySchema,\n // Ports the setup's services listen on.\n ports: z.array(z.number().int()).default([]),\n});\n\nexport type ComputerSandboxArtifact = z.infer<typeof computerArtifactSchema>;\nexport type ComputerSandboxState = z.infer<typeof computerStateSchema>;\n\nexport interface ComputerSandboxSessionIface extends NetworkSandboxSessionIface {\n // What this computer's handle offers (the host reports it).\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type ComputerSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n ComputerSandboxArtifact,\n ComputerSandboxState,\n ComputerSandboxSessionIface\n>;\n\nexport interface ComputerSandboxErrorIface extends Error {\n code:\n | 'artifact_unavailable'\n | 'computer_gone'\n | 'computer_not_running'\n | 'invalid_environment'\n | 'build_failed';\n}\n\nconst computerSandboxError = (\n code: ComputerSandboxErrorIface['code'],\n message: string,\n): ComputerSandboxErrorIface =>\n Object.assign(new Error(message), { name: 'ComputerSandboxError', code });\n\nconst HTTP_TOKEN_LIFETIME_MS = 60 * 60_000;\nconst HTTP_TOKEN_RENEW_MS = 5 * 60_000;\n\n// Builds run from here; the capture scrub removes /tmp/*.\nconst BUILD_ROOT = '/tmp/final-build';\n// What the Computers API's capture scrub removes, so the home check skips it.\nconst CAPTURE_SCRUBBED_PATHS = [\n '/home/user/.bash_history',\n '/home/user/.zsh_history',\n '/home/user/.sh_history',\n '/home/user/.git-credentials',\n '/home/user/.config/gh/hosts.yml',\n '/home/user/.npmrc',\n '/home/user/.pypirc',\n '/home/user/.cargo/credentials',\n '/home/user/.cargo/credentials.toml',\n '/home/user/.aws',\n '/home/user/.config/gcloud',\n '/home/user/.azure',\n '/home/user/.docker/config.json',\n '/home/user/.netrc',\n '/home/user/.ssh',\n];\nconst BUILDER_IDLE_TIMEOUT_SECONDS = 2 * 60 * 60;\n// Bumped when the meaning of the build inputs changes (forces rebuilds).\nconst ARTIFACT_KEY_VERSION = 1;\n// Part of a built base's key; bumping it rebuilds every base.\nconst PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION = 2;\n\ninterface ComputerEgressConfigIface {\n egress: ComputerEgressPolicy;\n allow?: string[];\n}\nconst computerEgressOf = (policy: NetworkPolicyIface): ComputerEgressConfigIface => {\n if (policy.mode === NetworkPolicy.AllowAll) return { egress: ComputerEgressPolicy.Internet };\n if (policy.mode === NetworkPolicy.DenyAll) return { egress: ComputerEgressPolicy.None };\n return { egress: ComputerEgressPolicy.Allowlist, allow: policy.allow ?? [] };\n};\n\n// An allowlist also admits the platform's egress hosts, so its proxy stays reachable.\nconst egressFor = (\n ctx: Pick<SandboxResourceContextIface, 'platformEgressHosts'>,\n requested: NetworkPolicyIface,\n): ComputerEgressConfigIface => computerEgressOf(withPlatformEgressHosts(ctx, requested));\n\n// The setup's network as a computer can enforce it from boot: every host, none,\n// or an allowlist. A computer has no per-host deny list, so a setup naming one\n// is refused at create rather than run unenforced.\nexport const computerNetworkPolicyOf = (setup: SandboxSetupIface | null): NetworkPolicyIface => {\n const network = setup?.network;\n if (network == null) return { mode: NetworkPolicy.AllowAll };\n if ((network.deny ?? []).length > 0)\n throw computerSandboxError(\n 'invalid_environment',\n 'A Final computer cannot deny individual hosts; list the hosts to allow instead',\n );\n if (network.allow == null) return { mode: NetworkPolicy.AllowAll };\n return network.allow.length === 0\n ? { mode: NetworkPolicy.DenyAll }\n : { mode: NetworkPolicy.Allowlist, allow: [...network.allow] };\n};\n\nconst LINEAGE_PREFIX = 'lineage:';\n\nconst compactId = (id: string): string => id.replaceAll('-', '');\n\n// The computer's name: stable for the sandbox, so an attach retried after a\n// lost answer finds the computer it already created.\nexport const computerNameFor = async (sandboxId: string): Promise<string> =>\n `as-${(await sha256Hex(sandboxId)).slice(0, 24)}`;\n\nconst isRunningState = (state: ComputerState): boolean =>\n state === ComputerState.Running ||\n state === ComputerState.Paused ||\n state === ComputerState.Resuming;\n\n// Nothing runs on these to pause, and the Computers API refuses a pause of them:\n// stopped or shelved (the disk at rest), errored (resume reports it gone), or deleted.\nconst hasNothingToPause = (state: ComputerState): boolean =>\n state === ComputerState.Stopped ||\n state === ComputerState.Shelved ||\n state === ComputerState.Error ||\n state === ComputerState.Deleted;\n\n// A refusal (409), a missing computer (404) or a failed host command (5xx) can\n// mean the computer came to rest on its own; a request or auth failure cannot.\nconst pauseMayHaveSettled = (error: unknown): boolean =>\n isComputersApiError(error) &&\n error.statusCode != null &&\n (error.statusCode === 404 || error.statusCode === 409 || error.statusCode >= 500);\n\nconst RUNNING_POLL_MAX_MS = 5_000;\n\nexport const computerNeedsBuild = (build: ComputerBuildIface | undefined): boolean =>\n build != null && (build.steps.length > 0 || build.verify.length > 0);\n\n// The base's identity: a hash of the build-time inputs only, so identical\n// environments share one base.\nexport const computeComputerArtifactKey = async (inputs: {\n image: string;\n build: ComputerBuildIface | undefined;\n diskGb: number | null;\n}): Promise<string> => {\n if (!computerNeedsBuild(inputs.build)) {\n const hex = await sha256Hex(canonicalJson({ v: ARTIFACT_KEY_VERSION, image: inputs.image }));\n return `img-${hex.slice(0, 16)}`;\n }\n const hex = await sha256Hex(\n canonicalJson({\n v: ARTIFACT_KEY_VERSION,\n image: inputs.image,\n build: { steps: inputs.build?.steps ?? [], verify: inputs.build?.verify ?? [] },\n diskGb: inputs.diskGb,\n }),\n );\n return `pa-g${hex.slice(0, 16)}-c${PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION}`;\n};\n\n// What a computer's handle needs beyond the client: the sandbox it serves and\n// the platform's egress hosts its allowlist keeps.\ntype HandleContextIface = Pick<SandboxResourceContextIface, 'sandboxId' | 'platformEgressHosts'>;\n\nexport const createComputerSandboxProvider = (\n config: ComputerSandboxProviderConfigIface,\n): ComputerSandboxProviderIface => {\n const log: ComputerSandboxLogIface = config.log ?? (() => undefined);\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const sleep = config.sleep ?? defaultSleep;\n const runningWaitMs = config.runningWaitMs ?? 5 * 60_000;\n\n // An assertion for the Computers API before each request, and a new one\n // after a rejection.\n const credentialsFor = (ctx: SandboxProviderContextIface): ComputersApiCredentialsIface => ({\n computersAccess: async (args) => ({\n baseUrl: config.computersApiUrl,\n token: (\n await ctx.identity({ audience: config.computersApiUrl, refresh: args?.refresh === true })\n ).token,\n }),\n });\n\n const clientFor = (ctx: SandboxProviderContextIface): ComputersApiClientIface =>\n createComputersApiClient({\n config: config.computersApi ?? {},\n credentials: credentialsFor(ctx),\n });\n\n const registerImage = (client: ComputersApiClientIface, reference: string) =>\n client.registerImage(\n config.registryCredentialId == null\n ? { reference }\n : { reference, registryCredentialId: config.registryCredentialId },\n );\n\n // Computers are created from registered image versions, as any API customer's are.\n // A `lineage:` image is the newest ready version of that lineage; a reference\n // is registered once, at prepare, and registered again here when its version expired.\n const readyImageVersion = async (\n client: ComputersApiClientIface,\n base: { image: string; imageVersionId: string | null },\n ): Promise<string> => {\n if (base.image.startsWith(LINEAGE_PREFIX)) {\n const lineage = base.image.slice(LINEAGE_PREFIX.length);\n const [newest] = await client.listImages({ lineage, state: ComputerImageState.Ready });\n if (newest == null) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `the Computers API has no ready image version in lineage ${lineage}`,\n );\n }\n return newest.id;\n }\n let version: ComputerImageIface | null = null;\n if (base.imageVersionId != null) {\n try {\n version = await client.getImage(base.imageVersionId);\n } catch (error) {\n if (!isComputersApiStatus(error, 404)) throw error;\n }\n }\n if (version == null || version.state === ComputerImageState.Expired) {\n version = await registerImage(client, base.image);\n }\n const deadline = now() + (config.imageWaitMs ?? 15 * 60_000);\n while (\n version.state === ComputerImageState.Pending ||\n version.state === ComputerImageState.Building\n ) {\n if (now() >= deadline) throw new Error(`image ${base.image} is still building`);\n await sleep(config.imagePollMs ?? 5_000);\n version = await client.getImage(version.id);\n }\n if (version.state !== ComputerImageState.Ready) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `image ${base.image} is ${version.state}${version.error == null ? '' : `: ${version.error}`}`,\n );\n }\n return version.id;\n };\n\n const mcpClosers = new Map<string, Set<() => Promise<void>>>();\n const closeComputerMcp = async (computerId: string) => {\n const results = await Promise.allSettled(\n [...(mcpClosers.get(computerId) ?? [])].map((close) => close()),\n );\n for (const result of results) if (result.status === 'rejected') throw result.reason;\n };\n const deletedAfterFenceError = async (options: {\n client: ComputersApiClientIface;\n computerId: string;\n cause: unknown;\n }): Promise<boolean> => {\n if (isComputersApiStatus(options.cause, 404)) return true;\n if (!isComputersApiStatus(options.cause, 409)) return false;\n try {\n const current = await options.client.getComputer(options.computerId);\n return current == null || current.state === ComputerState.Deleted;\n } catch (lookup) {\n throw new AggregateError(\n [options.cause, lookup],\n 'Computer fence and deletion lookup failed',\n );\n }\n };\n\n // The provider's own session on a computer: the platform's files and seeds\n // are written through it, never through a host's grant.\n const setupSession = (args: {\n client: ComputersApiClientIface;\n info: ComputerInfoIface;\n env: () => Promise<Record<string, string>>;\n }): { sandbox: NetworkSandboxSessionIface; transport: SandboxTransportIface } => {\n const transport = createComputersApiTransport({\n client: args.client,\n computerId: args.info.id,\n });\n const sandbox = createTransportSession({\n id: args.info.id,\n description: `setup of ${args.info.name}`,\n workspaceRoot: WORKSPACE_ROOT,\n transport,\n baseEnv: args.env,\n randomUuid,\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('setup sessions expose no ports');\n },\n stop: async () => undefined,\n destroy: async () => undefined,\n },\n });\n return { sandbox, transport };\n };\n\n const buildHandle = async (args: {\n ctx: HandleContextIface;\n client: ComputersApiClientIface;\n info: ComputerInfoIface;\n env: () => Promise<Record<string, string>>;\n ports: readonly number[];\n // A viewer's handle: it changes nothing, and stopping it leaves the computer alone.\n passive: boolean;\n closeSetup?: () => void;\n }): Promise<SandboxProviderHandleIface<ComputerSandboxSessionIface>> => {\n const { client, info } = args;\n const transport = createComputersApiTransport({ client, computerId: info.id });\n let httpToken: { token: string; expiresAtMs: number } | null = null;\n const session = createTransportSession({\n id: info.id,\n description: `Final computer ${info.name}`,\n workspaceRoot: WORKSPACE_ROOT,\n transport,\n baseEnv: args.env,\n randomUuid,\n network: {\n ports: [...args.ports],\n // The computer's hostname with a preview token, which opens its HTTP ports only.\n getPortEndpoint: async ({ port, protocol }) => {\n const hostname = info.hostname ?? (await client.getComputer(info.id))?.hostname ?? null;\n if (hostname == null) throw new Error(`computer ${info.name} has no public hostname`);\n if (httpToken == null || httpToken.expiresAtMs - now() < HTTP_TOKEN_RENEW_MS) {\n const expiresAtMs = now() + HTTP_TOKEN_LIFETIME_MS;\n const token = await client.createPreviewToken({\n computerId: info.id,\n name: `agent sandbox ${args.ctx.sandboxId}`,\n expiresAt: new Date(expiresAtMs),\n });\n httpToken = { token, expiresAtMs };\n }\n const scheme = protocol === PortProtocol.Ws ? 'wss' : 'https';\n return {\n url: `${scheme}://${port === 443 ? hostname : `${hostname}:${port}`}`,\n headers: { authorization: `Bearer ${httpToken.token}` },\n };\n },\n stop: async () => {\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(info.id);\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n try {\n await client.action(info.id, 'stop');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n transport.close();\n args.closeSetup?.();\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer stop or MCP cleanup failed');\n },\n destroy: async () => {\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(info.id);\n } catch (cause) {\n failures.push(cause);\n }\n transport.close();\n try {\n await client.action(info.id, 'delete');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n },\n });\n let computerUseInstalled: boolean | null = null;\n if (!args.passive) {\n try {\n computerUseInstalled = (await client.computerUseStatus(info.id, AbortSignal.timeout(1000)))\n .installed;\n } catch {\n /* Optional discovery must never fail the sandbox. */\n }\n }\n const computerUse =\n args.passive || computerUseInstalled === false\n ? null\n : createComputerUseEndpoint({ client, computerId: info.id, cwd: WORKSPACE_ROOT });\n const closeMcp = async () => {\n try {\n await computerUse?.close();\n } catch (error) {\n log('computer_use.close_failed', {\n computerId: info.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n const closers = mcpClosers.get(info.id);\n closers?.delete(closeMcp);\n if (closers?.size === 0) mcpClosers.delete(info.id);\n };\n if (computerUse != null) {\n const closers = mcpClosers.get(info.id) ?? new Set<() => Promise<void>>();\n closers.add(closeMcp);\n mcpClosers.set(info.id, closers);\n }\n const capabilities = [SandboxCapability.Files, SandboxCapability.Ports];\n let screenAvailable = false;\n try {\n screenAvailable = (await client.screenStatus(info.id, AbortSignal.timeout(1000))).available;\n } catch {\n /* Optional desktop discovery leaves headless computers usable. */\n }\n if (screenAvailable) capabilities.push(SandboxCapability.Screen);\n if (computerUse != null) capabilities.push(SandboxCapability.ComputerUse);\n if (!args.passive)\n capabilities.push(\n SandboxCapability.Process,\n SandboxCapability.DurableProcesses,\n SandboxCapability.NetworkPolicy,\n );\n const full: ComputerSandboxSessionIface = {\n ...session,\n setNetworkPolicy: async (policy) => {\n if (args.passive) throw new Error('this sandbox handle is read-only');\n await client.setNetworkPolicy(info.id, egressFor(args.ctx, policy));\n },\n capabilities,\n };\n if (computerUse != null) full.computerUse = async () => computerUse.endpoint;\n if (screenAvailable) full.screen = (options) => client.openScreen(info.id, options);\n return {\n sandbox: args.passive ? readOnlySession(full) : full,\n onSandboxStop: async () => {\n const failures: unknown[] = [];\n for (const finish of [closeMcp, () => transport.close(), () => args.closeSetup?.()]) {\n try {\n await finish();\n } catch (cause) {\n failures.push(cause);\n }\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'Computer MCP cleanup failed');\n },\n onSandboxDelete: async () => {\n const failures: unknown[] = [];\n try {\n await closeMcp();\n } catch (cause) {\n failures.push(cause);\n }\n transport.close();\n args.closeSetup?.();\n try {\n await client.action(info.id, 'delete');\n } catch (cause) {\n if (!isComputersApiStatus(cause, 404)) failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n onRuntimeShutdown: async () => {\n try {\n await closeMcp();\n } finally {\n transport.close();\n args.closeSetup?.();\n }\n },\n };\n };\n\n // A captured base, once it is ready; a failed or expired one must be built again.\n const awaitBase = async (\n client: ComputersApiClientIface,\n baseId: string,\n key: string,\n ): Promise<ComputerBaseIface> => {\n const deadline = now() + (config.buildWaitMs ?? 30 * 60_000);\n for (;;) {\n const base = await client.getBase(baseId);\n if (base == null || base.state === ComputerBaseState.Expired) {\n throw computerSandboxError(\n 'artifact_unavailable',\n `computer base ${key} (${baseId}) is ${base == null ? 'gone' : 'expired'}; prepare it again`,\n );\n }\n if (base.state === ComputerBaseState.Ready) return base;\n if (base.state === ComputerBaseState.Failed) {\n throw computerSandboxError(\n 'build_failed',\n `computer base ${key} failed to capture: ${base.error ?? 'unknown error'}`,\n );\n }\n if (now() >= deadline) throw new Error(`computer base ${key} is still capturing`);\n await sleep(config.buildPollMs ?? 5_000);\n }\n };\n\n // The Computers API answers a computer it created or started before the\n // computer has a host, and refuses commands and file writes until it runs\n // (`autoResume: false`), so nothing touches it before this resolves. Only\n // Running counts: a paused computer still refuses them.\n const awaitComputerRunning = async (\n client: ComputersApiClientIface,\n computerId: string,\n timeoutMs: number,\n ): Promise<ComputerInfoIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = config.runningPollMs ?? 250;\n for (;;) {\n const computer = await client.getComputer(computerId);\n if (computer == null || computer.state === ComputerState.Deleted)\n throw computerSandboxError('computer_gone', `computer ${computerId} is gone`);\n if (computer.state === ComputerState.Error)\n throw computerSandboxError(\n 'computer_gone',\n `computer ${computer.name} is in the Error state`,\n );\n if (computer.state === ComputerState.Running) return computer;\n const left = deadline - now();\n if (left <= 0)\n throw computerSandboxError(\n 'computer_not_running',\n `computer ${computer.name} was not running within ${Math.round(timeoutMs / 1000)} s (it is ${ComputerState[computer.state]})`,\n );\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, RUNNING_POLL_MAX_MS);\n }\n };\n\n // Run build.steps, then build.verify, on a builder computer of the\n // environment's image, captured as a base its computers are created from.\n const build = async (args: {\n ctx: SandboxPrepareContextIface;\n image: string;\n build: ComputerBuildIface;\n machine: ComputerEnvironmentIface['machine'];\n region: string | null;\n key: string;\n }): Promise<ComputerSandboxArtifact> => {\n const { ctx, key } = args;\n const client = clientFor(ctx);\n const diskGb = args.machine?.diskGb ?? null;\n const imageVersionId = await readyImageVersion(client, {\n image: args.image,\n imageVersionId: null,\n });\n const body: CreateComputerBodyIface = {\n name: `ag-${key.slice(4, 20)}-${compactId(randomUuid()).slice(0, 8)}`,\n imageVersionId,\n ...args.machine,\n // The base is the root disk; a user volume would keep /home and /workspaces off it.\n userVolumeGb: null,\n // Nothing secret at create: the create env lands in the guest.\n env: {},\n commandMode: ComputerCommandMode.Custom,\n customCommand: 'sleep infinity',\n autoResume: false,\n idleTimeoutSeconds: BUILDER_IDLE_TIMEOUT_SECONDS,\n tags: ['final-agent-sandbox-build'],\n };\n if (args.region != null) body.regionSlug = args.region;\n // One builder per attempt: a retry after a failed build starts clean.\n const builder = await client.createComputer(\n body,\n `agent-guide-build-${(await sha256Hex(`${key}:${randomUuid()}`)).slice(0, 32)}`,\n );\n ctx.log?.(`building computer base ${key} on ${builder.name}`);\n try {\n await awaitComputerRunning(client, builder.id, runningWaitMs);\n const sandbox = setupSession({ client, info: builder, env: async () => ({}) }).sandbox;\n const prepared = await sandbox.run({\n command: '/bin/sh',\n args: ['-c', `mkdir -p ${BUILD_ROOT}\\n${homeBaselineScript()}`],\n cwd: '/',\n });\n if (prepared.exitCode !== 0) {\n throw computerSandboxError('build_failed', 'failed to record the pre-build home baseline');\n }\n const steps = [\n ...args.build.steps.map((step) => ({ step, label: 'build step' })),\n ...args.build.verify.map((step) => ({ step, label: 'verify step' })),\n ];\n for (const [index, { step, label }] of steps.entries()) {\n ctx.log?.(`${label} ${index + 1}/${steps.length}`);\n const result = await sandbox.run({\n command: `set -eu\\n${step.run}`,\n shell: true,\n cwd: BUILD_ROOT,\n timeoutMs: step.timeoutMinutes * 60_000,\n });\n if (result.exitCode !== 0) {\n throw computerSandboxError(\n 'build_failed',\n `${label} ${index + 1} failed (exit ${result.exitCode}): ${result.stderr.trim().slice(-2000)}`,\n );\n }\n }\n const homeContent = await sandbox.run({\n command: '/bin/sh',\n args: ['-c', homeContentScript({ excludedPaths: CAPTURE_SCRUBBED_PATHS })],\n cwd: '/',\n });\n if (homeContent.exitCode === HOME_BASELINE_MISSING_EXIT_CODE) {\n throw computerSandboxError(\n 'build_failed',\n `build steps removed ${HOME_BASELINE_ROOT}, which the home content check needs; leave /var/tmp/final-template-build in place.`,\n );\n }\n if (homeContent.exitCode !== 0) {\n const offending = homeContent.stdout\n .trim()\n .split('\\n')\n .filter((line) => line !== '');\n throw computerSandboxError(\n 'build_failed',\n `build steps left content under /home or /workspaces, which each computer's own volume hides: ${offending.join(', ')}. Install tools and configuration to system paths such as /usr/local, or point the tool's home there (for example CARGO_HOME=/usr/local/cargo, RUSTUP_HOME=/usr/local/rustup, NVM_DIR=/usr/local/nvm), put home files in /usr/share/final-vm/home-skel, and use /etc/gitconfig instead of git config --global.`,\n );\n }\n const captured = await client.captureComputer(builder.id, { retained: true });\n if (!captured.retained)\n throw computerSandboxError(\n 'build_failed',\n 'the Computers API did not retain the built base',\n );\n ctx.log?.(`capturing computer base ${key} as ${captured.id}`);\n const base = await awaitBase(client, captured.id, key);\n return {\n version: 1,\n key,\n image: args.image,\n diskGb: diskGb ?? base.diskGb,\n seedFiles: {},\n base: { kind: 'captured', baseId: base.id },\n };\n } finally {\n // The capture stopped the builder; it is not part of the base.\n try {\n await client.action(builder.id, 'delete');\n } catch (error) {\n log('computer_sandbox.builder_delete_failed', {\n computerId: builder.id,\n error: error instanceof Error ? error.message : String(error),\n });\n }\n }\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxEnvironmentImplementationIface<\n ComputerSandboxArtifact,\n ComputerSandboxState,\n ComputerSandboxSessionIface\n > => {\n const parsed = computerEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) {\n throw computerSandboxError(\n 'invalid_environment',\n `invalid computer environment: ${parsed.error.message}`,\n );\n }\n const options = parsed.data;\n const image = options.image ?? config.defaultImage ?? DEFAULT_COMPUTER_IMAGE;\n const machine = options.machine ?? config.machine;\n const region = options.region ?? config.regionSlug ?? null;\n // Outlasts the platform's own idle parking, so the platform parks first.\n const idleTimeoutFor = (ctx: SandboxResourceContextIface): number =>\n options.idleTimeoutSeconds ??\n (ctx.lifecycle.parkAfterIdleMs == null\n ? DEFAULT_IDLE_TIMEOUT_SECONDS\n : Math.ceil(ctx.lifecycle.parkAfterIdleMs / 1000) + IDLE_TIMEOUT_MARGIN_SECONDS);\n const seedsFor = (ctx: SandboxPrepareContextIface): Record<string, string> =>\n sandboxSeedFiles({ files: ctx.files, resources: ctx.resources });\n const keyFor = async (files: Record<string, string>): Promise<string> => {\n const baseKey = await computeComputerArtifactKey({\n image,\n build: options.build,\n diskGb: machine?.diskGb ?? null,\n });\n return Object.keys(files).length === 0\n ? baseKey\n : `${baseKey}-s${await sha256Hex(sandboxSeedIdentity(files))}`;\n };\n const retainedBase = async (\n ctx: SandboxPrepareContextIface,\n baseKey: string,\n ): Promise<ComputerSandboxArtifact | null> => {\n const cached = computerArtifactSchema.safeParse(await ctx.artifacts?.get(baseKey));\n if (!cached.success || cached.data.key !== baseKey || cached.data.base.kind !== 'captured')\n return null;\n const client = clientFor(ctx);\n const base = await client.getBase(cached.data.base.baseId);\n if (base?.state !== ComputerBaseState.Ready) return null;\n if (!base.retained && !(await client.setBaseRetention(base.id, true)).retained)\n throw computerSandboxError(\n 'build_failed',\n 'the Computers API did not retain the prepared base',\n );\n return cached.data;\n };\n\n const stateOf = (raw: JsonValue): ComputerSandboxState => {\n const state = computerStateSchema.safeParse(raw);\n if (!state.success)\n throw computerSandboxError(\n 'computer_gone',\n 'this sandbox was recorded by an older computer provider; create it again',\n );\n return state.data;\n };\n\n // The computer the state names, else one an interrupted attach created\n // under the sandbox's name; null when none exists.\n const findComputer = async (\n client: ComputersApiClientIface,\n state: ComputerSandboxState,\n ): Promise<ComputerInfoIface | null> => {\n const found = await client.getComputer(state.computerId ?? state.computerName);\n return found == null || found.state === ComputerState.Deleted ? null : found;\n };\n\n return {\n capabilities: async () => ({\n [Capability.Files]: FilesAccess.Write,\n [Capability.Shell]: ShellAccess.Execute,\n [Capability.ComputerUse]: ScreenAccess.Control,\n }),\n // The computer-use tools of this environment's image, from the Computers\n // API without a computer, so a sandbox lists them before its first attach.\n // Unknown when the API cannot tell: the first attach learns them.\n mcpCatalog: async (ctx) => {\n let tools: Awaited<ReturnType<ComputersApiClientIface['computerUseCatalog']>>;\n try {\n tools = await clientFor(ctx).computerUseCatalog({ image });\n } catch (error) {\n log('computer_use_catalog_unavailable', {\n image,\n error: error instanceof Error ? error.message : String(error),\n });\n return null;\n }\n return tools == null ? null : { computerUse: toolDescriptorsOf(tools), localMcp: null };\n },\n processes: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n if (state.computerId == null) throw new Error('this computer has not started yet');\n return clientFor(ctx).inspectProcesses(state.computerId, request);\n },\n editor: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n const computerId = state.computerId;\n if (computerId == null) {\n if (request.operation === 'available') return { available: false };\n throw new Error('this computer has not started yet');\n }\n const client = clientFor(ctx);\n const open = (expiresAtMs?: number) =>\n computerEditor({\n client,\n computerId,\n request,\n randomUuid,\n expiresAtMs,\n });\n return open();\n },\n readSnapshot: async (ctx, rawState, request) => {\n const state = stateOf(rawState);\n if (state.computerId == null) return null;\n return readComputerSnapshot({\n client: clientFor(ctx),\n computerId: state.computerId,\n request,\n });\n },\n artifactKey: async (ctx) => keyFor(seedsFor(ctx)),\n // Builds the base an environment with build steps needs, or registers an\n // image reference so its version builds ahead of the first attach (a\n // lineage needs nothing until then).\n prepare: async (ctx) => {\n const seedFiles = seedsFor(ctx);\n const key = await keyFor(seedFiles);\n const seedArtifact = await sandboxSeedArtifact(ctx, seedFiles);\n if (options.build != null && computerNeedsBuild(options.build)) {\n const baseKey = await keyFor({});\n const retained = await retainedBase(ctx, baseKey);\n if (retained != null) return { ...retained, key, ...seedArtifact };\n const built = await build({\n ctx,\n image,\n build: options.build,\n machine,\n region,\n key: baseKey,\n });\n await ctx.artifacts?.put(baseKey, built);\n return { ...built, key, ...seedArtifact };\n }\n const imageVersionId = image.startsWith(LINEAGE_PREFIX)\n ? null\n : (await registerImage(clientFor(ctx), image)).id;\n ctx.log?.(`computer base ${key} is image ${image}`);\n return {\n version: 1,\n key,\n image,\n diskGb: machine?.diskGb ?? null,\n ...seedArtifact,\n base: { kind: 'image', image, imageVersionId },\n };\n },\n // Records the computer; the first attach creates it. The setup's network\n // policy is checked now so a policy a computer cannot enforce never boots.\n create: async (ctx, { setup }) => {\n const network = computerNetworkPolicyOf(setup);\n const ports = [\n ...new Set(\n (setup?.services ?? []).flatMap((service) =>\n service.port == null ? [] : [service.port],\n ),\n ),\n ];\n return {\n state: {\n version: 2,\n computerName: await computerNameFor(ctx.sandboxId),\n computerId: null,\n network,\n ports,\n },\n region,\n };\n },\n awaitRunning: async (ctx, rawState, options) => {\n const state = stateOf(rawState);\n await awaitComputerRunning(\n clientFor(ctx),\n state.computerId ?? state.computerName,\n options.timeoutMs,\n );\n },\n attach: async (ctx, { artifact: rawArtifact, state: rawState }) => {\n const state = stateOf(rawState);\n const artifact = computerArtifactSchema.safeParse(rawArtifact);\n if (!artifact.success)\n throw computerSandboxError(\n 'artifact_unavailable',\n 'this computer base predates the current computer provider; prepare it again',\n );\n const base = artifact.data.base;\n if (computerNeedsBuild(options.build) && base.kind !== 'captured')\n throw computerSandboxError(\n 'artifact_unavailable',\n `computer base ${artifact.data.key} was prepared without its build steps; prepare it again`,\n );\n const client = clientFor(ctx);\n const env = platformProcessEnvironment(ctx, {});\n const policy = withPlatformEgressHosts(ctx, state.network);\n const egress = computerEgressOf(policy);\n const existing = await findComputer(client, state);\n if (existing?.state === ComputerState.Error)\n throw computerSandboxError(\n 'computer_gone',\n `Computer ${existing.id} (${existing.name}) is in the Error state. Recover it through the Computers API before retrying; its disk is preserved.`,\n );\n let info: ComputerInfoIface;\n let booted: boolean;\n if (existing != null) {\n info = existing;\n // A paused computer resumes with its processes; a stopped or shelved one boots.\n booted = !isRunningState(existing.state);\n if (existing.state === ComputerState.Paused) await client.action(existing.id, 'resume');\n else if (booted) await client.action(existing.id, 'start');\n } else {\n // A computer the state named but that no longer exists comes back\n // empty: the attach reports a fresh disk.\n booted = true;\n const source: Pick<CreateComputerBodyIface, 'baseId' | 'imageVersionId'> =\n base.kind === 'captured'\n ? { baseId: (await awaitBase(client, base.baseId, artifact.data.key)).id }\n : { imageVersionId: await readyImageVersion(client, base) };\n const body: CreateComputerBodyIface = {\n name: state.computerName,\n ...source,\n ...machine,\n env: {},\n autoResume: true,\n idleTimeoutSeconds: idleTimeoutFor(ctx),\n // The sandbox owns deletion; VM-level ephemeral disks cannot be paused.\n ephemeral: false,\n network: egress,\n tags: [\n 'final-agent-sandbox',\n `agent-sandbox:${ctx.sandboxId}`,\n 'agent-runtime-attachment:v1',\n 'agent-runtime-role:sandbox',\n ],\n };\n // Idle must preserve files: the sandbox is deleted only by its owner.\n body.idlePolicy = ComputerIdlePolicy.Pause;\n if (region != null) body.regionSlug = region;\n // A retry of this attach makes the same request; one after the\n // computer was deleted, or after re-registering the image, a new one.\n const idempotencyKey = `agent-sandbox-${(await sha256Hex(`${ctx.sandboxId}:${state.computerName}:${state.computerId ?? 'first'}:${source.baseId ?? source.imageVersionId}:false`)).slice(0, 32)}`;\n info = await client.createComputer(body, idempotencyKey);\n }\n const fresh = existing == null;\n log('computer_sandbox.attached', { computerId: info.id, fresh, booted });\n let cleanup: (() => Promise<void>) | null = null;\n try {\n info = await awaitComputerRunning(client, info.id, runningWaitMs);\n // A reused computer keeps whatever policy it last ran under; it gets the setup's again.\n if (!fresh) await client.setNetworkPolicy(info.id, egress);\n await reportPlatformNetworkPolicy(ctx, policy);\n const setup = setupSession({ client, info, env });\n cleanup = async () => setup.transport.close();\n await writePlatformFiles(ctx, setup.sandbox);\n // A new disk gets the workspace seeds once.\n if (fresh) {\n const seedMarker = `${WORKSPACE_ROOT}/.final/workspace-prepared/${await sha256Hex(artifact.data.key)}`;\n if ((await setup.sandbox.stat({ path: seedMarker })) == null) {\n await materializeSandboxSeeds({\n sandbox: setup.sandbox,\n root: WORKSPACE_ROOT,\n files: await sandboxSeedFilesForAttach(ctx, artifact.data),\n });\n await setup.sandbox.writeTextFile({ path: seedMarker, content: 'complete' });\n }\n }\n const handle = await buildHandle({\n ctx,\n client,\n info,\n env,\n ports: state.ports,\n passive: false,\n closeSetup: () => setup.transport.close(),\n });\n return {\n handle,\n region: info.regionSlug ?? region,\n state: { ...state, computerId: info.id },\n fresh,\n booted,\n };\n } catch (error) {\n let cause = error;\n try {\n await cleanup?.();\n } catch (cleanupError) {\n cause = new AggregateError(\n [error, cleanupError],\n 'Computer attach and setup cleanup failed',\n );\n }\n // No state reaches the caller on failure; remove only a computer this attach created.\n if (fresh) {\n try {\n await client.action(info.id, 'delete');\n } catch (cleanupError) {\n throw new AggregateError(\n [cause, cleanupError],\n `computer ${info.name} attach and cleanup failed`,\n );\n }\n }\n throw cause;\n }\n },\n attachPassive: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n const client = clientFor(ctx);\n const info = await findComputer(client, state);\n if (info == null || info.state !== ComputerState.Running)\n throw computerSandboxError(\n 'computer_not_running',\n 'computer is not running for passive access',\n );\n return buildHandle({\n ctx,\n client,\n info: await awaitComputerRunning(client, info.id, runningWaitMs),\n env: platformProcessEnvironment(ctx, {}),\n ports: state.ports,\n passive: true,\n });\n },\n // The computer pauses on its own idle policy; nothing to do.\n detach: async (_ctx, { state }) => stateOf(state),\n park: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n if (state.computerId == null) return state;\n const computerId = state.computerId;\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(computerId);\n } catch (cause) {\n failures.push(cause);\n }\n try {\n const client = clientFor(ctx);\n // Park reads the computer's state rather than trusting a pause's status\n // alone: a pause that cannot land would otherwise fail on every retry.\n let current: ComputerInfoIface | null | undefined;\n try {\n current = await client.getComputer(computerId);\n } catch (cause) {\n failures.push(cause);\n }\n if (current !== undefined && (current == null || hasNothingToPause(current.state))) {\n log('computer_sandbox.park_at_rest', {\n computerId,\n state: current?.state ?? null,\n });\n } else {\n // A paused computer is paused again: a resume may be in flight.\n try {\n await client.action(computerId, 'pause');\n } catch (error) {\n if (!pauseMayHaveSettled(error)) throw error;\n // Parked if it came to rest meanwhile (an idle pause or stop, a delete);\n // otherwise the pause did not happen and park is retried.\n const settled = await client.getComputer(computerId);\n if (\n settled != null &&\n settled.state !== ComputerState.Paused &&\n !hasNothingToPause(settled.state)\n )\n throw error;\n log('computer_sandbox.park_at_rest', {\n computerId,\n state: settled?.state ?? null,\n });\n }\n }\n } catch (cause) {\n failures.push(cause);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1) throw new AggregateError(failures, 'Computer pause failed');\n return state;\n },\n delete: async (ctx, { state: rawState }) => {\n const state = stateOf(rawState);\n const client = clientFor(ctx);\n const computer = await findComputer(client, state);\n if (computer == null) return;\n const failures: unknown[] = [];\n try {\n await closeComputerMcp(computer.id);\n } catch (cause) {\n failures.push(cause);\n }\n log('computer_sandbox.delete', { computerId: computer.id });\n try {\n await client.action(computer.id, 'delete');\n } catch (error) {\n // A conflict is done only when the computer is already gone; one\n // mid-transition (an idle pause committing) is retried.\n if (!(await deletedAfterFenceError({ client, computerId: computer.id, cause: error })))\n failures.push(error);\n }\n if (failures.length === 1) throw failures[0];\n if (failures.length > 1)\n throw new AggregateError(failures, 'Computer delete or MCP cleanup failed');\n },\n };\n };\n\n return defineSandboxProvider({\n name: COMPUTER_PROVIDER,\n stateProtocolVersion: 2,\n environment,\n });\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["COMPUTER_PROVIDER", "hex", "options"]
|
|
7
7
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ProcessInspectionRequestIface, type ProcessInspectionResultIface } from '@finalai/agent-protocol/process-inspection';
|
|
2
|
-
import { type JsonValue } from '@finalai/agent-provider';
|
|
2
|
+
import { type JsonObject, type JsonValue } from '@finalai/agent-provider';
|
|
3
3
|
import type { FinalPlatformAccessIface } from "./environment.mjs";
|
|
4
4
|
import { ComputerImageState, type ComputerBaseIface, type ComputerBrowserAccessIface, type ComputerBrowserAccessOptionsIface, type ComputerCommandMode, ComputerEgressPolicy, type ComputerIdlePolicy, type ComputerImageIface, type ComputerInfoIface, type ComputerScreenOpenOptionsIface, type ComputerSnapshotRequestIface, type ComputerSnapshotResponseIface } from '@finalai/computers';
|
|
5
5
|
import * as z from 'zod';
|
|
@@ -124,6 +124,10 @@ export interface ComputersApiClientIface {
|
|
|
124
124
|
id: string;
|
|
125
125
|
bootId: string;
|
|
126
126
|
}>;
|
|
127
|
+
computerUseCatalog(args: {
|
|
128
|
+
image: string;
|
|
129
|
+
signal?: AbortSignal;
|
|
130
|
+
}): Promise<JsonObject[] | null>;
|
|
127
131
|
setNetworkPolicy(computerId: string, policy: {
|
|
128
132
|
egress: ComputerEgressPolicy;
|
|
129
133
|
allow?: string[];
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProcessInspectionOperation
|
|
3
3
|
} from "@finalai/agent-protocol/process-inspection";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
jsonObjectSchema,
|
|
6
|
+
jsonValueSchema
|
|
7
|
+
} from "@finalai/agent-provider";
|
|
5
8
|
import {
|
|
6
9
|
computerBrowserAccessSchema,
|
|
7
10
|
ComputerImageState,
|
|
@@ -51,6 +54,7 @@ const computerResponseSchema = z.object({ computer: jsonValueSchema });
|
|
|
51
54
|
const imageResponseSchema = z.object({ image: jsonValueSchema });
|
|
52
55
|
const baseResponseSchema = z.object({ base: jsonValueSchema });
|
|
53
56
|
const imagesResponseSchema = z.object({ images: z.array(jsonValueSchema) });
|
|
57
|
+
const computerUseCatalogSchema = z.object({ tools: z.array(jsonObjectSchema).nullable() });
|
|
54
58
|
const createComputersApiClient = (args) => {
|
|
55
59
|
const request = async (req) => {
|
|
56
60
|
const send = async (refresh) => {
|
|
@@ -209,6 +213,20 @@ const createComputersApiClient = (args) => {
|
|
|
209
213
|
signal,
|
|
210
214
|
schema: z.object({ available: z.boolean(), installed: z.boolean().default(false) })
|
|
211
215
|
}),
|
|
216
|
+
computerUseCatalog: async ({ image, signal }) => {
|
|
217
|
+
try {
|
|
218
|
+
return (await request({
|
|
219
|
+
method: "GET",
|
|
220
|
+
path: "/computer-use/catalog",
|
|
221
|
+
query: { image },
|
|
222
|
+
signal,
|
|
223
|
+
schema: computerUseCatalogSchema
|
|
224
|
+
})).tools;
|
|
225
|
+
} catch (error) {
|
|
226
|
+
if (isComputersApiStatus(error, 404)) return null;
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
},
|
|
212
230
|
openComputerUse: (computerId, options) => request({
|
|
213
231
|
method: "POST",
|
|
214
232
|
path: `${computerPath(computerId)}/computer-use`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/computers-api.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n ProcessInspectionOperation,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport { jsonValueSchema, type JsonValue } from '@finalai/agent-provider';\nimport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nimport {\n computerBrowserAccessSchema,\n ComputerImageState,\n computerSnapshotResponseSchema,\n createTransport,\n normalizeComputerBase,\n normalizeComputerImage,\n normalizeComputerInfo,\n ok,\n type ComputerBaseIface,\n type ComputerBrowserAccessIface,\n type ComputerBrowserAccessOptionsIface,\n type ComputerCommandMode,\n ComputerEgressPolicy,\n type ComputerIdlePolicy,\n type ComputerImageIface,\n type ComputerInfoIface,\n type ComputerScreenOpenOptionsIface,\n type ComputerSnapshotRequestIface,\n type ComputerSnapshotResponseIface,\n} from '@finalai/computers';\nimport * as z from 'zod';\nimport { inspectComputerProcesses } from \"./computer-processes.mjs\";\n// The public Computers API (`/v1`), authenticated with the provider's\n// configured access (./access.ts). This speaks the REST surface directly, reusing\n// @finalai/computers's row normalization, because the provider needs an injected\n// fetch and per-call abort signals that the SDK's client does not take.\n\n// The Computers API access asked for before each request, and again after the\n// API rejected the last token. Null: none granted.\nexport interface ComputersApiCredentialsIface {\n computersAccess(args?: { refresh?: boolean }): Promise<FinalPlatformAccessIface | null>;\n}\n\nexport interface ComputersApiConfigIface {\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n}\n\nexport enum ComputersApiErrorCode {\n CredentialMissing = 'credential_missing',\n RequestFailed = 'request_failed',\n}\n\nexport interface ComputersApiErrorIface extends Error {\n code: ComputersApiErrorCode;\n statusCode: number | null;\n}\n\nexport const computersApiError = (\n message: string,\n statusCode: number | null,\n code: ComputersApiErrorCode = ComputersApiErrorCode.RequestFailed,\n): ComputersApiErrorIface =>\n Object.assign(new Error(message), { name: 'ComputersApiError', code, statusCode });\n\nexport const isComputersApiError = (cause: unknown): cause is ComputersApiErrorIface =>\n cause instanceof Error && 'statusCode' in cause && 'code' in cause;\n\nexport const isComputersApiStatus = (cause: unknown, ...statuses: number[]): boolean =>\n isComputersApiError(cause) && cause.statusCode != null && statuses.includes(cause.statusCode);\n\n// Exactly one of imageVersionId (a registered image) and baseId (a captured computer).\nexport interface CreateComputerBodyIface {\n name: string;\n imageVersionId?: string;\n baseId?: string;\n regionSlug?: string;\n vcpu?: number;\n memoryMb?: number;\n diskGb?: number;\n // Null: no user volume, so everything the computer writes is on the disk a capture takes.\n userVolumeGb?: number | null;\n env: Record<string, string>;\n commandMode?: ComputerCommandMode;\n customCommand?: string;\n ephemeral?: boolean;\n idleTimeoutSeconds?: number;\n idlePolicy?: ComputerIdlePolicy;\n network?: { egress: ComputerEgressPolicy; allow?: string[] };\n autoResume?: boolean;\n tags?: string[];\n}\n\nexport interface ExecBodyIface {\n autoResume?: boolean;\n command: string;\n env?: Record<string, string>;\n cwd?: string;\n user?: string;\n timeoutMs?: number;\n readyTimeoutMs?: number;\n}\n\n// `stop` shelves a computer that is not ephemeral: its disks go to storage and\n// its host is released; `start` brings it back with its files.\nexport type ComputerAction = 'start' | 'stop' | 'pause' | 'resume' | 'delete';\n\nconst outputStreamSchema = z.object({\n dataB64: z.string(),\n offset: z.number(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst processOutputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n state: z.union([z.literal('running'), z.literal('exited')]),\n result: z.object({ exitCode: z.number().nullable(), signal: z.string().nullable() }).nullable(),\n});\nexport type ComputerProcessOutputIface = z.infer<typeof processOutputSchema>;\nconst runResponseSchema = processOutputSchema.extend({\n id: z.string(),\n bootId: z.string(),\n timedOut: z.boolean(),\n});\nexport type ComputerRunResultIface = z.infer<typeof runResponseSchema>;\nconst execResponseSchema = z.object({ id: z.string(), bootId: z.string() });\nconst fileReadSchema = z.object({\n dataB64: z.string(),\n eof: z.boolean(),\n offset: z.number().optional(),\n});\nconst tokenSchema = z.object({ id: z.string(), token: z.string() });\nconst computerResponseSchema = z.object({ computer: jsonValueSchema });\nconst imageResponseSchema = z.object({ image: jsonValueSchema });\nconst baseResponseSchema = z.object({ base: jsonValueSchema });\nconst imagesResponseSchema = z.object({ images: z.array(jsonValueSchema) });\n\nexport interface ComputersApiClientIface {\n disableAutoResume(computerId: string): Promise<void>;\n inspectProcesses(\n computerId: string,\n input: ProcessInspectionRequestIface,\n ): Promise<ProcessInspectionResultIface>;\n openBrowserAccess(\n computerId: string,\n options: ComputerBrowserAccessOptionsIface,\n ): Promise<ComputerBrowserAccessIface>;\n closeBrowserAccess(computerId: string, tokenId: string): Promise<void>;\n readSnapshot(\n computerId: string,\n request: ComputerSnapshotRequestIface,\n ): Promise<ComputerSnapshotResponseIface>;\n screenStatus(computerId: string, signal?: AbortSignal): Promise<{ available: boolean }>;\n openScreen(\n computerId: string,\n options?: ComputerScreenOpenOptionsIface,\n ): Promise<{ url: string; token: string; expiresAt: string }>;\n computerUseStatus(\n computerId: string,\n signal?: AbortSignal,\n ): Promise<{ available: boolean; installed: boolean }>;\n openComputerUse(\n computerId: string,\n options: { cwd: string; readyTimeoutMs?: number; signal?: AbortSignal },\n ): Promise<{ id: string; bootId: string }>;\n setNetworkPolicy(\n computerId: string,\n policy: { egress: ComputerEgressPolicy; allow?: string[] },\n lifecycle?: { autoResume: false },\n ): Promise<void>;\n createComputer(body: CreateComputerBodyIface, idempotencyKey: string): Promise<ComputerInfoIface>;\n // Null when the computer does not exist (or was deleted).\n getComputer(idOrName: string): Promise<ComputerInfoIface | null>;\n getNetworkPolicy(\n idOrName: string,\n ): Promise<{ egress: ComputerEgressPolicy; allow: string[] } | null>;\n action(idOrName: string, action: ComputerAction): Promise<void>;\n exec(computerId: string, body: ExecBodyIface): Promise<{ id: string; bootId: string }>;\n run(\n computerId: string,\n body: ExecBodyIface & { waitMs?: number },\n ): Promise<ComputerRunResultIface>;\n output(args: {\n computerId: string;\n processId: string;\n bootId: string;\n stdoutOffset: number;\n stderrOffset: number;\n waitMs: number;\n signal?: AbortSignal;\n }): Promise<ComputerProcessOutputIface>;\n input(args: {\n computerId: string;\n processId: string;\n body: Record<string, JsonValue>;\n signal?: AbortSignal;\n }): Promise<void>;\n terminate(args: { computerId: string; processId: string; bootId: string }): Promise<void>;\n readFile(args: {\n computerId: string;\n path: string;\n offset: number;\n length: number;\n signal?: AbortSignal;\n }): Promise<{ dataB64: string; eof: boolean }>;\n writeFile(args: {\n computerId: string;\n path: string;\n dataB64: string;\n append: boolean;\n signal?: AbortSignal;\n }): Promise<void>;\n // An `http`-scoped token for one computer's ports (a preview token).\n createPreviewToken(args: { computerId: string; name: string; expiresAt: Date }): Promise<string>;\n // The organization's and the platform's image versions, newest first.\n listImages(args: { lineage: string; state: ComputerImageState }): Promise<ComputerImageIface[]>;\n // Registering a digest the organization already has returns that version.\n registerImage(args: {\n reference: string;\n registryCredentialId?: string;\n }): Promise<ComputerImageIface>;\n getImage(imageVersionId: string): Promise<ComputerImageIface>;\n // Captures a running computer as a base; the computer stops for it.\n captureComputer(idOrName: string, options?: { retained?: boolean }): Promise<ComputerBaseIface>;\n setBaseRetention(baseId: string, retained: boolean): Promise<ComputerBaseIface>;\n // Null when the base does not exist.\n getBase(baseId: string): Promise<ComputerBaseIface | null>;\n}\n\nexport const createComputersApiClient = (args: {\n config: ComputersApiConfigIface;\n // Asked for access before each request.\n credentials: ComputersApiCredentialsIface | undefined;\n}): ComputersApiClientIface => {\n const request = async <T>(req: {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n query?: Record<string, string>;\n body?: object;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n schema: z.ZodType<T>;\n }): Promise<T> => {\n const send = async (refresh: boolean) => {\n const access = await args.credentials?.computersAccess({ refresh });\n if (access == null) {\n throw computersApiError(\n 'the computer provider was granted no Computers API access',\n null,\n ComputersApiErrorCode.CredentialMissing,\n );\n }\n return createTransport({\n baseUrl: access.baseUrl,\n auth: { apiKey: access.token },\n fetch: args.config.fetch,\n requestTimeoutMs: args.config.requestTimeoutMs,\n }).request({\n method: req.method,\n path: req.path,\n query: req.query,\n jsonBody: req.body,\n headers: req.headers,\n signal: req.signal,\n });\n };\n let response = await send(false);\n // A rejected token is asked for again once, in case it expired.\n if (!response.ok && response.statusCode === 401) response = await send(true);\n if (!response.ok) throw computersApiError(response.error, response.statusCode ?? null);\n const parsed = response.data;\n const result = req.schema.safeParse(parsed);\n if (!result.success)\n throw computersApiError(`unexpected Computers API ${req.path} response`, null);\n return result.data;\n };\n\n const computerPath = (idOrName: string): string => `/computers/${encodeURIComponent(idOrName)}`;\n const toInfo = (row: JsonValue): ComputerInfoIface => {\n const info = normalizeComputerInfo(row);\n if (info == null) throw computersApiError('unexpected computer shape', null);\n return info;\n };\n const toImage = (row: JsonValue): ComputerImageIface => {\n const image = normalizeComputerImage(row);\n if (image == null) throw computersApiError('unexpected image shape', null);\n return image;\n };\n const toBase = (row: JsonValue): ComputerBaseIface => {\n const base = normalizeComputerBase(row);\n if (base == null) throw computersApiError('unexpected base shape', null);\n return base;\n };\n const anyBody = jsonValueSchema;\n\n return {\n inspectProcesses: async (computerId, input) => {\n const result = await inspectComputerProcesses({\n computerPath: computerPath(computerId),\n request: input,\n transport: {\n request: async (args) =>\n ok(\n await request({\n method: args.method,\n path: args.path,\n query: args.query,\n body: args.jsonBody,\n schema: jsonValueSchema,\n }),\n ),\n },\n });\n if (!result.ok) throw computersApiError(result.error, result.statusCode ?? null);\n return input.operation === ProcessInspectionOperation.Available && 'available' in result.data\n ? { ...result.data, canStop: true }\n : result.data;\n },\n createComputer: async (body, idempotencyKey) => {\n // The token determines the project.\n const response = await request({\n method: 'POST',\n path: '/computers',\n body,\n headers: { 'idempotency-key': idempotencyKey },\n schema: computerResponseSchema,\n });\n return toInfo(response.computer);\n },\n getNetworkPolicy: async (idOrName) => {\n const response = await request({\n method: 'GET',\n path: computerPath(idOrName),\n schema: computerResponseSchema,\n });\n const parsed = z\n .object({\n network: z.object({\n egress: z.nativeEnum(ComputerEgressPolicy),\n allow: z.array(z.string()).default([]),\n }),\n })\n .safeParse(response.computer);\n if (!parsed.success)\n throw computersApiError(\n 'The public Computers API did not return a supported network policy',\n null,\n );\n return parsed.data.network;\n },\n getComputer: async (idOrName) => {\n try {\n const response = await request({\n method: 'GET',\n path: computerPath(idOrName),\n schema: computerResponseSchema,\n });\n return toInfo(response.computer);\n } catch (error) {\n if (isComputersApiStatus(error, 404)) return null;\n throw error;\n }\n },\n action: async (idOrName, action) => {\n await request({\n method: 'POST',\n path: `${computerPath(idOrName)}/actions/${action}`,\n body: {},\n schema: anyBody,\n });\n },\n openBrowserAccess: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/browser-access`,\n body: options,\n schema: computerBrowserAccessSchema,\n }),\n closeBrowserAccess: async (computerId, tokenId) => {\n await request({\n method: 'DELETE',\n path: `${computerPath(computerId)}/browser-access/${encodeURIComponent(tokenId)}`,\n schema: anyBody,\n });\n },\n readSnapshot: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/file-snapshots/read`,\n body,\n schema: computerSnapshotResponseSchema,\n }),\n screenStatus: (computerId, signal) =>\n request({\n method: 'GET',\n path: `${computerPath(computerId)}/screen`,\n signal,\n schema: z.object({ available: z.boolean() }),\n }),\n openScreen: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/screen`,\n body: options ?? {},\n schema: z.object({ url: z.string().url(), token: z.string(), expiresAt: z.string() }),\n }),\n computerUseStatus: async (computerId, signal) =>\n request({\n method: 'GET',\n path: `${computerPath(computerId)}/computer-use`,\n signal,\n schema: z.object({ available: z.boolean(), installed: z.boolean().default(false) }),\n }),\n openComputerUse: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/computer-use`,\n body: { cwd: options.cwd, readyTimeoutMs: options.readyTimeoutMs },\n signal: options.signal,\n schema: execResponseSchema,\n }),\n disableAutoResume: async (computerId) => {\n await request({\n method: 'PATCH',\n path: computerPath(computerId),\n body: { autoResume: false },\n schema: computerResponseSchema,\n });\n },\n setNetworkPolicy: async (computerId, policy, lifecycle) => {\n await request({\n method: 'PATCH',\n path: computerPath(computerId),\n body: { network: policy, ...lifecycle },\n schema: computerResponseSchema,\n });\n },\n exec: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/exec`,\n body,\n schema: execResponseSchema,\n }),\n run: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/run`,\n body,\n schema: runResponseSchema,\n }),\n output: (o) =>\n request({\n method: 'GET',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/output`,\n query: {\n bootId: o.bootId,\n stdoutOffset: String(o.stdoutOffset),\n stderrOffset: String(o.stderrOffset),\n waitMs: String(o.waitMs),\n },\n signal: o.signal,\n schema: processOutputSchema,\n }),\n input: async (o) => {\n await request({\n method: 'POST',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/input`,\n body: o.body,\n signal: o.signal,\n schema: anyBody,\n });\n },\n terminate: async (o) => {\n await request({\n method: 'POST',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/terminate`,\n body: { bootId: o.bootId },\n schema: anyBody,\n });\n },\n readFile: async (o) => {\n const read = await request({\n method: 'GET',\n path: `${computerPath(o.computerId)}/files`,\n query: {\n path: o.path,\n offset: String(o.offset),\n length: String(o.length),\n autoResume: 'false',\n },\n signal: o.signal,\n schema: fileReadSchema,\n });\n // The API echoes the offset; a server that ignored the range would hand back the start again.\n if (o.offset > 0 && read.offset !== o.offset) {\n throw computersApiError(\n 'the Computers API ignored a ranged file read; partial contents refused',\n null,\n );\n }\n return { dataB64: read.dataB64, eof: read.eof };\n },\n writeFile: async (o) => {\n await request({\n method: 'PUT',\n path: `${computerPath(o.computerId)}/files`,\n body: { path: o.path, dataB64: o.dataB64, append: o.append },\n signal: o.signal,\n schema: anyBody,\n });\n },\n createPreviewToken: async (o) =>\n (\n await request({\n method: 'POST',\n path: '/tokens',\n body: {\n name: o.name,\n computerId: o.computerId,\n scopes: ['http'],\n expiresAt: o.expiresAt.toISOString(),\n },\n schema: tokenSchema,\n })\n ).token,\n listImages: async (o) =>\n (\n await request({\n method: 'GET',\n path: '/images',\n query: { lineage: o.lineage, state: o.state },\n schema: imagesResponseSchema,\n })\n ).images.map(toImage),\n registerImage: async (o) =>\n toImage(\n (\n await request({\n method: 'POST',\n path: '/images',\n body: o.registryCredentialId == null ? { reference: o.reference } : o,\n schema: imageResponseSchema,\n })\n ).image,\n ),\n getImage: async (imageVersionId) =>\n toImage(\n (\n await request({\n method: 'GET',\n path: `/images/${encodeURIComponent(imageVersionId)}`,\n schema: imageResponseSchema,\n })\n ).image,\n ),\n captureComputer: async (idOrName, options) =>\n toBase(\n (\n await request({\n method: 'POST',\n path: `${computerPath(idOrName)}/capture`,\n body: options ?? {},\n schema: baseResponseSchema,\n })\n ).base,\n ),\n setBaseRetention: async (baseId, retained) =>\n toBase(\n (\n await request({\n method: 'PATCH',\n path: `/bases/${encodeURIComponent(baseId)}`,\n body: { retained },\n schema: baseResponseSchema,\n })\n ).base,\n ),\n getBase: async (baseId) => {\n try {\n const response = await request({\n method: 'GET',\n path: `/bases/${encodeURIComponent(baseId)}`,\n schema: baseResponseSchema,\n });\n return toBase(response.base);\n } catch (error) {\n if (isComputersApiStatus(error, 404)) return null;\n throw error;\n }\n },\n };\n};\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,OAGK;AACP,
|
|
4
|
+
"sourcesContent": ["import {\n ProcessInspectionOperation,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport {\n jsonObjectSchema,\n jsonValueSchema,\n type JsonObject,\n type JsonValue,\n} from '@finalai/agent-provider';\nimport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nimport {\n computerBrowserAccessSchema,\n ComputerImageState,\n computerSnapshotResponseSchema,\n createTransport,\n normalizeComputerBase,\n normalizeComputerImage,\n normalizeComputerInfo,\n ok,\n type ComputerBaseIface,\n type ComputerBrowserAccessIface,\n type ComputerBrowserAccessOptionsIface,\n type ComputerCommandMode,\n ComputerEgressPolicy,\n type ComputerIdlePolicy,\n type ComputerImageIface,\n type ComputerInfoIface,\n type ComputerScreenOpenOptionsIface,\n type ComputerSnapshotRequestIface,\n type ComputerSnapshotResponseIface,\n} from '@finalai/computers';\nimport * as z from 'zod';\nimport { inspectComputerProcesses } from \"./computer-processes.mjs\";\n// The public Computers API (`/v1`), authenticated with the provider's\n// configured access (./access.ts). This speaks the REST surface directly, reusing\n// @finalai/computers's row normalization, because the provider needs an injected\n// fetch and per-call abort signals that the SDK's client does not take.\n\n// The Computers API access asked for before each request, and again after the\n// API rejected the last token. Null: none granted.\nexport interface ComputersApiCredentialsIface {\n computersAccess(args?: { refresh?: boolean }): Promise<FinalPlatformAccessIface | null>;\n}\n\nexport interface ComputersApiConfigIface {\n fetch?: typeof fetch;\n requestTimeoutMs?: number;\n}\n\nexport enum ComputersApiErrorCode {\n CredentialMissing = 'credential_missing',\n RequestFailed = 'request_failed',\n}\n\nexport interface ComputersApiErrorIface extends Error {\n code: ComputersApiErrorCode;\n statusCode: number | null;\n}\n\nexport const computersApiError = (\n message: string,\n statusCode: number | null,\n code: ComputersApiErrorCode = ComputersApiErrorCode.RequestFailed,\n): ComputersApiErrorIface =>\n Object.assign(new Error(message), { name: 'ComputersApiError', code, statusCode });\n\nexport const isComputersApiError = (cause: unknown): cause is ComputersApiErrorIface =>\n cause instanceof Error && 'statusCode' in cause && 'code' in cause;\n\nexport const isComputersApiStatus = (cause: unknown, ...statuses: number[]): boolean =>\n isComputersApiError(cause) && cause.statusCode != null && statuses.includes(cause.statusCode);\n\n// Exactly one of imageVersionId (a registered image) and baseId (a captured computer).\nexport interface CreateComputerBodyIface {\n name: string;\n imageVersionId?: string;\n baseId?: string;\n regionSlug?: string;\n vcpu?: number;\n memoryMb?: number;\n diskGb?: number;\n // Null: no user volume, so everything the computer writes is on the disk a capture takes.\n userVolumeGb?: number | null;\n env: Record<string, string>;\n commandMode?: ComputerCommandMode;\n customCommand?: string;\n ephemeral?: boolean;\n idleTimeoutSeconds?: number;\n idlePolicy?: ComputerIdlePolicy;\n network?: { egress: ComputerEgressPolicy; allow?: string[] };\n autoResume?: boolean;\n tags?: string[];\n}\n\nexport interface ExecBodyIface {\n autoResume?: boolean;\n command: string;\n env?: Record<string, string>;\n cwd?: string;\n user?: string;\n timeoutMs?: number;\n readyTimeoutMs?: number;\n}\n\n// `stop` shelves a computer that is not ephemeral: its disks go to storage and\n// its host is released; `start` brings it back with its files.\nexport type ComputerAction = 'start' | 'stop' | 'pause' | 'resume' | 'delete';\n\nconst outputStreamSchema = z.object({\n dataB64: z.string(),\n offset: z.number(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst processOutputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n state: z.union([z.literal('running'), z.literal('exited')]),\n result: z.object({ exitCode: z.number().nullable(), signal: z.string().nullable() }).nullable(),\n});\nexport type ComputerProcessOutputIface = z.infer<typeof processOutputSchema>;\nconst runResponseSchema = processOutputSchema.extend({\n id: z.string(),\n bootId: z.string(),\n timedOut: z.boolean(),\n});\nexport type ComputerRunResultIface = z.infer<typeof runResponseSchema>;\nconst execResponseSchema = z.object({ id: z.string(), bootId: z.string() });\nconst fileReadSchema = z.object({\n dataB64: z.string(),\n eof: z.boolean(),\n offset: z.number().optional(),\n});\nconst tokenSchema = z.object({ id: z.string(), token: z.string() });\nconst computerResponseSchema = z.object({ computer: jsonValueSchema });\nconst imageResponseSchema = z.object({ image: jsonValueSchema });\nconst baseResponseSchema = z.object({ base: jsonValueSchema });\nconst imagesResponseSchema = z.object({ images: z.array(jsonValueSchema) });\nconst computerUseCatalogSchema = z.object({ tools: z.array(jsonObjectSchema).nullable() });\n\nexport interface ComputersApiClientIface {\n disableAutoResume(computerId: string): Promise<void>;\n inspectProcesses(\n computerId: string,\n input: ProcessInspectionRequestIface,\n ): Promise<ProcessInspectionResultIface>;\n openBrowserAccess(\n computerId: string,\n options: ComputerBrowserAccessOptionsIface,\n ): Promise<ComputerBrowserAccessIface>;\n closeBrowserAccess(computerId: string, tokenId: string): Promise<void>;\n readSnapshot(\n computerId: string,\n request: ComputerSnapshotRequestIface,\n ): Promise<ComputerSnapshotResponseIface>;\n screenStatus(computerId: string, signal?: AbortSignal): Promise<{ available: boolean }>;\n openScreen(\n computerId: string,\n options?: ComputerScreenOpenOptionsIface,\n ): Promise<{ url: string; token: string; expiresAt: string }>;\n computerUseStatus(\n computerId: string,\n signal?: AbortSignal,\n ): Promise<{ available: boolean; installed: boolean }>;\n openComputerUse(\n computerId: string,\n options: { cwd: string; readyTimeoutMs?: number; signal?: AbortSignal },\n ): Promise<{ id: string; bootId: string }>;\n // The computer-use server's tools on computers made from `image`, known\n // without a computer: empty when it has none, null when the API cannot tell.\n computerUseCatalog(args: { image: string; signal?: AbortSignal }): Promise<JsonObject[] | null>;\n setNetworkPolicy(\n computerId: string,\n policy: { egress: ComputerEgressPolicy; allow?: string[] },\n lifecycle?: { autoResume: false },\n ): Promise<void>;\n createComputer(body: CreateComputerBodyIface, idempotencyKey: string): Promise<ComputerInfoIface>;\n // Null when the computer does not exist (or was deleted).\n getComputer(idOrName: string): Promise<ComputerInfoIface | null>;\n getNetworkPolicy(\n idOrName: string,\n ): Promise<{ egress: ComputerEgressPolicy; allow: string[] } | null>;\n action(idOrName: string, action: ComputerAction): Promise<void>;\n exec(computerId: string, body: ExecBodyIface): Promise<{ id: string; bootId: string }>;\n run(\n computerId: string,\n body: ExecBodyIface & { waitMs?: number },\n ): Promise<ComputerRunResultIface>;\n output(args: {\n computerId: string;\n processId: string;\n bootId: string;\n stdoutOffset: number;\n stderrOffset: number;\n waitMs: number;\n signal?: AbortSignal;\n }): Promise<ComputerProcessOutputIface>;\n input(args: {\n computerId: string;\n processId: string;\n body: Record<string, JsonValue>;\n signal?: AbortSignal;\n }): Promise<void>;\n terminate(args: { computerId: string; processId: string; bootId: string }): Promise<void>;\n readFile(args: {\n computerId: string;\n path: string;\n offset: number;\n length: number;\n signal?: AbortSignal;\n }): Promise<{ dataB64: string; eof: boolean }>;\n writeFile(args: {\n computerId: string;\n path: string;\n dataB64: string;\n append: boolean;\n signal?: AbortSignal;\n }): Promise<void>;\n // An `http`-scoped token for one computer's ports (a preview token).\n createPreviewToken(args: { computerId: string; name: string; expiresAt: Date }): Promise<string>;\n // The organization's and the platform's image versions, newest first.\n listImages(args: { lineage: string; state: ComputerImageState }): Promise<ComputerImageIface[]>;\n // Registering a digest the organization already has returns that version.\n registerImage(args: {\n reference: string;\n registryCredentialId?: string;\n }): Promise<ComputerImageIface>;\n getImage(imageVersionId: string): Promise<ComputerImageIface>;\n // Captures a running computer as a base; the computer stops for it.\n captureComputer(idOrName: string, options?: { retained?: boolean }): Promise<ComputerBaseIface>;\n setBaseRetention(baseId: string, retained: boolean): Promise<ComputerBaseIface>;\n // Null when the base does not exist.\n getBase(baseId: string): Promise<ComputerBaseIface | null>;\n}\n\nexport const createComputersApiClient = (args: {\n config: ComputersApiConfigIface;\n // Asked for access before each request.\n credentials: ComputersApiCredentialsIface | undefined;\n}): ComputersApiClientIface => {\n const request = async <T>(req: {\n method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';\n path: string;\n query?: Record<string, string>;\n body?: object;\n headers?: Record<string, string>;\n signal?: AbortSignal;\n schema: z.ZodType<T>;\n }): Promise<T> => {\n const send = async (refresh: boolean) => {\n const access = await args.credentials?.computersAccess({ refresh });\n if (access == null) {\n throw computersApiError(\n 'the computer provider was granted no Computers API access',\n null,\n ComputersApiErrorCode.CredentialMissing,\n );\n }\n return createTransport({\n baseUrl: access.baseUrl,\n auth: { apiKey: access.token },\n fetch: args.config.fetch,\n requestTimeoutMs: args.config.requestTimeoutMs,\n }).request({\n method: req.method,\n path: req.path,\n query: req.query,\n jsonBody: req.body,\n headers: req.headers,\n signal: req.signal,\n });\n };\n let response = await send(false);\n // A rejected token is asked for again once, in case it expired.\n if (!response.ok && response.statusCode === 401) response = await send(true);\n if (!response.ok) throw computersApiError(response.error, response.statusCode ?? null);\n const parsed = response.data;\n const result = req.schema.safeParse(parsed);\n if (!result.success)\n throw computersApiError(`unexpected Computers API ${req.path} response`, null);\n return result.data;\n };\n\n const computerPath = (idOrName: string): string => `/computers/${encodeURIComponent(idOrName)}`;\n const toInfo = (row: JsonValue): ComputerInfoIface => {\n const info = normalizeComputerInfo(row);\n if (info == null) throw computersApiError('unexpected computer shape', null);\n return info;\n };\n const toImage = (row: JsonValue): ComputerImageIface => {\n const image = normalizeComputerImage(row);\n if (image == null) throw computersApiError('unexpected image shape', null);\n return image;\n };\n const toBase = (row: JsonValue): ComputerBaseIface => {\n const base = normalizeComputerBase(row);\n if (base == null) throw computersApiError('unexpected base shape', null);\n return base;\n };\n const anyBody = jsonValueSchema;\n\n return {\n inspectProcesses: async (computerId, input) => {\n const result = await inspectComputerProcesses({\n computerPath: computerPath(computerId),\n request: input,\n transport: {\n request: async (args) =>\n ok(\n await request({\n method: args.method,\n path: args.path,\n query: args.query,\n body: args.jsonBody,\n schema: jsonValueSchema,\n }),\n ),\n },\n });\n if (!result.ok) throw computersApiError(result.error, result.statusCode ?? null);\n return input.operation === ProcessInspectionOperation.Available && 'available' in result.data\n ? { ...result.data, canStop: true }\n : result.data;\n },\n createComputer: async (body, idempotencyKey) => {\n // The token determines the project.\n const response = await request({\n method: 'POST',\n path: '/computers',\n body,\n headers: { 'idempotency-key': idempotencyKey },\n schema: computerResponseSchema,\n });\n return toInfo(response.computer);\n },\n getNetworkPolicy: async (idOrName) => {\n const response = await request({\n method: 'GET',\n path: computerPath(idOrName),\n schema: computerResponseSchema,\n });\n const parsed = z\n .object({\n network: z.object({\n egress: z.nativeEnum(ComputerEgressPolicy),\n allow: z.array(z.string()).default([]),\n }),\n })\n .safeParse(response.computer);\n if (!parsed.success)\n throw computersApiError(\n 'The public Computers API did not return a supported network policy',\n null,\n );\n return parsed.data.network;\n },\n getComputer: async (idOrName) => {\n try {\n const response = await request({\n method: 'GET',\n path: computerPath(idOrName),\n schema: computerResponseSchema,\n });\n return toInfo(response.computer);\n } catch (error) {\n if (isComputersApiStatus(error, 404)) return null;\n throw error;\n }\n },\n action: async (idOrName, action) => {\n await request({\n method: 'POST',\n path: `${computerPath(idOrName)}/actions/${action}`,\n body: {},\n schema: anyBody,\n });\n },\n openBrowserAccess: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/browser-access`,\n body: options,\n schema: computerBrowserAccessSchema,\n }),\n closeBrowserAccess: async (computerId, tokenId) => {\n await request({\n method: 'DELETE',\n path: `${computerPath(computerId)}/browser-access/${encodeURIComponent(tokenId)}`,\n schema: anyBody,\n });\n },\n readSnapshot: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/file-snapshots/read`,\n body,\n schema: computerSnapshotResponseSchema,\n }),\n screenStatus: (computerId, signal) =>\n request({\n method: 'GET',\n path: `${computerPath(computerId)}/screen`,\n signal,\n schema: z.object({ available: z.boolean() }),\n }),\n openScreen: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/screen`,\n body: options ?? {},\n schema: z.object({ url: z.string().url(), token: z.string(), expiresAt: z.string() }),\n }),\n computerUseStatus: async (computerId, signal) =>\n request({\n method: 'GET',\n path: `${computerPath(computerId)}/computer-use`,\n signal,\n schema: z.object({ available: z.boolean(), installed: z.boolean().default(false) }),\n }),\n computerUseCatalog: async ({ image, signal }) => {\n try {\n return (\n await request({\n method: 'GET',\n path: '/computer-use/catalog',\n query: { image },\n signal,\n schema: computerUseCatalogSchema,\n })\n ).tools;\n } catch (error) {\n // An API without the catalog leaves it unknown.\n if (isComputersApiStatus(error, 404)) return null;\n throw error;\n }\n },\n openComputerUse: (computerId, options) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/computer-use`,\n body: { cwd: options.cwd, readyTimeoutMs: options.readyTimeoutMs },\n signal: options.signal,\n schema: execResponseSchema,\n }),\n disableAutoResume: async (computerId) => {\n await request({\n method: 'PATCH',\n path: computerPath(computerId),\n body: { autoResume: false },\n schema: computerResponseSchema,\n });\n },\n setNetworkPolicy: async (computerId, policy, lifecycle) => {\n await request({\n method: 'PATCH',\n path: computerPath(computerId),\n body: { network: policy, ...lifecycle },\n schema: computerResponseSchema,\n });\n },\n exec: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/exec`,\n body,\n schema: execResponseSchema,\n }),\n run: (computerId, body) =>\n request({\n method: 'POST',\n path: `${computerPath(computerId)}/run`,\n body,\n schema: runResponseSchema,\n }),\n output: (o) =>\n request({\n method: 'GET',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/output`,\n query: {\n bootId: o.bootId,\n stdoutOffset: String(o.stdoutOffset),\n stderrOffset: String(o.stderrOffset),\n waitMs: String(o.waitMs),\n },\n signal: o.signal,\n schema: processOutputSchema,\n }),\n input: async (o) => {\n await request({\n method: 'POST',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/input`,\n body: o.body,\n signal: o.signal,\n schema: anyBody,\n });\n },\n terminate: async (o) => {\n await request({\n method: 'POST',\n path: `${computerPath(o.computerId)}/processes/${encodeURIComponent(o.processId)}/terminate`,\n body: { bootId: o.bootId },\n schema: anyBody,\n });\n },\n readFile: async (o) => {\n const read = await request({\n method: 'GET',\n path: `${computerPath(o.computerId)}/files`,\n query: {\n path: o.path,\n offset: String(o.offset),\n length: String(o.length),\n autoResume: 'false',\n },\n signal: o.signal,\n schema: fileReadSchema,\n });\n // The API echoes the offset; a server that ignored the range would hand back the start again.\n if (o.offset > 0 && read.offset !== o.offset) {\n throw computersApiError(\n 'the Computers API ignored a ranged file read; partial contents refused',\n null,\n );\n }\n return { dataB64: read.dataB64, eof: read.eof };\n },\n writeFile: async (o) => {\n await request({\n method: 'PUT',\n path: `${computerPath(o.computerId)}/files`,\n body: { path: o.path, dataB64: o.dataB64, append: o.append },\n signal: o.signal,\n schema: anyBody,\n });\n },\n createPreviewToken: async (o) =>\n (\n await request({\n method: 'POST',\n path: '/tokens',\n body: {\n name: o.name,\n computerId: o.computerId,\n scopes: ['http'],\n expiresAt: o.expiresAt.toISOString(),\n },\n schema: tokenSchema,\n })\n ).token,\n listImages: async (o) =>\n (\n await request({\n method: 'GET',\n path: '/images',\n query: { lineage: o.lineage, state: o.state },\n schema: imagesResponseSchema,\n })\n ).images.map(toImage),\n registerImage: async (o) =>\n toImage(\n (\n await request({\n method: 'POST',\n path: '/images',\n body: o.registryCredentialId == null ? { reference: o.reference } : o,\n schema: imageResponseSchema,\n })\n ).image,\n ),\n getImage: async (imageVersionId) =>\n toImage(\n (\n await request({\n method: 'GET',\n path: `/images/${encodeURIComponent(imageVersionId)}`,\n schema: imageResponseSchema,\n })\n ).image,\n ),\n captureComputer: async (idOrName, options) =>\n toBase(\n (\n await request({\n method: 'POST',\n path: `${computerPath(idOrName)}/capture`,\n body: options ?? {},\n schema: baseResponseSchema,\n })\n ).base,\n ),\n setBaseRetention: async (baseId, retained) =>\n toBase(\n (\n await request({\n method: 'PATCH',\n path: `/bases/${encodeURIComponent(baseId)}`,\n body: { retained },\n schema: baseResponseSchema,\n })\n ).base,\n ),\n getBase: async (baseId) => {\n try {\n const response = await request({\n method: 'GET',\n path: `/bases/${encodeURIComponent(baseId)}`,\n schema: baseResponseSchema,\n });\n return toBase(response.base);\n } catch (error) {\n if (isComputersApiStatus(error, 404)) return null;\n throw error;\n }\n },\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["ComputersApiErrorCode", "args"]
|
|
7
7
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { Capability, FilesAccess, ScreenAccess, ShellAccess } from "@finalai/agent-protocol";
|
|
2
|
-
import {
|
|
3
|
-
toolDescriptorSchema
|
|
4
|
-
} from "@finalai/agent-provider";
|
|
2
|
+
import {} from "@finalai/agent-provider";
|
|
5
3
|
import {
|
|
6
4
|
defineSandboxProvider,
|
|
7
5
|
SandboxCapability
|
|
@@ -18,6 +16,7 @@ import { DEVICE_PROVIDER, deviceEnvironmentSchema } from "./environment.mjs";
|
|
|
18
16
|
import { createMcpPipe } from "./mcp-pipe.mjs";
|
|
19
17
|
import { sandboxPathsFor, SandboxPlatform } from "./paths.mjs";
|
|
20
18
|
import { createTransportSession, readOnlySession } from "./session.mjs";
|
|
19
|
+
import { toolDescriptorsOf } from "./tool-catalog.mjs";
|
|
21
20
|
import { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from "./device-api.mjs";
|
|
22
21
|
import { DEVICE_PROVIDER as DEVICE_PROVIDER2 } from "./environment.mjs";
|
|
23
22
|
import { SandboxPlatform as SandboxPlatform2 } from "./paths.mjs";
|
|
@@ -28,13 +27,6 @@ const deviceStateSchema = z.object({
|
|
|
28
27
|
generation: z.number().int().min(0)
|
|
29
28
|
});
|
|
30
29
|
const DEVICE_COMPUTER_USE_SERVER = DEVICE_API_COMPUTER_USE_SERVER;
|
|
31
|
-
const descriptorsOf = (tools) => tools.flatMap((tool) => {
|
|
32
|
-
const parsed = toolDescriptorSchema.safeParse({
|
|
33
|
-
...tool,
|
|
34
|
-
description: tool.description ?? tool.title ?? tool.name
|
|
35
|
-
});
|
|
36
|
-
return parsed.success ? [parsed.data] : [];
|
|
37
|
-
});
|
|
38
30
|
const LEASE_RENEW_MARGIN_MS = 5 * 6e4;
|
|
39
31
|
const ONLINE_POLL_MS = 500;
|
|
40
32
|
const ONLINE_POLL_MAX_MS = 5e3;
|
|
@@ -292,10 +284,10 @@ const createDeviceSandboxProvider = (config) => {
|
|
|
292
284
|
let localKnown = local != null;
|
|
293
285
|
for (const server of local?.servers ?? []) {
|
|
294
286
|
if (server.tools == null) localKnown = false;
|
|
295
|
-
else localMcp[server.name] =
|
|
287
|
+
else localMcp[server.name] = toolDescriptorsOf(server.tools);
|
|
296
288
|
}
|
|
297
289
|
return {
|
|
298
|
-
computerUse: catalog.computerUse == null ? null :
|
|
290
|
+
computerUse: catalog.computerUse == null ? null : toolDescriptorsOf(catalog.computerUse.tools),
|
|
299
291
|
localMcp: localKnown ? localMcp : null
|
|
300
292
|
};
|
|
301
293
|
},
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/device.ts"],
|
|
4
|
-
"sourcesContent": ["import { Capability, FilesAccess, ScreenAccess, ShellAccess } from '@finalai/agent-protocol';\nimport {\n toolDescriptorSchema,\n type JsonObject,\n type JsonValue,\n type ToolDescriptorIface,\n} from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n SandboxCapability,\n type McpChannelEndpointIface,\n type NetworkSandboxSessionIface,\n type SandboxCapabilityOffer,\n type SandboxEnvironmentImplementationIface,\n type SandboxProviderContextIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxResourceContextIface,\n type SandboxSetupIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { commandEncoderFor } from \"./commands.mjs\";\nimport {\n createDeviceApiClient,\n DEVICE_API_COMPUTER_USE_SERVER,\n DeviceApiCapability,\n DeviceApiLeaseAccess,\n type DeviceApiCallerIface,\n type DeviceApiConfigIface,\n type DeviceApiCredentialsIface,\n type DeviceApiDeviceIface,\n type DeviceApiFetchIface,\n type DeviceApiLeaseIface,\n} from \"./device-api.mjs\";\nimport { DEVICE_PROVIDER, deviceEnvironmentSchema } from \"./environment.mjs\";\nimport { createMcpPipe } from \"./mcp-pipe.mjs\";\nimport { sandboxPathsFor, SandboxPlatform } from \"./paths.mjs\";\nimport { createTransportSession, readOnlySession } from \"./session.mjs\";\n\nexport { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from \"./device-api.mjs\";\nexport type { DeviceApiConfigIface, DeviceApiFetchIface } from \"./device-api.mjs\";\nexport { DEVICE_PROVIDER } from \"./environment.mjs\";\nexport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nexport { SandboxPlatform } from \"./paths.mjs\";\n\n// The `device` sandbox: a person's own computer running Final Device. The\n// provider is a client of the Device API, the Device's backend, exactly as a\n// vendor provider is a client of its vendor's API: it leases a workspace there\n// and drives files, processes, computer use and the screen through that API.\n// It knows nothing of how the Device API reaches the Device\n// (DEVICE_DIRECT_ENDPOINT.md). A Device is one person's machine: every call\n// names the user the sandbox acts for (ctx.actingUser, read per call since it\n// changes between turns), and the Device API refuses a Device that user does\n// not own. A Device takes no sandbox setup: it is the person's machine as it is.\n\nexport interface DeviceSandboxProviderConfigIface {\n // Transport options.\n api: DeviceApiConfigIface;\n // The Device API origin. Requests authenticate with the provider's platform\n // identity for it (ctx.identity), which names the acting user and which the\n // registration must be granted.\n deviceApiUrl: string;\n fetch?: DeviceApiFetchIface;\n // Device leases last at most an hour; renewed while in use.\n leaseTtlMs?: number;\n // How long attach waits for an offline Device to connect (default 0:\n // an offline Device fails at once); polled from 500 ms, doubling to 5 s.\n onlineWaitMs?: number;\n sleep?: (ms: number) => Promise<void>;\n log?: (message: string, fields?: Record<string, string | number | boolean | null>) => void;\n randomUuid?: () => string;\n now?: () => number;\n}\n\nconst deviceArtifactSchema = z.object({ version: z.literal(1), deviceId: z.string() });\n// `generation`: the last lease generation taken; 0 before the first attach.\nconst deviceStateSchema = z.object({\n version: z.literal(2),\n deviceId: z.string(),\n generation: z.number().int().min(0),\n});\nexport type DeviceSandboxArtifact = z.infer<typeof deviceArtifactSchema>;\nexport type DeviceSandboxState = z.infer<typeof deviceStateSchema>;\n\nexport const DEVICE_COMPUTER_USE_SERVER = DEVICE_API_COMPUTER_USE_SERVER;\n\nexport interface DeviceSandboxSessionIface extends NetworkSandboxSessionIface {\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type DeviceSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n>;\n\n// The Device API's recorded tools as tool descriptors; one that does not fit\n// the contract is left out.\nconst descriptorsOf = (tools: readonly JsonObject[]): ToolDescriptorIface[] =>\n tools.flatMap((tool) => {\n const parsed = toolDescriptorSchema.safeParse({\n ...tool,\n description: tool.description ?? tool.title ?? tool.name,\n });\n return parsed.success ? [parsed.data] : [];\n });\n\nconst LEASE_RENEW_MARGIN_MS = 5 * 60_000;\nconst ONLINE_POLL_MS = 500;\nconst ONLINE_POLL_MAX_MS = 5_000;\nconst MAX_LEASE_TTL_MS = 60 * 60_000;\nconst MIN_LEASE_TTL_MS = 60_000;\n\nconst platformOf = (platform: string): SandboxPlatform =>\n platform === 'windows' ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\n// A Device is the person's machine as it is: nothing is cloned, installed or\n// started on it, and its network is the person's. Notes may still describe it.\nconst refuseSetup = (setup: SandboxSetupIface | null): void => {\n if (setup == null) return;\n const parts = [\n setup.repositories.length > 0 ? 'repositories' : null,\n Object.keys(setup.variables).length > 0 ? 'variables' : null,\n setup.steps.length > 0 ? 'steps' : null,\n setup.services.length > 0 ? 'services' : null,\n Object.keys(setup.commands).length > 0 ? 'commands' : null,\n setup.network != null ? 'a network policy' : null,\n ].filter((part) => part != null);\n if (parts.length > 0)\n throw new Error(`a Final Device takes no sandbox setup (this one has ${parts.join(', ')})`);\n};\n\nexport const createDeviceSandboxProvider = (\n config: DeviceSandboxProviderConfigIface,\n): DeviceSandboxProviderIface => {\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const log = config.log ?? (() => undefined);\n const leaseTtlMs = Math.max(\n MIN_LEASE_TTL_MS,\n Math.min(config.leaseTtlMs ?? 15 * 60_000, MAX_LEASE_TTL_MS),\n );\n const sleep =\n config.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const onlineWaitMs = config.onlineWaitMs ?? 0;\n const api = createDeviceApiClient({ api: config.api, fetch: config.fetch });\n\n // A Device runs when it is connected to the Device API; nothing is leased before.\n const awaitOnline = async (\n caller: DeviceApiCallerIface,\n deviceId: string,\n timeoutMs: number,\n ): Promise<DeviceApiDeviceIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = ONLINE_POLL_MS;\n for (;;) {\n const device = await api.getDevice({ caller, deviceId });\n if (device == null) throw new Error(`device ${deviceId} was not found`);\n if (device.online) return device;\n const left = deadline - now();\n if (left <= 0) throw new Error(`${device.displayName} is not connected`);\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, ONLINE_POLL_MAX_MS);\n }\n };\n\n // An assertion for the Device API before each request, and a new one after\n // a rejection; it carries the acting user it was issued for.\n const credentialsFor = (ctx: SandboxProviderContextIface): DeviceApiCredentialsIface => ({\n deviceAccess: async (args) => ({\n baseUrl: config.deviceApiUrl,\n token: (\n await ctx.identity({ audience: config.deviceApiUrl, refresh: args?.refresh === true })\n ).token,\n }),\n });\n\n const callerFor = (ctx: SandboxProviderContextIface): DeviceApiCallerIface => ({\n organizationId: ctx.organizationId,\n credentials: credentialsFor(ctx),\n actingUser: ctx.actingUser,\n });\n\n const lease = async (args: {\n ctx: SandboxResourceContextIface;\n deviceId: string;\n afterGeneration: number;\n passive: boolean;\n }): Promise<{\n handle: SandboxProviderHandleIface<DeviceSandboxSessionIface>;\n generation: number;\n }> => {\n const { ctx } = args;\n const caller = callerFor(ctx);\n // A Device workspace is keyed by the sandbox: every attach of this sandbox\n // finds the same files, and its processes end with each lease generation.\n const bindingId = ctx.sandboxId;\n // The provider's awaitRunning, before the lease.\n const device = await awaitOnline(caller, args.deviceId, onlineWaitMs);\n // The host gates each call by its grant; the lease is the most the Device allows.\n const leaseAccess = device.writable ? DeviceApiLeaseAccess.Write : DeviceApiLeaseAccess.Read;\n const afterGeneration = args.afterGeneration === 0 ? undefined : args.afterGeneration;\n let current: DeviceApiLeaseIface = args.passive\n ? await api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n })\n : await api.lease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n ttlMs: leaseTtlMs,\n afterGeneration,\n });\n if (\n args.passive &&\n (current.deviceId !== device.id ||\n current.generation < args.afterGeneration ||\n current.expiresAtMs <= now())\n )\n throw new Error('The existing Device lease is unavailable');\n let renewing: Promise<DeviceApiLeaseIface> | null = null;\n // The current lease handle, renewed shortly before it lapses.\n const leaseHandle = async (): Promise<string> => {\n if (current.expiresAtMs - now() < LEASE_RENEW_MARGIN_MS) {\n renewing ??= (\n args.passive\n ? api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n })\n : api.renew({ caller, lease: current.lease, ttlMs: leaseTtlMs })\n ).finally(() => {\n renewing = null;\n });\n current = await renewing;\n }\n return current.lease;\n };\n let released = false;\n const release = async (): Promise<void> => {\n if (released || args.passive) return;\n released = true;\n await api.release({ caller, lease: current.lease });\n };\n\n const platform = platformOf(current.platform);\n const paths = sandboxPathsFor(platform);\n const session = createTransportSession({\n id: `${device.id}:${bindingId}`,\n description: `${device.displayName} (Final Device)`,\n workspaceRoot: current.workspaceRoot,\n transport: api.transport({ caller, lease: leaseHandle }),\n baseEnv: async () => ({}),\n randomUuid,\n paths,\n commands: commandEncoderFor(platform),\n // Lease processes end with the lease generation; a new one knows none.\n processScope: () => String(current.generation),\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('Final Device sandboxes expose no ports');\n },\n stop: release,\n destroy: release,\n },\n });\n\n const offered = new Set(current.capabilities);\n const processes = offered.has(DeviceApiCapability.Process);\n const localMcp = offered.has(DeviceApiCapability.LocalMcp);\n const computerUse = offered.has(DeviceApiCapability.ComputerUse);\n const capabilities = [SandboxCapability.Files];\n if (processes) capabilities.push(SandboxCapability.Process);\n if (processes && !args.passive) capabilities.push(SandboxCapability.DurableProcesses);\n if (localMcp) capabilities.push(SandboxCapability.LocalMcp);\n if (computerUse) capabilities.push(SandboxCapability.ComputerUse);\n if (device.screenReady) capabilities.push(SandboxCapability.Screen);\n\n // The Device's computer-use server, or one of its local MCP servers, is a byte\n // pipe in the Device API (`/v1/leases/:lease/mcp/:server/{open,write,read,close}`):\n // a channel endpoint whoever runs this handle opens in process.\n const openMcpPipe = (server: string) => {\n const clientId = randomUuid();\n const request = async (\n action: 'open' | 'write' | 'read' | 'close',\n dataBase64?: string,\n signal?: AbortSignal,\n ): Promise<string> =>\n api.pipe({\n caller,\n lease: await leaseHandle(),\n server,\n action,\n clientId,\n dataBase64,\n signal,\n });\n return createMcpPipe({\n wire: {\n open: async (signal) => {\n await request('open', undefined, signal);\n },\n write: async (data, signal) => {\n await request('write', data, signal);\n },\n read: (signal) => request('read', undefined, signal),\n close: async () => {\n await request('close').catch(() => undefined);\n },\n },\n });\n };\n const channelEndpoint = (server: string): McpChannelEndpointIface => ({\n name: server,\n connect: async () => {\n const pipe = openMcpPipe(server);\n return {\n send: (message, options) => pipe.send(message, options?.abortSignal),\n receive: (options) => pipe.receive(options?.abortSignal),\n close: () => pipe.close(),\n };\n },\n });\n const sandbox: DeviceSandboxSessionIface = { ...session, capabilities };\n // Without process access there is nothing to attach to.\n if (!processes) delete sandbox.attachProcess;\n if (computerUse) {\n sandbox.computerUse = async () => channelEndpoint(DEVICE_COMPUTER_USE_SERVER);\n }\n if (localMcp) {\n sandbox.localMcp = async () =>\n (await api.localMcpServers({ caller, lease: await leaseHandle() })).map(channelEndpoint);\n }\n if (device.screenReady) {\n sandbox.screen = (options) =>\n api.screen({\n caller,\n deviceId: device.id,\n sessionId: randomUuid(),\n viewOnly: options?.viewOnly ?? true,\n });\n }\n log('device_sandbox.attached', { deviceId: device.id, generation: current.generation });\n return {\n generation: current.generation,\n handle: {\n // A viewer's lease is the existing one: it changes nothing.\n sandbox: args.passive ? readOnlySession(sandbox) : sandbox,\n onSandboxStop: release,\n onSandboxDelete: release,\n onRuntimeShutdown: async () => undefined,\n },\n };\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxEnvironmentImplementationIface<\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n > => {\n const parsed = deviceEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) throw new Error(`invalid device environment: ${parsed.error.message}`);\n const options = parsed.data;\n // The Device the environment names; the Device API checks on every call\n // that the acting user owns it.\n const resolveDeviceId = async (caller: DeviceApiCallerIface): Promise<string> => {\n if ('deviceId' in options) return options.deviceId;\n const device = await api.resolvePairing({ caller, code: options.pairing });\n if (device == null) throw new Error('the Final Device pairing code is unknown or expired');\n return device.id;\n };\n return {\n // What a lease on this Device grants, known from the registry without\n // leasing (the Device API's rule: processes and computer use with a write\n // lease on a Device that allows processes).\n capabilities: async (ctx): Promise<SandboxCapabilityOffer> => {\n const device = await api.getDevice({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n if (device == null) return {};\n const offer: SandboxCapabilityOffer = {\n [Capability.Files]: device.writable ? FilesAccess.Write : FilesAccess.Read,\n };\n if (device.writable && device.allowProcesses) {\n offer[Capability.Shell] = ShellAccess.Execute;\n offer[Capability.ComputerUse] = ScreenAccess.Control;\n } else if (device.screenReady) offer[Capability.ComputerUse] = ScreenAccess.View;\n return offer;\n },\n features: async (ctx) => {\n const device = await api.getDevice({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n if (device == null) return null;\n const offered = [SandboxCapability.Files];\n if (device.writable && device.allowProcesses) {\n offered.push(\n SandboxCapability.Process,\n SandboxCapability.DurableProcesses,\n SandboxCapability.LocalMcp,\n SandboxCapability.ComputerUse,\n );\n }\n if (device.screenReady) offered.push(SandboxCapability.Screen);\n return offered;\n },\n // What the Device's servers last listed through the Device API (it records\n // them from the MCP pipes), so the projection lists them without leasing.\n // A Device the API has never seen list gives unknown; its first lease does.\n mcpCatalog: async (ctx) => {\n const catalog = await api.mcpCatalog({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n const local = catalog.localServers;\n const localMcp: Record<string, ToolDescriptorIface[]> = {};\n let localKnown = local != null;\n for (const server of local?.servers ?? []) {\n if (server.tools == null) localKnown = false;\n else localMcp[server.name] = descriptorsOf(server.tools);\n }\n return {\n computerUse:\n catalog.computerUse == null ? null : descriptorsOf(catalog.computerUse.tools),\n localMcp: localKnown ? localMcp : null,\n };\n },\n processes: async (ctx, rawState, request) => {\n const state = deviceStateSchema.parse(rawState);\n return api.inspectProcesses({\n caller: callerFor(ctx),\n deviceId: state.deviceId,\n bindingId: ctx.sandboxId,\n request,\n });\n },\n artifactKey: async (ctx) => `device:${await resolveDeviceId(callerFor(ctx))}`,\n prepare: async (ctx) => ({ version: 1, deviceId: await resolveDeviceId(callerFor(ctx)) }),\n create: async (_ctx, { artifact, setup }) => {\n refuseSetup(setup);\n return { state: { version: 2, deviceId: artifact.deviceId, generation: 0 } };\n },\n awaitRunning: async (ctx, rawState, { timeoutMs }) => {\n const { deviceId } = deviceStateSchema.pick({ deviceId: true }).parse(rawState);\n await awaitOnline(callerFor(ctx), deviceId, timeoutMs);\n },\n // A Device never takes a lease back at an old generation once it lapsed,\n // so every attach leases a later one, and no process from before survives.\n attach: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n const { handle, generation } = await lease({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n passive: false,\n });\n return {\n handle,\n state: { ...state, generation },\n fresh: state.generation === 0,\n booted: true,\n };\n },\n attachPassive: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await lease({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n passive: true,\n })\n ).handle;\n },\n // The lease lapses on its own; the next generation retires its processes.\n detach: async (_ctx, { state }) => deviceStateSchema.parse(state),\n park: async (_ctx, { state }) => deviceStateSchema.parse(state),\n // The Device stays the person's; its workspace for this sandbox is let go.\n delete: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n await api.releaseWorkspaceLeases({\n caller: callerFor(ctx),\n deviceId: state.deviceId,\n bindingId: ctx.sandboxId,\n });\n },\n };\n };\n\n return defineSandboxProvider({\n name: DEVICE_PROVIDER,\n stateProtocolVersion: 2,\n environment,\n });\n};\n"],
|
|
5
|
-
"mappings": "AAAA,SAAS,YAAY,aAAa,cAAc,mBAAmB;AACnE
|
|
4
|
+
"sourcesContent": ["import { Capability, FilesAccess, ScreenAccess, ShellAccess } from '@finalai/agent-protocol';\nimport { type JsonValue, type ToolDescriptorIface } from '@finalai/agent-provider';\nimport {\n defineSandboxProvider,\n SandboxCapability,\n type McpChannelEndpointIface,\n type NetworkSandboxSessionIface,\n type SandboxCapabilityOffer,\n type SandboxEnvironmentImplementationIface,\n type SandboxProviderContextIface,\n type SandboxProviderHandleIface,\n type SandboxProviderIface,\n type SandboxResourceContextIface,\n type SandboxSetupIface,\n} from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { commandEncoderFor } from \"./commands.mjs\";\nimport {\n createDeviceApiClient,\n DEVICE_API_COMPUTER_USE_SERVER,\n DeviceApiCapability,\n DeviceApiLeaseAccess,\n type DeviceApiCallerIface,\n type DeviceApiConfigIface,\n type DeviceApiCredentialsIface,\n type DeviceApiDeviceIface,\n type DeviceApiFetchIface,\n type DeviceApiLeaseIface,\n} from \"./device-api.mjs\";\nimport { DEVICE_PROVIDER, deviceEnvironmentSchema } from \"./environment.mjs\";\nimport { createMcpPipe } from \"./mcp-pipe.mjs\";\nimport { sandboxPathsFor, SandboxPlatform } from \"./paths.mjs\";\nimport { createTransportSession, readOnlySession } from \"./session.mjs\";\nimport { toolDescriptorsOf } from \"./tool-catalog.mjs\";\n\nexport { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from \"./device-api.mjs\";\nexport type { DeviceApiConfigIface, DeviceApiFetchIface } from \"./device-api.mjs\";\nexport { DEVICE_PROVIDER } from \"./environment.mjs\";\nexport type { FinalPlatformAccessIface } from \"./environment.mjs\";\nexport { SandboxPlatform } from \"./paths.mjs\";\n\n// The `device` sandbox: a person's own computer running Final Device. The\n// provider is a client of the Device API, the Device's backend, exactly as a\n// vendor provider is a client of its vendor's API: it leases a workspace there\n// and drives files, processes, computer use and the screen through that API.\n// It knows nothing of how the Device API reaches the Device\n// (DEVICE_DIRECT_ENDPOINT.md). A Device is one person's machine: every call\n// names the user the sandbox acts for (ctx.actingUser, read per call since it\n// changes between turns), and the Device API refuses a Device that user does\n// not own. A Device takes no sandbox setup: it is the person's machine as it is.\n\nexport interface DeviceSandboxProviderConfigIface {\n // Transport options.\n api: DeviceApiConfigIface;\n // The Device API origin. Requests authenticate with the provider's platform\n // identity for it (ctx.identity), which names the acting user and which the\n // registration must be granted.\n deviceApiUrl: string;\n fetch?: DeviceApiFetchIface;\n // Device leases last at most an hour; renewed while in use.\n leaseTtlMs?: number;\n // How long attach waits for an offline Device to connect (default 0:\n // an offline Device fails at once); polled from 500 ms, doubling to 5 s.\n onlineWaitMs?: number;\n sleep?: (ms: number) => Promise<void>;\n log?: (message: string, fields?: Record<string, string | number | boolean | null>) => void;\n randomUuid?: () => string;\n now?: () => number;\n}\n\nconst deviceArtifactSchema = z.object({ version: z.literal(1), deviceId: z.string() });\n// `generation`: the last lease generation taken; 0 before the first attach.\nconst deviceStateSchema = z.object({\n version: z.literal(2),\n deviceId: z.string(),\n generation: z.number().int().min(0),\n});\nexport type DeviceSandboxArtifact = z.infer<typeof deviceArtifactSchema>;\nexport type DeviceSandboxState = z.infer<typeof deviceStateSchema>;\n\nexport const DEVICE_COMPUTER_USE_SERVER = DEVICE_API_COMPUTER_USE_SERVER;\n\nexport interface DeviceSandboxSessionIface extends NetworkSandboxSessionIface {\n readonly capabilities: readonly SandboxCapability[];\n}\n\nexport type DeviceSandboxProviderIface = SandboxProviderIface<\n JsonValue,\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n>;\n\n// The Device API's recorded tools as tool descriptors; one that does not fit\n// the contract is left out.\nconst LEASE_RENEW_MARGIN_MS = 5 * 60_000;\nconst ONLINE_POLL_MS = 500;\nconst ONLINE_POLL_MAX_MS = 5_000;\nconst MAX_LEASE_TTL_MS = 60 * 60_000;\nconst MIN_LEASE_TTL_MS = 60_000;\n\nconst platformOf = (platform: string): SandboxPlatform =>\n platform === 'windows' ? SandboxPlatform.Windows : SandboxPlatform.Posix;\n\n// A Device is the person's machine as it is: nothing is cloned, installed or\n// started on it, and its network is the person's. Notes may still describe it.\nconst refuseSetup = (setup: SandboxSetupIface | null): void => {\n if (setup == null) return;\n const parts = [\n setup.repositories.length > 0 ? 'repositories' : null,\n Object.keys(setup.variables).length > 0 ? 'variables' : null,\n setup.steps.length > 0 ? 'steps' : null,\n setup.services.length > 0 ? 'services' : null,\n Object.keys(setup.commands).length > 0 ? 'commands' : null,\n setup.network != null ? 'a network policy' : null,\n ].filter((part) => part != null);\n if (parts.length > 0)\n throw new Error(`a Final Device takes no sandbox setup (this one has ${parts.join(', ')})`);\n};\n\nexport const createDeviceSandboxProvider = (\n config: DeviceSandboxProviderConfigIface,\n): DeviceSandboxProviderIface => {\n const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());\n const now = config.now ?? (() => Date.now());\n const log = config.log ?? (() => undefined);\n const leaseTtlMs = Math.max(\n MIN_LEASE_TTL_MS,\n Math.min(config.leaseTtlMs ?? 15 * 60_000, MAX_LEASE_TTL_MS),\n );\n const sleep =\n config.sleep ?? ((ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)));\n const onlineWaitMs = config.onlineWaitMs ?? 0;\n const api = createDeviceApiClient({ api: config.api, fetch: config.fetch });\n\n // A Device runs when it is connected to the Device API; nothing is leased before.\n const awaitOnline = async (\n caller: DeviceApiCallerIface,\n deviceId: string,\n timeoutMs: number,\n ): Promise<DeviceApiDeviceIface> => {\n const deadline = now() + timeoutMs;\n let pollMs = ONLINE_POLL_MS;\n for (;;) {\n const device = await api.getDevice({ caller, deviceId });\n if (device == null) throw new Error(`device ${deviceId} was not found`);\n if (device.online) return device;\n const left = deadline - now();\n if (left <= 0) throw new Error(`${device.displayName} is not connected`);\n await sleep(Math.min(pollMs, left));\n pollMs = Math.min(pollMs * 2, ONLINE_POLL_MAX_MS);\n }\n };\n\n // An assertion for the Device API before each request, and a new one after\n // a rejection; it carries the acting user it was issued for.\n const credentialsFor = (ctx: SandboxProviderContextIface): DeviceApiCredentialsIface => ({\n deviceAccess: async (args) => ({\n baseUrl: config.deviceApiUrl,\n token: (\n await ctx.identity({ audience: config.deviceApiUrl, refresh: args?.refresh === true })\n ).token,\n }),\n });\n\n const callerFor = (ctx: SandboxProviderContextIface): DeviceApiCallerIface => ({\n organizationId: ctx.organizationId,\n credentials: credentialsFor(ctx),\n actingUser: ctx.actingUser,\n });\n\n const lease = async (args: {\n ctx: SandboxResourceContextIface;\n deviceId: string;\n afterGeneration: number;\n passive: boolean;\n }): Promise<{\n handle: SandboxProviderHandleIface<DeviceSandboxSessionIface>;\n generation: number;\n }> => {\n const { ctx } = args;\n const caller = callerFor(ctx);\n // A Device workspace is keyed by the sandbox: every attach of this sandbox\n // finds the same files, and its processes end with each lease generation.\n const bindingId = ctx.sandboxId;\n // The provider's awaitRunning, before the lease.\n const device = await awaitOnline(caller, args.deviceId, onlineWaitMs);\n // The host gates each call by its grant; the lease is the most the Device allows.\n const leaseAccess = device.writable ? DeviceApiLeaseAccess.Write : DeviceApiLeaseAccess.Read;\n const afterGeneration = args.afterGeneration === 0 ? undefined : args.afterGeneration;\n let current: DeviceApiLeaseIface = args.passive\n ? await api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n })\n : await api.lease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n ttlMs: leaseTtlMs,\n afterGeneration,\n });\n if (\n args.passive &&\n (current.deviceId !== device.id ||\n current.generation < args.afterGeneration ||\n current.expiresAtMs <= now())\n )\n throw new Error('The existing Device lease is unavailable');\n let renewing: Promise<DeviceApiLeaseIface> | null = null;\n // The current lease handle, renewed shortly before it lapses.\n const leaseHandle = async (): Promise<string> => {\n if (current.expiresAtMs - now() < LEASE_RENEW_MARGIN_MS) {\n renewing ??= (\n args.passive\n ? api.recoverLease({\n caller,\n deviceId: device.id,\n sessionId: ctx.sandboxId,\n bindingId,\n access: leaseAccess,\n })\n : api.renew({ caller, lease: current.lease, ttlMs: leaseTtlMs })\n ).finally(() => {\n renewing = null;\n });\n current = await renewing;\n }\n return current.lease;\n };\n let released = false;\n const release = async (): Promise<void> => {\n if (released || args.passive) return;\n released = true;\n await api.release({ caller, lease: current.lease });\n };\n\n const platform = platformOf(current.platform);\n const paths = sandboxPathsFor(platform);\n const session = createTransportSession({\n id: `${device.id}:${bindingId}`,\n description: `${device.displayName} (Final Device)`,\n workspaceRoot: current.workspaceRoot,\n transport: api.transport({ caller, lease: leaseHandle }),\n baseEnv: async () => ({}),\n randomUuid,\n paths,\n commands: commandEncoderFor(platform),\n // Lease processes end with the lease generation; a new one knows none.\n processScope: () => String(current.generation),\n network: {\n ports: [],\n getPortEndpoint: async () => {\n throw new Error('Final Device sandboxes expose no ports');\n },\n stop: release,\n destroy: release,\n },\n });\n\n const offered = new Set(current.capabilities);\n const processes = offered.has(DeviceApiCapability.Process);\n const localMcp = offered.has(DeviceApiCapability.LocalMcp);\n const computerUse = offered.has(DeviceApiCapability.ComputerUse);\n const capabilities = [SandboxCapability.Files];\n if (processes) capabilities.push(SandboxCapability.Process);\n if (processes && !args.passive) capabilities.push(SandboxCapability.DurableProcesses);\n if (localMcp) capabilities.push(SandboxCapability.LocalMcp);\n if (computerUse) capabilities.push(SandboxCapability.ComputerUse);\n if (device.screenReady) capabilities.push(SandboxCapability.Screen);\n\n // The Device's computer-use server, or one of its local MCP servers, is a byte\n // pipe in the Device API (`/v1/leases/:lease/mcp/:server/{open,write,read,close}`):\n // a channel endpoint whoever runs this handle opens in process.\n const openMcpPipe = (server: string) => {\n const clientId = randomUuid();\n const request = async (\n action: 'open' | 'write' | 'read' | 'close',\n dataBase64?: string,\n signal?: AbortSignal,\n ): Promise<string> =>\n api.pipe({\n caller,\n lease: await leaseHandle(),\n server,\n action,\n clientId,\n dataBase64,\n signal,\n });\n return createMcpPipe({\n wire: {\n open: async (signal) => {\n await request('open', undefined, signal);\n },\n write: async (data, signal) => {\n await request('write', data, signal);\n },\n read: (signal) => request('read', undefined, signal),\n close: async () => {\n await request('close').catch(() => undefined);\n },\n },\n });\n };\n const channelEndpoint = (server: string): McpChannelEndpointIface => ({\n name: server,\n connect: async () => {\n const pipe = openMcpPipe(server);\n return {\n send: (message, options) => pipe.send(message, options?.abortSignal),\n receive: (options) => pipe.receive(options?.abortSignal),\n close: () => pipe.close(),\n };\n },\n });\n const sandbox: DeviceSandboxSessionIface = { ...session, capabilities };\n // Without process access there is nothing to attach to.\n if (!processes) delete sandbox.attachProcess;\n if (computerUse) {\n sandbox.computerUse = async () => channelEndpoint(DEVICE_COMPUTER_USE_SERVER);\n }\n if (localMcp) {\n sandbox.localMcp = async () =>\n (await api.localMcpServers({ caller, lease: await leaseHandle() })).map(channelEndpoint);\n }\n if (device.screenReady) {\n sandbox.screen = (options) =>\n api.screen({\n caller,\n deviceId: device.id,\n sessionId: randomUuid(),\n viewOnly: options?.viewOnly ?? true,\n });\n }\n log('device_sandbox.attached', { deviceId: device.id, generation: current.generation });\n return {\n generation: current.generation,\n handle: {\n // A viewer's lease is the existing one: it changes nothing.\n sandbox: args.passive ? readOnlySession(sandbox) : sandbox,\n onSandboxStop: release,\n onSandboxDelete: release,\n onRuntimeShutdown: async () => undefined,\n },\n };\n };\n\n const environment = (\n rawOptions?: JsonValue,\n ): SandboxEnvironmentImplementationIface<\n DeviceSandboxArtifact,\n DeviceSandboxState,\n DeviceSandboxSessionIface\n > => {\n const parsed = deviceEnvironmentSchema.safeParse(rawOptions ?? {});\n if (!parsed.success) throw new Error(`invalid device environment: ${parsed.error.message}`);\n const options = parsed.data;\n // The Device the environment names; the Device API checks on every call\n // that the acting user owns it.\n const resolveDeviceId = async (caller: DeviceApiCallerIface): Promise<string> => {\n if ('deviceId' in options) return options.deviceId;\n const device = await api.resolvePairing({ caller, code: options.pairing });\n if (device == null) throw new Error('the Final Device pairing code is unknown or expired');\n return device.id;\n };\n return {\n // What a lease on this Device grants, known from the registry without\n // leasing (the Device API's rule: processes and computer use with a write\n // lease on a Device that allows processes).\n capabilities: async (ctx): Promise<SandboxCapabilityOffer> => {\n const device = await api.getDevice({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n if (device == null) return {};\n const offer: SandboxCapabilityOffer = {\n [Capability.Files]: device.writable ? FilesAccess.Write : FilesAccess.Read,\n };\n if (device.writable && device.allowProcesses) {\n offer[Capability.Shell] = ShellAccess.Execute;\n offer[Capability.ComputerUse] = ScreenAccess.Control;\n } else if (device.screenReady) offer[Capability.ComputerUse] = ScreenAccess.View;\n return offer;\n },\n features: async (ctx) => {\n const device = await api.getDevice({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n if (device == null) return null;\n const offered = [SandboxCapability.Files];\n if (device.writable && device.allowProcesses) {\n offered.push(\n SandboxCapability.Process,\n SandboxCapability.DurableProcesses,\n SandboxCapability.LocalMcp,\n SandboxCapability.ComputerUse,\n );\n }\n if (device.screenReady) offered.push(SandboxCapability.Screen);\n return offered;\n },\n // What the Device's servers last listed through the Device API (it records\n // them from the MCP pipes), so the projection lists them without leasing.\n // A Device the API has never seen list gives unknown; its first lease does.\n mcpCatalog: async (ctx) => {\n const catalog = await api.mcpCatalog({\n caller: callerFor(ctx),\n deviceId: await resolveDeviceId(callerFor(ctx)),\n });\n const local = catalog.localServers;\n const localMcp: Record<string, ToolDescriptorIface[]> = {};\n let localKnown = local != null;\n for (const server of local?.servers ?? []) {\n if (server.tools == null) localKnown = false;\n else localMcp[server.name] = toolDescriptorsOf(server.tools);\n }\n return {\n computerUse:\n catalog.computerUse == null ? null : toolDescriptorsOf(catalog.computerUse.tools),\n localMcp: localKnown ? localMcp : null,\n };\n },\n processes: async (ctx, rawState, request) => {\n const state = deviceStateSchema.parse(rawState);\n return api.inspectProcesses({\n caller: callerFor(ctx),\n deviceId: state.deviceId,\n bindingId: ctx.sandboxId,\n request,\n });\n },\n artifactKey: async (ctx) => `device:${await resolveDeviceId(callerFor(ctx))}`,\n prepare: async (ctx) => ({ version: 1, deviceId: await resolveDeviceId(callerFor(ctx)) }),\n create: async (_ctx, { artifact, setup }) => {\n refuseSetup(setup);\n return { state: { version: 2, deviceId: artifact.deviceId, generation: 0 } };\n },\n awaitRunning: async (ctx, rawState, { timeoutMs }) => {\n const { deviceId } = deviceStateSchema.pick({ deviceId: true }).parse(rawState);\n await awaitOnline(callerFor(ctx), deviceId, timeoutMs);\n },\n // A Device never takes a lease back at an old generation once it lapsed,\n // so every attach leases a later one, and no process from before survives.\n attach: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n const { handle, generation } = await lease({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n passive: false,\n });\n return {\n handle,\n state: { ...state, generation },\n fresh: state.generation === 0,\n booted: true,\n };\n },\n attachPassive: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n return (\n await lease({\n ctx,\n deviceId: state.deviceId,\n afterGeneration: state.generation,\n passive: true,\n })\n ).handle;\n },\n // The lease lapses on its own; the next generation retires its processes.\n detach: async (_ctx, { state }) => deviceStateSchema.parse(state),\n park: async (_ctx, { state }) => deviceStateSchema.parse(state),\n // The Device stays the person's; its workspace for this sandbox is let go.\n delete: async (ctx, { state: rawState }) => {\n const state = deviceStateSchema.parse(rawState);\n await api.releaseWorkspaceLeases({\n caller: callerFor(ctx),\n deviceId: state.deviceId,\n bindingId: ctx.sandboxId,\n });\n },\n };\n };\n\n return defineSandboxProvider({\n name: DEVICE_PROVIDER,\n stateProtocolVersion: 2,\n environment,\n });\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["DEVICE_PROVIDER", "SandboxPlatform"]
|
|
7
7
|
}
|
|
@@ -10,6 +10,7 @@ export interface McpPipeWireIface {
|
|
|
10
10
|
read(signal?: AbortSignal): Promise<string>;
|
|
11
11
|
close(): Promise<void>;
|
|
12
12
|
}
|
|
13
|
+
export declare const utf8Writes: (bytes: Uint8Array, maxBytes: number) => Uint8Array[];
|
|
13
14
|
export declare const createMcpPipe: (args: {
|
|
14
15
|
wire: McpPipeWireIface;
|
|
15
16
|
}) => McpPipeIface;
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { jsonValueSchema } from "@finalai/agent-provider";
|
|
2
2
|
import { decodeBase64, encodeBase64 } from "./bytes.mjs";
|
|
3
3
|
const MAX_WRITE_BYTES = 64 * 1024;
|
|
4
|
+
const utf8Writes = (bytes, maxBytes) => {
|
|
5
|
+
const writes = [];
|
|
6
|
+
let start = 0;
|
|
7
|
+
while (start < bytes.byteLength) {
|
|
8
|
+
let end = Math.min(start + maxBytes, bytes.byteLength);
|
|
9
|
+
let boundary = end;
|
|
10
|
+
while (boundary > start && boundary < bytes.byteLength && ((bytes[boundary] ?? 0) & 192) === 128)
|
|
11
|
+
boundary -= 1;
|
|
12
|
+
if (boundary > start) end = boundary;
|
|
13
|
+
writes.push(bytes.subarray(start, end));
|
|
14
|
+
start = end;
|
|
15
|
+
}
|
|
16
|
+
return writes;
|
|
17
|
+
};
|
|
4
18
|
const createMcpPipe = (args) => {
|
|
5
19
|
let opened = null;
|
|
6
20
|
const decoder = new TextDecoder();
|
|
@@ -32,8 +46,8 @@ const createMcpPipe = (args) => {
|
|
|
32
46
|
await ensureOpen(signal);
|
|
33
47
|
const bytes = new TextEncoder().encode(`${JSON.stringify(message)}
|
|
34
48
|
`);
|
|
35
|
-
for (
|
|
36
|
-
await args.wire.write(encodeBase64(
|
|
49
|
+
for (const write of utf8Writes(bytes, MAX_WRITE_BYTES)) {
|
|
50
|
+
await args.wire.write(encodeBase64(write), signal);
|
|
37
51
|
}
|
|
38
52
|
};
|
|
39
53
|
return {
|
|
@@ -50,6 +64,7 @@ const createMcpPipe = (args) => {
|
|
|
50
64
|
};
|
|
51
65
|
};
|
|
52
66
|
export {
|
|
53
|
-
createMcpPipe
|
|
67
|
+
createMcpPipe,
|
|
68
|
+
utf8Writes
|
|
54
69
|
};
|
|
55
70
|
//# sourceMappingURL=mcp-pipe.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/mcp-pipe.ts"],
|
|
4
|
-
"sourcesContent": ["import type { JsonValue } from '@finalai/agent-provider';\nimport { jsonValueSchema } from '@finalai/agent-provider';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\n\n// An MCP server reached as an open/write/read/close byte pipe (the Device API's\n// `/v1/leases/:lease/mcp/:server/*`), framed as newline-delimited JSON-RPC. The\n// device handle hands it over as an MCP channel (McpChannelIface), which the\n// session service's MCP projection drives like any sandbox-hosted server.\n\nexport interface McpPipeIface {\n // Sends one JSON-RPC message (request, response or notification).\n send(message: JsonValue, signal?: AbortSignal): Promise<void>;\n // Messages the server sent since the last call; empty when none arrived.\n receive(signal?: AbortSignal): Promise<JsonValue[]>;\n close(): Promise<void>;\n}\n\nexport interface McpPipeWireIface {\n open(signal?: AbortSignal): Promise<void>;\n // Base64 bytes in; resolves once written.\n write(dataBase64: string, signal?: AbortSignal): Promise<void>;\n // Base64 bytes out; empty when nothing arrived before the wire's idle wait.\n read(signal?: AbortSignal): Promise<string>;\n close(): Promise<void>;\n}\n\n// Writes are clicks and keystrokes: keep them small and never replay one.\nconst MAX_WRITE_BYTES = 64 * 1024;\n\nexport const createMcpPipe = (args: { wire: McpPipeWireIface }): McpPipeIface => {\n let opened: Promise<void> | null = null;\n const decoder = new TextDecoder();\n let partial = '';\n const inbox: JsonValue[] = [];\n const ensureOpen = (signal?: AbortSignal): Promise<void> => {\n opened ??= args.wire.open(signal).catch((cause: unknown) => {\n opened = null;\n throw cause;\n });\n return opened;\n };\n\n const pull = async (signal?: AbortSignal): Promise<void> => {\n await ensureOpen(signal);\n const data = await args.wire.read(signal);\n if (data === '') return;\n const lines = (partial + decoder.decode(decodeBase64(data), { stream: true })).split('\\n');\n partial = lines.pop() ?? '';\n for (const line of lines) {\n if (line.trim() === '') continue;\n try {\n const parsed = jsonValueSchema.safeParse(JSON.parse(line));\n if (parsed.success) inbox.push(parsed.data);\n } catch {\n // Not JSON-RPC (server log noise on stdout); dropped.\n }\n }\n };\n\n const send = async (message: JsonValue, signal?: AbortSignal): Promise<void> => {\n await ensureOpen(signal);\n const bytes = new TextEncoder().encode(`${JSON.stringify(message)}\\n`);\n for (
|
|
5
|
-
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,cAAc,oBAAoB;AAyB3C,MAAM,kBAAkB,KAAK;
|
|
4
|
+
"sourcesContent": ["import type { JsonValue } from '@finalai/agent-provider';\nimport { jsonValueSchema } from '@finalai/agent-provider';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\n\n// An MCP server reached as an open/write/read/close byte pipe (the Device API's\n// `/v1/leases/:lease/mcp/:server/*`), framed as newline-delimited JSON-RPC. The\n// device handle hands it over as an MCP channel (McpChannelIface), which the\n// session service's MCP projection drives like any sandbox-hosted server.\n\nexport interface McpPipeIface {\n // Sends one JSON-RPC message (request, response or notification).\n send(message: JsonValue, signal?: AbortSignal): Promise<void>;\n // Messages the server sent since the last call; empty when none arrived.\n receive(signal?: AbortSignal): Promise<JsonValue[]>;\n close(): Promise<void>;\n}\n\nexport interface McpPipeWireIface {\n open(signal?: AbortSignal): Promise<void>;\n // Base64 bytes in; resolves once written.\n write(dataBase64: string, signal?: AbortSignal): Promise<void>;\n // Base64 bytes out; empty when nothing arrived before the wire's idle wait.\n read(signal?: AbortSignal): Promise<string>;\n close(): Promise<void>;\n}\n\n// Writes are clicks and keystrokes: keep them small and never replay one.\nconst MAX_WRITE_BYTES = 64 * 1024;\n\n// Splits UTF-8 bytes into writes of at most `maxBytes`, each ending on a\n// character boundary: a receiver may decode every write on its own.\nexport const utf8Writes = (bytes: Uint8Array, maxBytes: number): Uint8Array[] => {\n const writes: Uint8Array[] = [];\n let start = 0;\n while (start < bytes.byteLength) {\n let end = Math.min(start + maxBytes, bytes.byteLength);\n // Back off continuation bytes (10xxxxxx) so the next write starts a character.\n let boundary = end;\n while (\n boundary > start &&\n boundary < bytes.byteLength &&\n ((bytes[boundary] ?? 0) & 0xc0) === 0x80\n )\n boundary -= 1;\n if (boundary > start) end = boundary;\n writes.push(bytes.subarray(start, end));\n start = end;\n }\n return writes;\n};\n\nexport const createMcpPipe = (args: { wire: McpPipeWireIface }): McpPipeIface => {\n let opened: Promise<void> | null = null;\n const decoder = new TextDecoder();\n let partial = '';\n const inbox: JsonValue[] = [];\n const ensureOpen = (signal?: AbortSignal): Promise<void> => {\n opened ??= args.wire.open(signal).catch((cause: unknown) => {\n opened = null;\n throw cause;\n });\n return opened;\n };\n\n const pull = async (signal?: AbortSignal): Promise<void> => {\n await ensureOpen(signal);\n const data = await args.wire.read(signal);\n if (data === '') return;\n const lines = (partial + decoder.decode(decodeBase64(data), { stream: true })).split('\\n');\n partial = lines.pop() ?? '';\n for (const line of lines) {\n if (line.trim() === '') continue;\n try {\n const parsed = jsonValueSchema.safeParse(JSON.parse(line));\n if (parsed.success) inbox.push(parsed.data);\n } catch {\n // Not JSON-RPC (server log noise on stdout); dropped.\n }\n }\n };\n\n const send = async (message: JsonValue, signal?: AbortSignal): Promise<void> => {\n await ensureOpen(signal);\n const bytes = new TextEncoder().encode(`${JSON.stringify(message)}\\n`);\n for (const write of utf8Writes(bytes, MAX_WRITE_BYTES)) {\n await args.wire.write(encodeBase64(write), signal);\n }\n };\n\n return {\n send,\n receive: async (signal) => {\n await pull(signal);\n return inbox.splice(0);\n },\n close: async () => {\n if (opened == null) return;\n opened = null;\n await args.wire.close();\n },\n };\n};\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,uBAAuB;AAChC,SAAS,cAAc,oBAAoB;AAyB3C,MAAM,kBAAkB,KAAK;AAItB,MAAM,aAAa,CAAC,OAAmB,aAAmC;AAC/E,QAAM,SAAuB,CAAC;AAC9B,MAAI,QAAQ;AACZ,SAAO,QAAQ,MAAM,YAAY;AAC/B,QAAI,MAAM,KAAK,IAAI,QAAQ,UAAU,MAAM,UAAU;AAErD,QAAI,WAAW;AACf,WACE,WAAW,SACX,WAAW,MAAM,gBACf,MAAM,QAAQ,KAAK,KAAK,SAAU;AAEpC,kBAAY;AACd,QAAI,WAAW,MAAO,OAAM;AAC5B,WAAO,KAAK,MAAM,SAAS,OAAO,GAAG,CAAC;AACtC,YAAQ;AAAA,EACV;AACA,SAAO;AACT;AAEO,MAAM,gBAAgB,CAAC,SAAmD;AAC/E,MAAI,SAA+B;AACnC,QAAM,UAAU,IAAI,YAAY;AAChC,MAAI,UAAU;AACd,QAAM,QAAqB,CAAC;AAC5B,QAAM,aAAa,CAAC,WAAwC;AAC1D,eAAW,KAAK,KAAK,KAAK,MAAM,EAAE,MAAM,CAAC,UAAmB;AAC1D,eAAS;AACT,YAAM;AAAA,IACR,CAAC;AACD,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OAAO,WAAwC;AAC1D,UAAM,WAAW,MAAM;AACvB,UAAM,OAAO,MAAM,KAAK,KAAK,KAAK,MAAM;AACxC,QAAI,SAAS,GAAI;AACjB,UAAM,SAAS,UAAU,QAAQ,OAAO,aAAa,IAAI,GAAG,EAAE,QAAQ,KAAK,CAAC,GAAG,MAAM,IAAI;AACzF,cAAU,MAAM,IAAI,KAAK;AACzB,eAAW,QAAQ,OAAO;AACxB,UAAI,KAAK,KAAK,MAAM,GAAI;AACxB,UAAI;AACF,cAAM,SAAS,gBAAgB,UAAU,KAAK,MAAM,IAAI,CAAC;AACzD,YAAI,OAAO,QAAS,OAAM,KAAK,OAAO,IAAI;AAAA,MAC5C,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAEA,QAAM,OAAO,OAAO,SAAoB,WAAwC;AAC9E,UAAM,WAAW,MAAM;AACvB,UAAM,QAAQ,IAAI,YAAY,EAAE,OAAO,GAAG,KAAK,UAAU,OAAO,CAAC;AAAA,CAAI;AACrE,eAAW,SAAS,WAAW,OAAO,eAAe,GAAG;AACtD,YAAM,KAAK,KAAK,MAAM,aAAa,KAAK,GAAG,MAAM;AAAA,IACnD;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA,SAAS,OAAO,WAAW;AACzB,YAAM,KAAK,MAAM;AACjB,aAAO,MAAM,OAAO,CAAC;AAAA,IACvB;AAAA,IACA,OAAO,YAAY;AACjB,UAAI,UAAU,KAAM;AACpB,eAAS;AACT,YAAM,KAAK,KAAK,MAAM;AAAA,IACxB;AAAA,EACF;AACF;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -165,6 +165,8 @@ const createFakeComputersApi = (args = {}) => {
|
|
|
165
165
|
if (key != null) byIdempotency.set(key, id);
|
|
166
166
|
return json({ computer: wire(computer2) });
|
|
167
167
|
}
|
|
168
|
+
if (request.method === "GET" && path === "/computer-use/catalog" && args.computerUseCatalog != null)
|
|
169
|
+
return json({ tools: args.computerUseCatalog[url.searchParams.get("image") ?? ""] ?? null });
|
|
168
170
|
if (request.method === "GET" && path === "/images") {
|
|
169
171
|
const lineage = url.searchParams.get("lineage");
|
|
170
172
|
const state = url.searchParams.get("state");
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../../src/sandboxes/testing/fake-backends.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n jsonObjectSchema,\n jsonValueSchema,\n type JsonObject,\n type JsonValue,\n} from '@finalai/agent-provider';\nimport { ComputerEgressPolicy } from '@finalai/computers';\nimport { posix } from 'node:path';\nimport * as z from 'zod';\nimport { concatBytes, decodeBase64, encodeBase64 } from \"../bytes.mjs\";\nimport { createFakeMachine, readFakeOutput, type FakeMachineIface } from \"./fake-machine.mjs\";\n\n// A fake public Computers API (`/v1` over fetch, bearer token), backed by\n// in-memory machines.\n\nexport interface FakeComputerIface {\n id: string;\n name: string;\n state: number;\n body: JsonObject;\n machine: FakeMachineIface;\n}\n\nexport interface FakeImageIface {\n id: string;\n source: 'platform' | 'customer';\n reference: string;\n lineage: string;\n state: 'pending' | 'building' | 'ready' | 'failed' | 'expired';\n error: string | null;\n}\n\nexport interface FakeBaseIface {\n id: string;\n computerId: string;\n state: 'capturing' | 'ready' | 'failed' | 'expired';\n error: string | null;\n retained: boolean;\n}\n\nexport interface FakeComputersApiIface {\n fetch: typeof fetch;\n computers: Map<string, FakeComputerIface>;\n images: Map<string, FakeImageIface>;\n bases: Map<string, FakeBaseIface>;\n // Base reads a fresh capture answers `capturing` before it settles.\n baseCaptureReads: { count: number };\n // Set: the next captures settle `failed` with this error instead of `ready`.\n captureFailure: { error: string | null };\n requests: { method: string; path: string; body: JsonValue; headers: Headers }[];\n actions: { computerId: string; action: string }[];\n // Actions answered 409 (a conflicting transition) without changing the computer.\n actionConflicts: Set<string>;\n // Actions answered with this status (a failed host command) without changing the computer.\n actionFailures: Map<string, number>;\n // Computer reads a stopped computer answers `stopped` before it is shelved.\n shelveReads: { count: number };\n // Image reads a fresh registration answers `building` before it is ready.\n imageBuildReads: { count: number };\n // Computer reads a created or started computer answers `pending` (a resumed\n // one `resuming`) before it runs; until then commands and files answer 409.\n bootReads: { count: number };\n computerByName(name: string): FakeComputerIface | undefined;\n}\n\nconst STATE = {\n Pending: 1,\n Running: 3,\n Paused: 4,\n Stopped: 5,\n Resuming: 6,\n Error: 8,\n Deleted: 9,\n Shelved: 10,\n} as const;\nconst NOT_RUNNING = 'Computer is not running; resume it explicitly before this operation';\nexport const FAKE_COMPUTERS_API_KEY = 'fk_org_api_key';\nexport const FAKE_PLATFORM_SANDBOX_IMAGE = 'cimv_0190e0000000700080000000000001';\n\nconst json = (body: JsonValue, status = 200): Response =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });\n\n// What POST /v1/computers accepts; anything else, such as image, lineage,\n// projectArtifact or platform-only policies, is refused so a test fails when the\n// provider asks for it.\nconst createComputerSchema = z.strictObject({\n name: z.string().optional(),\n regionSlug: z.string().optional(),\n imageVersionId: z.string().startsWith('cimv_').optional(),\n baseId: z.string().startsWith('part_').optional(),\n idlePolicy: z.enum(['shelve', 'pause', 'delete']).optional(),\n network: z\n .strictObject({\n egress: z.nativeEnum(ComputerEgressPolicy),\n allow: z.array(z.string()).optional(),\n })\n .optional(),\n vcpu: z.number().optional(),\n memoryMb: z.number().optional(),\n diskGb: z.number().optional(),\n userVolumeGb: z.number().nullable().optional(),\n env: z.record(z.string(), z.string()).optional(),\n setupScript: z.string().optional(),\n commandMode: z.number().optional(),\n customCommand: z.string().optional(),\n httpPort: z.number().optional(),\n httpPublic: z.boolean().optional(),\n ephemeral: z.boolean().optional(),\n idleTimeoutSeconds: z.number().optional(),\n autoResume: z.boolean().optional(),\n tags: z.array(z.string()).optional(),\n comment: z.string().optional(),\n});\n\nexport const createFakeComputersApi = (\n args: {\n machineFor?: (computer: { id: string; name: string }) => FakeMachineIface;\n computerUseAvailable?: boolean;\n screenAvailable?: boolean;\n } = {},\n): FakeComputersApiIface => {\n const computers = new Map<string, FakeComputerIface>();\n const images = new Map<string, FakeImageIface>([\n [\n FAKE_PLATFORM_SANDBOX_IMAGE,\n {\n id: FAKE_PLATFORM_SANDBOX_IMAGE,\n source: 'platform',\n reference: 'ghcr.io/final/sandbox:release',\n lineage: 'sandbox',\n state: 'ready',\n error: null,\n },\n ],\n ]);\n const requests: FakeComputersApiIface['requests'] = [];\n const actions: FakeComputersApiIface['actions'] = [];\n const actionConflicts = new Set<string>();\n const actionFailures = new Map<string, number>();\n const shelveReads = { count: 0 };\n const shelving = new Map<string, number>();\n const imageBuildReads = { count: 1 };\n const bootReads = { count: 1 };\n const booting = new Map<string, number>();\n const boot = (computer: FakeComputerIface, state: number) => {\n if (bootReads.count <= 0) {\n computer.state = STATE.Running;\n return;\n }\n computer.state = state;\n booting.set(computer.id, bootReads.count);\n };\n const imageReads = new Map<string, number>();\n const bases = new Map<string, FakeBaseIface>();\n const baseCaptureReads = { count: 1 };\n const captureFailure: FakeComputersApiIface['captureFailure'] = { error: null };\n const captureErrors = new Map<string, string>();\n const baseReads = new Map<string, number>();\n let computerCount = 0;\n const byIdempotency = new Map<string, string>();\n\n const wire = (computer: FakeComputerIface) => ({\n id: computer.id,\n name: computer.name,\n state: computer.state,\n network: computer.body.network ?? { egress: ComputerEgressPolicy.Internet },\n imageVersionId: z\n .string()\n .nullable()\n .catch(null)\n .parse(computer.body.imageVersionId ?? null),\n // The token's project: the API infers it.\n projectId: 'prj_fake',\n hostname: `${computer.name}-k3p9x7qd.virtual-machine.lax-2.example`,\n tags: [],\n });\n const imageWire = (image: FakeImageIface) => ({\n ...image,\n digest: `sha256:${image.id}`,\n sizes: ['standard'],\n registryCredentialId: null,\n createdAt: null,\n readyAt: null,\n lastUsedAt: null,\n });\n const baseWire = (base: FakeBaseIface) => ({\n ...base,\n image: 'ghcr.io/final/sandbox:release',\n digest: `sha256:${'b'.repeat(64)}`,\n diskGb: 20,\n createdAt: null,\n readyAt: null,\n lastUsedAt: null,\n });\n const find = (idOrName: string): FakeComputerIface | undefined =>\n computers.get(idOrName) ??\n [...computers.values()].find(\n (computer) => computer.name === idOrName && computer.state !== STATE.Deleted,\n );\n\n const handle = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const text = request.method === 'GET' ? '' : await request.text();\n const body = text === '' ? null : jsonValueSchema.parse(JSON.parse(text));\n requests.push({ method: request.method, path: url.pathname, body, headers: request.headers });\n if (!url.pathname.startsWith('/v1/')) return json({ error: 'not found' }, 404);\n if (request.headers.get('authorization') !== `Bearer ${FAKE_COMPUTERS_API_KEY}`) {\n return json({ error: 'unauthorized' }, 401);\n }\n const path = url.pathname.slice('/v1'.length);\n if (request.method === 'POST' && path === '/computers') {\n const parsed = createComputerSchema.safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n if ((parsed.data.imageVersionId == null) === (parsed.data.baseId == null)) {\n return json({ error: 'pass exactly one of imageVersionId and baseId' }, 400);\n }\n if (parsed.data.imageVersionId != null) {\n const image = images.get(parsed.data.imageVersionId);\n if (image == null) return json({ error: 'image version not found' }, 404);\n if (image.state !== 'ready') return json({ error: `image version is ${image.state}` }, 409);\n }\n if (parsed.data.baseId != null) {\n const base = bases.get(parsed.data.baseId);\n if (base == null) return json({ error: 'base not found' }, 404);\n if (base.state !== 'ready') return json({ error: `base is ${base.state}` }, 409);\n }\n const key = request.headers.get('idempotency-key');\n if (parsed.data.ephemeral === true && parsed.data.idlePolicy === 'pause')\n return json({ error: 'ephemeral VMs are always deleted when idle' }, 400);\n const existing = key == null ? undefined : computers.get(byIdempotency.get(key) ?? '');\n if (existing != null) return json({ computer: wire(existing) });\n computerCount += 1;\n const id = `comp_0190a0000000700080000000${String(computerCount).padStart(4, '0')}`;\n const name = parsed.data.name ?? `computer-${computerCount}`;\n const computer: FakeComputerIface = {\n id,\n name,\n state: STATE.Pending,\n body: jsonObjectSchema.parse(body),\n machine: args.machineFor?.({ id, name }) ?? createFakeMachine(),\n };\n boot(computer, STATE.Pending);\n computers.set(id, computer);\n if (key != null) byIdempotency.set(key, id);\n return json({ computer: wire(computer) });\n }\n if (request.method === 'GET' && path === '/images') {\n const lineage = url.searchParams.get('lineage');\n const state = url.searchParams.get('state');\n const matching = [...images.values()]\n .filter((image) => lineage == null || image.lineage === lineage)\n .filter((image) => state == null || image.state === state)\n .reverse();\n return json({ images: matching.map(imageWire) });\n }\n if (request.method === 'POST' && path === '/images') {\n const parsed = z\n .strictObject({\n reference: z.string(),\n registryCredentialId: z.string().optional(),\n sizes: z.array(z.string()).optional(),\n })\n .safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n const known = [...images.values()].find(\n (image) =>\n image.reference === parsed.data.reference &&\n (image.state === 'pending' || image.state === 'building' || image.state === 'ready'),\n );\n if (known != null) return json({ image: imageWire(known) });\n const id = `cimv_0190f0000000700080000000${String(images.size + 1).padStart(4, '0')}`;\n const image: FakeImageIface = {\n id,\n source: 'customer',\n reference: parsed.data.reference,\n lineage: parsed.data.reference,\n state: 'building',\n error: null,\n };\n images.set(id, image);\n return json({ image: imageWire(image) }, 201);\n }\n const imageMatch = /^\\/images\\/([^/]+)$/.exec(path);\n if (request.method === 'GET' && imageMatch != null) {\n const image = images.get(decodeURIComponent(imageMatch[1] ?? ''));\n if (image == null) return json({ error: 'image not found' }, 404);\n const reads = (imageReads.get(image.id) ?? 0) + 1;\n imageReads.set(image.id, reads);\n if (image.state === 'building' && reads > imageBuildReads.count) image.state = 'ready';\n return json({ image: imageWire(image) });\n }\n if (request.method === 'POST' && path === '/tokens') {\n const parsed = z\n .strictObject({\n name: z.string(),\n computerId: z.string().startsWith('comp_').optional(),\n scopes: z.array(z.string()).optional(),\n expiresAt: z.string().optional(),\n })\n .safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n return json({ id: 'ctok_1', token: 'fvm1.http-token' });\n }\n const baseMatch = /^\\/bases\\/([^/]+)$/.exec(path);\n if (request.method === 'PATCH' && baseMatch != null) {\n const base = bases.get(decodeURIComponent(baseMatch[1] ?? ''));\n if (base == null) return json({ error: 'base not found' }, 404);\n const retained = z.object({ retained: z.boolean() }).parse(body);\n base.retained = retained.retained;\n return json({ base: baseWire(base) });\n }\n if (request.method === 'GET' && baseMatch != null) {\n const base = bases.get(decodeURIComponent(baseMatch[1] ?? ''));\n if (base == null) return json({ error: 'base not found' }, 404);\n const reads = (baseReads.get(base.id) ?? 0) + 1;\n baseReads.set(base.id, reads);\n if (base.state === 'capturing' && reads > baseCaptureReads.count) {\n const error = captureErrors.get(base.id) ?? null;\n base.state = error == null ? 'ready' : 'failed';\n base.error = error;\n }\n return json({ base: baseWire(base) });\n }\n const computerMatch = /^\\/computers\\/([^/]+)(\\/.*)?$/.exec(path);\n if (computerMatch == null) return json({ error: `no route ${path}` }, 404);\n const computer = find(decodeURIComponent(computerMatch[1] ?? ''));\n if (computer == null || computer.state === STATE.Deleted)\n return json({ error: 'computer not found' }, 404);\n const rest = computerMatch[2] ?? '';\n const machine = computer.machine;\n if (request.method === 'GET' && rest === '/screen')\n return json({ available: args.screenAvailable ?? false });\n if (request.method === 'POST' && rest === '/screen')\n return json({\n url: `https://computer-api.example/v1/computers/${computer.id}/screen/view#screen-token`,\n token: 'screen-token',\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n if (request.method === 'PATCH' && rest === '') {\n const patch = createComputerSchema.pick({ network: true, autoResume: true }).parse(body);\n if (patch.network != null) computer.body.network = patch.network;\n if (patch.autoResume != null) computer.body.autoResume = patch.autoResume;\n return json({ computer: wire(computer) });\n }\n if (request.method === 'GET' && rest === '/computer-use')\n return json({\n available: args.computerUseAvailable ?? false,\n installed: args.computerUseAvailable ?? false,\n });\n if (request.method === 'GET' && rest === '') {\n const starting = booting.get(computer.id);\n if (starting != null) {\n if (starting <= 0) {\n booting.delete(computer.id);\n computer.state = STATE.Running;\n } else booting.set(computer.id, starting - 1);\n }\n const left = shelving.get(computer.id);\n if (left != null) {\n if (left <= 0) {\n shelving.delete(computer.id);\n computer.state = STATE.Shelved;\n } else shelving.set(computer.id, left - 1);\n }\n return json({ computer: wire(computer) });\n }\n if (request.method === 'POST' && rest === '/capture') {\n if (computer.state !== STATE.Running) return json({ error: 'not running' }, 409);\n if (computer.body.userVolumeGb !== null) return json({ error: 'has a user volume' }, 409);\n const id = `part_0190b0000000700080000000${String(bases.size + 1).padStart(4, '0')}`;\n const capture = z.object({ retained: z.boolean().default(false) }).parse(body ?? {});\n const base: FakeBaseIface = {\n id,\n computerId: computer.id,\n state: 'capturing',\n error: null,\n retained: capture.retained,\n };\n bases.set(id, base);\n if (captureFailure.error != null) captureErrors.set(id, captureFailure.error);\n computer.state = STATE.Stopped;\n return json({ base: baseWire(base) }, 202);\n }\n const action = /^\\/actions\\/(.+)$/.exec(rest);\n if (request.method === 'POST' && action != null) {\n const name = action[1] ?? '';\n actions.push({ computerId: computer.id, action: name });\n if (actionConflicts.has(name))\n return json({ error: 'a lifecycle transition is committing' }, 409);\n const failure = actionFailures.get(name);\n if (failure != null) return json({ error: `${name} failed` }, failure);\n // The API pauses only a computer that runs.\n if (name === 'pause' && computer.state === STATE.Shelved)\n return json({ error: 'VM is shelved; wake it before pausing' }, 409);\n if (name === 'pause' && computer.state === STATE.Stopped)\n return json({ error: 'VM is stopped; nothing to pause' }, 409);\n if (name === 'pause' && computer.state === STATE.Error)\n return json({ error: 'pause failed: cannot pause vm in state Error' }, 502);\n if (name !== 'resume' && name !== 'start') booting.delete(computer.id);\n if (name === 'pause') computer.state = STATE.Paused;\n if (name === 'resume') boot(computer, STATE.Resuming);\n if (name === 'start') boot(computer, STATE.Pending);\n // A computer that is not ephemeral shelves on stop.\n if (name === 'stop') {\n computer.state = shelveReads.count > 0 ? STATE.Stopped : STATE.Shelved;\n if (shelveReads.count > 0) shelving.set(computer.id, shelveReads.count);\n }\n if (name === 'delete') computer.state = STATE.Deleted;\n return json({ computer: wire(computer) });\n }\n if (\n computer.state !== STATE.Running &&\n (rest === '/exec' || rest === '/run' || rest === '/files' || rest.startsWith('/processes/'))\n )\n return json({ error: NOT_RUNNING }, 409);\n if (request.method === 'POST' && (rest === '/exec' || rest === '/run')) {\n const parsed = z\n .object({\n command: z.string(),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n })\n .parse(body);\n const process = machine.exec({\n id: `proc-${machine.execs.length + 1}`,\n command: parsed.command,\n cwd: parsed.cwd ?? '/',\n env: parsed.env ?? {},\n });\n if (rest === '/exec')\n return json({ id: process.id, bootId: process.bootId, pid: 1, state: 'running' });\n const output = await readFakeOutput(process, { stdout: 0, stderr: 0, waitMs: 50 });\n return json({\n id: process.id,\n bootId: process.bootId,\n pid: 1,\n timedOut: false,\n elapsedMs: 1,\n ...outputBody(output, process, 0, 0),\n });\n }\n const processMatch = /^\\/processes\\/([^/]+)\\/(output|input|terminate)$/.exec(rest);\n if (processMatch != null) {\n const process = machine.processes.get(processMatch[1] ?? '');\n if (process == null) return json({ error: 'process not found' }, 404);\n if (processMatch[2] === 'output') {\n const stdoutOffset = Number(url.searchParams.get('stdoutOffset') ?? 0);\n const stderrOffset = Number(url.searchParams.get('stderrOffset') ?? 0);\n const output = await readFakeOutput(process, {\n stdout: stdoutOffset,\n stderr: stderrOffset,\n waitMs: Number(url.searchParams.get('waitMs') ?? 0),\n });\n return json(outputBody(output, process, stdoutOffset, stderrOffset));\n }\n if (processMatch[2] === 'terminate') {\n process.terminate();\n return json({ ok: true });\n }\n const input = z\n .object({\n dataB64: z.string().optional(),\n eof: z.boolean().optional(),\n signal: z.string().optional(),\n })\n .parse(body);\n if (input.dataB64 != null) process.write(decodeBase64(input.dataB64));\n if (input.eof === true) process.eof();\n if (input.signal != null) process.terminate(input.signal);\n return json({ ok: true });\n }\n if (rest === '/files' && request.method === 'GET') {\n const path = url.searchParams.get('path') ?? '';\n // Reads follow symlinks.\n const content = machine.files.get(machine.links.get(path) ?? path);\n if (content == null) return json({ error: `${path}: No such file or directory` }, 502);\n const offset = Number(url.searchParams.get('offset') ?? 0);\n const length = Number(url.searchParams.get('length') ?? content.byteLength);\n const slice = content.subarray(offset, offset + length);\n return json({\n dataB64: encodeBase64(slice),\n eof: offset + slice.byteLength >= content.byteLength,\n offset,\n });\n }\n if (rest === '/files' && request.method === 'PUT') {\n const parsed = z\n .object({ path: z.string(), dataB64: z.string(), append: z.boolean().optional() })\n .parse(body);\n if (!machine.dirs.has(posix.dirname(parsed.path)))\n return json({ error: 'No such file or directory' }, 502);\n const data = decodeBase64(parsed.dataB64);\n const previous =\n parsed.append === true\n ? (machine.files.get(parsed.path) ?? new Uint8Array())\n : new Uint8Array();\n machine.files.set(parsed.path, concatBytes([previous, data]));\n return json({ bytesWritten: data.byteLength });\n }\n return json({ error: `no route ${request.method} ${path}` }, 404);\n };\n\n return {\n fetch: async (input, init) => handle(new Request(input, init)),\n computers,\n images,\n bases,\n baseCaptureReads,\n captureFailure,\n requests,\n actions,\n actionConflicts,\n actionFailures,\n shelveReads,\n imageBuildReads,\n bootReads,\n computerByName: (name) => [...computers.values()].find((computer) => computer.name === name),\n };\n};\n\nconst outputBody = (\n output: { stdout: Uint8Array; stderr: Uint8Array; exited: boolean },\n process: {\n exitCode: number | null;\n signal: string | null;\n stdout: Uint8Array;\n stderr: Uint8Array;\n },\n stdoutOffset: number,\n stderrOffset: number,\n) => ({\n stdout: {\n dataB64: encodeBase64(output.stdout),\n offset: stdoutOffset,\n nextOffset: stdoutOffset + output.stdout.byteLength,\n eof: output.exited && stdoutOffset + output.stdout.byteLength >= process.stdout.byteLength,\n },\n stderr: {\n dataB64: encodeBase64(output.stderr),\n offset: stderrOffset,\n nextOffset: stderrOffset + output.stderr.byteLength,\n eof: output.exited && stderrOffset + output.stderr.byteLength >= process.stderr.byteLength,\n },\n state: output.exited ? 'exited' : 'running',\n result: output.exited ? { exitCode: process.exitCode, signal: process.signal } : null,\n});\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import {\n jsonObjectSchema,\n jsonValueSchema,\n type JsonObject,\n type JsonValue,\n} from '@finalai/agent-provider';\nimport { ComputerEgressPolicy } from '@finalai/computers';\nimport { posix } from 'node:path';\nimport * as z from 'zod';\nimport { concatBytes, decodeBase64, encodeBase64 } from \"../bytes.mjs\";\nimport { createFakeMachine, readFakeOutput, type FakeMachineIface } from \"./fake-machine.mjs\";\n\n// A fake public Computers API (`/v1` over fetch, bearer token), backed by\n// in-memory machines.\n\nexport interface FakeComputerIface {\n id: string;\n name: string;\n state: number;\n body: JsonObject;\n machine: FakeMachineIface;\n}\n\nexport interface FakeImageIface {\n id: string;\n source: 'platform' | 'customer';\n reference: string;\n lineage: string;\n state: 'pending' | 'building' | 'ready' | 'failed' | 'expired';\n error: string | null;\n}\n\nexport interface FakeBaseIface {\n id: string;\n computerId: string;\n state: 'capturing' | 'ready' | 'failed' | 'expired';\n error: string | null;\n retained: boolean;\n}\n\nexport interface FakeComputersApiIface {\n fetch: typeof fetch;\n computers: Map<string, FakeComputerIface>;\n images: Map<string, FakeImageIface>;\n bases: Map<string, FakeBaseIface>;\n // Base reads a fresh capture answers `capturing` before it settles.\n baseCaptureReads: { count: number };\n // Set: the next captures settle `failed` with this error instead of `ready`.\n captureFailure: { error: string | null };\n requests: { method: string; path: string; body: JsonValue; headers: Headers }[];\n actions: { computerId: string; action: string }[];\n // Actions answered 409 (a conflicting transition) without changing the computer.\n actionConflicts: Set<string>;\n // Actions answered with this status (a failed host command) without changing the computer.\n actionFailures: Map<string, number>;\n // Computer reads a stopped computer answers `stopped` before it is shelved.\n shelveReads: { count: number };\n // Image reads a fresh registration answers `building` before it is ready.\n imageBuildReads: { count: number };\n // Computer reads a created or started computer answers `pending` (a resumed\n // one `resuming`) before it runs; until then commands and files answer 409.\n bootReads: { count: number };\n computerByName(name: string): FakeComputerIface | undefined;\n}\n\nconst STATE = {\n Pending: 1,\n Running: 3,\n Paused: 4,\n Stopped: 5,\n Resuming: 6,\n Error: 8,\n Deleted: 9,\n Shelved: 10,\n} as const;\nconst NOT_RUNNING = 'Computer is not running; resume it explicitly before this operation';\nexport const FAKE_COMPUTERS_API_KEY = 'fk_org_api_key';\nexport const FAKE_PLATFORM_SANDBOX_IMAGE = 'cimv_0190e0000000700080000000000001';\n\nconst json = (body: JsonValue, status = 200): Response =>\n new Response(JSON.stringify(body), { status, headers: { 'content-type': 'application/json' } });\n\n// What POST /v1/computers accepts; anything else, such as image, lineage,\n// projectArtifact or platform-only policies, is refused so a test fails when the\n// provider asks for it.\nconst createComputerSchema = z.strictObject({\n name: z.string().optional(),\n regionSlug: z.string().optional(),\n imageVersionId: z.string().startsWith('cimv_').optional(),\n baseId: z.string().startsWith('part_').optional(),\n idlePolicy: z.enum(['shelve', 'pause', 'delete']).optional(),\n network: z\n .strictObject({\n egress: z.nativeEnum(ComputerEgressPolicy),\n allow: z.array(z.string()).optional(),\n })\n .optional(),\n vcpu: z.number().optional(),\n memoryMb: z.number().optional(),\n diskGb: z.number().optional(),\n userVolumeGb: z.number().nullable().optional(),\n env: z.record(z.string(), z.string()).optional(),\n setupScript: z.string().optional(),\n commandMode: z.number().optional(),\n customCommand: z.string().optional(),\n httpPort: z.number().optional(),\n httpPublic: z.boolean().optional(),\n ephemeral: z.boolean().optional(),\n idleTimeoutSeconds: z.number().optional(),\n autoResume: z.boolean().optional(),\n tags: z.array(z.string()).optional(),\n comment: z.string().optional(),\n});\n\nexport const createFakeComputersApi = (\n args: {\n machineFor?: (computer: { id: string; name: string }) => FakeMachineIface;\n computerUseAvailable?: boolean;\n screenAvailable?: boolean;\n // Computer-use tools by image, as `GET /computer-use/catalog` answers them;\n // absent, the route is missing (an API that cannot tell).\n computerUseCatalog?: Record<string, JsonObject[]>;\n } = {},\n): FakeComputersApiIface => {\n const computers = new Map<string, FakeComputerIface>();\n const images = new Map<string, FakeImageIface>([\n [\n FAKE_PLATFORM_SANDBOX_IMAGE,\n {\n id: FAKE_PLATFORM_SANDBOX_IMAGE,\n source: 'platform',\n reference: 'ghcr.io/final/sandbox:release',\n lineage: 'sandbox',\n state: 'ready',\n error: null,\n },\n ],\n ]);\n const requests: FakeComputersApiIface['requests'] = [];\n const actions: FakeComputersApiIface['actions'] = [];\n const actionConflicts = new Set<string>();\n const actionFailures = new Map<string, number>();\n const shelveReads = { count: 0 };\n const shelving = new Map<string, number>();\n const imageBuildReads = { count: 1 };\n const bootReads = { count: 1 };\n const booting = new Map<string, number>();\n const boot = (computer: FakeComputerIface, state: number) => {\n if (bootReads.count <= 0) {\n computer.state = STATE.Running;\n return;\n }\n computer.state = state;\n booting.set(computer.id, bootReads.count);\n };\n const imageReads = new Map<string, number>();\n const bases = new Map<string, FakeBaseIface>();\n const baseCaptureReads = { count: 1 };\n const captureFailure: FakeComputersApiIface['captureFailure'] = { error: null };\n const captureErrors = new Map<string, string>();\n const baseReads = new Map<string, number>();\n let computerCount = 0;\n const byIdempotency = new Map<string, string>();\n\n const wire = (computer: FakeComputerIface) => ({\n id: computer.id,\n name: computer.name,\n state: computer.state,\n network: computer.body.network ?? { egress: ComputerEgressPolicy.Internet },\n imageVersionId: z\n .string()\n .nullable()\n .catch(null)\n .parse(computer.body.imageVersionId ?? null),\n // The token's project: the API infers it.\n projectId: 'prj_fake',\n hostname: `${computer.name}-k3p9x7qd.virtual-machine.lax-2.example`,\n tags: [],\n });\n const imageWire = (image: FakeImageIface) => ({\n ...image,\n digest: `sha256:${image.id}`,\n sizes: ['standard'],\n registryCredentialId: null,\n createdAt: null,\n readyAt: null,\n lastUsedAt: null,\n });\n const baseWire = (base: FakeBaseIface) => ({\n ...base,\n image: 'ghcr.io/final/sandbox:release',\n digest: `sha256:${'b'.repeat(64)}`,\n diskGb: 20,\n createdAt: null,\n readyAt: null,\n lastUsedAt: null,\n });\n const find = (idOrName: string): FakeComputerIface | undefined =>\n computers.get(idOrName) ??\n [...computers.values()].find(\n (computer) => computer.name === idOrName && computer.state !== STATE.Deleted,\n );\n\n const handle = async (request: Request): Promise<Response> => {\n const url = new URL(request.url);\n const text = request.method === 'GET' ? '' : await request.text();\n const body = text === '' ? null : jsonValueSchema.parse(JSON.parse(text));\n requests.push({ method: request.method, path: url.pathname, body, headers: request.headers });\n if (!url.pathname.startsWith('/v1/')) return json({ error: 'not found' }, 404);\n if (request.headers.get('authorization') !== `Bearer ${FAKE_COMPUTERS_API_KEY}`) {\n return json({ error: 'unauthorized' }, 401);\n }\n const path = url.pathname.slice('/v1'.length);\n if (request.method === 'POST' && path === '/computers') {\n const parsed = createComputerSchema.safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n if ((parsed.data.imageVersionId == null) === (parsed.data.baseId == null)) {\n return json({ error: 'pass exactly one of imageVersionId and baseId' }, 400);\n }\n if (parsed.data.imageVersionId != null) {\n const image = images.get(parsed.data.imageVersionId);\n if (image == null) return json({ error: 'image version not found' }, 404);\n if (image.state !== 'ready') return json({ error: `image version is ${image.state}` }, 409);\n }\n if (parsed.data.baseId != null) {\n const base = bases.get(parsed.data.baseId);\n if (base == null) return json({ error: 'base not found' }, 404);\n if (base.state !== 'ready') return json({ error: `base is ${base.state}` }, 409);\n }\n const key = request.headers.get('idempotency-key');\n if (parsed.data.ephemeral === true && parsed.data.idlePolicy === 'pause')\n return json({ error: 'ephemeral VMs are always deleted when idle' }, 400);\n const existing = key == null ? undefined : computers.get(byIdempotency.get(key) ?? '');\n if (existing != null) return json({ computer: wire(existing) });\n computerCount += 1;\n const id = `comp_0190a0000000700080000000${String(computerCount).padStart(4, '0')}`;\n const name = parsed.data.name ?? `computer-${computerCount}`;\n const computer: FakeComputerIface = {\n id,\n name,\n state: STATE.Pending,\n body: jsonObjectSchema.parse(body),\n machine: args.machineFor?.({ id, name }) ?? createFakeMachine(),\n };\n boot(computer, STATE.Pending);\n computers.set(id, computer);\n if (key != null) byIdempotency.set(key, id);\n return json({ computer: wire(computer) });\n }\n if (\n request.method === 'GET' &&\n path === '/computer-use/catalog' &&\n args.computerUseCatalog != null\n )\n return json({ tools: args.computerUseCatalog[url.searchParams.get('image') ?? ''] ?? null });\n if (request.method === 'GET' && path === '/images') {\n const lineage = url.searchParams.get('lineage');\n const state = url.searchParams.get('state');\n const matching = [...images.values()]\n .filter((image) => lineage == null || image.lineage === lineage)\n .filter((image) => state == null || image.state === state)\n .reverse();\n return json({ images: matching.map(imageWire) });\n }\n if (request.method === 'POST' && path === '/images') {\n const parsed = z\n .strictObject({\n reference: z.string(),\n registryCredentialId: z.string().optional(),\n sizes: z.array(z.string()).optional(),\n })\n .safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n const known = [...images.values()].find(\n (image) =>\n image.reference === parsed.data.reference &&\n (image.state === 'pending' || image.state === 'building' || image.state === 'ready'),\n );\n if (known != null) return json({ image: imageWire(known) });\n const id = `cimv_0190f0000000700080000000${String(images.size + 1).padStart(4, '0')}`;\n const image: FakeImageIface = {\n id,\n source: 'customer',\n reference: parsed.data.reference,\n lineage: parsed.data.reference,\n state: 'building',\n error: null,\n };\n images.set(id, image);\n return json({ image: imageWire(image) }, 201);\n }\n const imageMatch = /^\\/images\\/([^/]+)$/.exec(path);\n if (request.method === 'GET' && imageMatch != null) {\n const image = images.get(decodeURIComponent(imageMatch[1] ?? ''));\n if (image == null) return json({ error: 'image not found' }, 404);\n const reads = (imageReads.get(image.id) ?? 0) + 1;\n imageReads.set(image.id, reads);\n if (image.state === 'building' && reads > imageBuildReads.count) image.state = 'ready';\n return json({ image: imageWire(image) });\n }\n if (request.method === 'POST' && path === '/tokens') {\n const parsed = z\n .strictObject({\n name: z.string(),\n computerId: z.string().startsWith('comp_').optional(),\n scopes: z.array(z.string()).optional(),\n expiresAt: z.string().optional(),\n })\n .safeParse(body);\n if (!parsed.success) return json({ error: 'invalid body' }, 400);\n return json({ id: 'ctok_1', token: 'fvm1.http-token' });\n }\n const baseMatch = /^\\/bases\\/([^/]+)$/.exec(path);\n if (request.method === 'PATCH' && baseMatch != null) {\n const base = bases.get(decodeURIComponent(baseMatch[1] ?? ''));\n if (base == null) return json({ error: 'base not found' }, 404);\n const retained = z.object({ retained: z.boolean() }).parse(body);\n base.retained = retained.retained;\n return json({ base: baseWire(base) });\n }\n if (request.method === 'GET' && baseMatch != null) {\n const base = bases.get(decodeURIComponent(baseMatch[1] ?? ''));\n if (base == null) return json({ error: 'base not found' }, 404);\n const reads = (baseReads.get(base.id) ?? 0) + 1;\n baseReads.set(base.id, reads);\n if (base.state === 'capturing' && reads > baseCaptureReads.count) {\n const error = captureErrors.get(base.id) ?? null;\n base.state = error == null ? 'ready' : 'failed';\n base.error = error;\n }\n return json({ base: baseWire(base) });\n }\n const computerMatch = /^\\/computers\\/([^/]+)(\\/.*)?$/.exec(path);\n if (computerMatch == null) return json({ error: `no route ${path}` }, 404);\n const computer = find(decodeURIComponent(computerMatch[1] ?? ''));\n if (computer == null || computer.state === STATE.Deleted)\n return json({ error: 'computer not found' }, 404);\n const rest = computerMatch[2] ?? '';\n const machine = computer.machine;\n if (request.method === 'GET' && rest === '/screen')\n return json({ available: args.screenAvailable ?? false });\n if (request.method === 'POST' && rest === '/screen')\n return json({\n url: `https://computer-api.example/v1/computers/${computer.id}/screen/view#screen-token`,\n token: 'screen-token',\n expiresAt: new Date(Date.now() + 900_000).toISOString(),\n });\n if (request.method === 'PATCH' && rest === '') {\n const patch = createComputerSchema.pick({ network: true, autoResume: true }).parse(body);\n if (patch.network != null) computer.body.network = patch.network;\n if (patch.autoResume != null) computer.body.autoResume = patch.autoResume;\n return json({ computer: wire(computer) });\n }\n if (request.method === 'GET' && rest === '/computer-use')\n return json({\n available: args.computerUseAvailable ?? false,\n installed: args.computerUseAvailable ?? false,\n });\n if (request.method === 'GET' && rest === '') {\n const starting = booting.get(computer.id);\n if (starting != null) {\n if (starting <= 0) {\n booting.delete(computer.id);\n computer.state = STATE.Running;\n } else booting.set(computer.id, starting - 1);\n }\n const left = shelving.get(computer.id);\n if (left != null) {\n if (left <= 0) {\n shelving.delete(computer.id);\n computer.state = STATE.Shelved;\n } else shelving.set(computer.id, left - 1);\n }\n return json({ computer: wire(computer) });\n }\n if (request.method === 'POST' && rest === '/capture') {\n if (computer.state !== STATE.Running) return json({ error: 'not running' }, 409);\n if (computer.body.userVolumeGb !== null) return json({ error: 'has a user volume' }, 409);\n const id = `part_0190b0000000700080000000${String(bases.size + 1).padStart(4, '0')}`;\n const capture = z.object({ retained: z.boolean().default(false) }).parse(body ?? {});\n const base: FakeBaseIface = {\n id,\n computerId: computer.id,\n state: 'capturing',\n error: null,\n retained: capture.retained,\n };\n bases.set(id, base);\n if (captureFailure.error != null) captureErrors.set(id, captureFailure.error);\n computer.state = STATE.Stopped;\n return json({ base: baseWire(base) }, 202);\n }\n const action = /^\\/actions\\/(.+)$/.exec(rest);\n if (request.method === 'POST' && action != null) {\n const name = action[1] ?? '';\n actions.push({ computerId: computer.id, action: name });\n if (actionConflicts.has(name))\n return json({ error: 'a lifecycle transition is committing' }, 409);\n const failure = actionFailures.get(name);\n if (failure != null) return json({ error: `${name} failed` }, failure);\n // The API pauses only a computer that runs.\n if (name === 'pause' && computer.state === STATE.Shelved)\n return json({ error: 'VM is shelved; wake it before pausing' }, 409);\n if (name === 'pause' && computer.state === STATE.Stopped)\n return json({ error: 'VM is stopped; nothing to pause' }, 409);\n if (name === 'pause' && computer.state === STATE.Error)\n return json({ error: 'pause failed: cannot pause vm in state Error' }, 502);\n if (name !== 'resume' && name !== 'start') booting.delete(computer.id);\n if (name === 'pause') computer.state = STATE.Paused;\n if (name === 'resume') boot(computer, STATE.Resuming);\n if (name === 'start') boot(computer, STATE.Pending);\n // A computer that is not ephemeral shelves on stop.\n if (name === 'stop') {\n computer.state = shelveReads.count > 0 ? STATE.Stopped : STATE.Shelved;\n if (shelveReads.count > 0) shelving.set(computer.id, shelveReads.count);\n }\n if (name === 'delete') computer.state = STATE.Deleted;\n return json({ computer: wire(computer) });\n }\n if (\n computer.state !== STATE.Running &&\n (rest === '/exec' || rest === '/run' || rest === '/files' || rest.startsWith('/processes/'))\n )\n return json({ error: NOT_RUNNING }, 409);\n if (request.method === 'POST' && (rest === '/exec' || rest === '/run')) {\n const parsed = z\n .object({\n command: z.string(),\n cwd: z.string().optional(),\n env: z.record(z.string(), z.string()).optional(),\n })\n .parse(body);\n const process = machine.exec({\n id: `proc-${machine.execs.length + 1}`,\n command: parsed.command,\n cwd: parsed.cwd ?? '/',\n env: parsed.env ?? {},\n });\n if (rest === '/exec')\n return json({ id: process.id, bootId: process.bootId, pid: 1, state: 'running' });\n const output = await readFakeOutput(process, { stdout: 0, stderr: 0, waitMs: 50 });\n return json({\n id: process.id,\n bootId: process.bootId,\n pid: 1,\n timedOut: false,\n elapsedMs: 1,\n ...outputBody(output, process, 0, 0),\n });\n }\n const processMatch = /^\\/processes\\/([^/]+)\\/(output|input|terminate)$/.exec(rest);\n if (processMatch != null) {\n const process = machine.processes.get(processMatch[1] ?? '');\n if (process == null) return json({ error: 'process not found' }, 404);\n if (processMatch[2] === 'output') {\n const stdoutOffset = Number(url.searchParams.get('stdoutOffset') ?? 0);\n const stderrOffset = Number(url.searchParams.get('stderrOffset') ?? 0);\n const output = await readFakeOutput(process, {\n stdout: stdoutOffset,\n stderr: stderrOffset,\n waitMs: Number(url.searchParams.get('waitMs') ?? 0),\n });\n return json(outputBody(output, process, stdoutOffset, stderrOffset));\n }\n if (processMatch[2] === 'terminate') {\n process.terminate();\n return json({ ok: true });\n }\n const input = z\n .object({\n dataB64: z.string().optional(),\n eof: z.boolean().optional(),\n signal: z.string().optional(),\n })\n .parse(body);\n if (input.dataB64 != null) process.write(decodeBase64(input.dataB64));\n if (input.eof === true) process.eof();\n if (input.signal != null) process.terminate(input.signal);\n return json({ ok: true });\n }\n if (rest === '/files' && request.method === 'GET') {\n const path = url.searchParams.get('path') ?? '';\n // Reads follow symlinks.\n const content = machine.files.get(machine.links.get(path) ?? path);\n if (content == null) return json({ error: `${path}: No such file or directory` }, 502);\n const offset = Number(url.searchParams.get('offset') ?? 0);\n const length = Number(url.searchParams.get('length') ?? content.byteLength);\n const slice = content.subarray(offset, offset + length);\n return json({\n dataB64: encodeBase64(slice),\n eof: offset + slice.byteLength >= content.byteLength,\n offset,\n });\n }\n if (rest === '/files' && request.method === 'PUT') {\n const parsed = z\n .object({ path: z.string(), dataB64: z.string(), append: z.boolean().optional() })\n .parse(body);\n if (!machine.dirs.has(posix.dirname(parsed.path)))\n return json({ error: 'No such file or directory' }, 502);\n const data = decodeBase64(parsed.dataB64);\n const previous =\n parsed.append === true\n ? (machine.files.get(parsed.path) ?? new Uint8Array())\n : new Uint8Array();\n machine.files.set(parsed.path, concatBytes([previous, data]));\n return json({ bytesWritten: data.byteLength });\n }\n return json({ error: `no route ${request.method} ${path}` }, 404);\n };\n\n return {\n fetch: async (input, init) => handle(new Request(input, init)),\n computers,\n images,\n bases,\n baseCaptureReads,\n captureFailure,\n requests,\n actions,\n actionConflicts,\n actionFailures,\n shelveReads,\n imageBuildReads,\n bootReads,\n computerByName: (name) => [...computers.values()].find((computer) => computer.name === name),\n };\n};\n\nconst outputBody = (\n output: { stdout: Uint8Array; stderr: Uint8Array; exited: boolean },\n process: {\n exitCode: number | null;\n signal: string | null;\n stdout: Uint8Array;\n stderr: Uint8Array;\n },\n stdoutOffset: number,\n stderrOffset: number,\n) => ({\n stdout: {\n dataB64: encodeBase64(output.stdout),\n offset: stdoutOffset,\n nextOffset: stdoutOffset + output.stdout.byteLength,\n eof: output.exited && stdoutOffset + output.stdout.byteLength >= process.stdout.byteLength,\n },\n stderr: {\n dataB64: encodeBase64(output.stderr),\n offset: stderrOffset,\n nextOffset: stderrOffset + output.stderr.byteLength,\n eof: output.exited && stderrOffset + output.stderr.byteLength >= process.stderr.byteLength,\n },\n state: output.exited ? 'exited' : 'running',\n result: output.exited ? { exitCode: process.exitCode, signal: process.signal } : null,\n});\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["computer", "image", "path"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import {
|
|
2
|
+
toolDescriptorSchema
|
|
3
|
+
} from "@finalai/agent-provider";
|
|
4
|
+
const toolDescriptorsOf = (tools) => tools.flatMap((tool) => {
|
|
5
|
+
const parsed = toolDescriptorSchema.safeParse({
|
|
6
|
+
...tool,
|
|
7
|
+
description: tool.description ?? tool.title ?? tool.name
|
|
8
|
+
});
|
|
9
|
+
return parsed.success ? [parsed.data] : [];
|
|
10
|
+
});
|
|
11
|
+
export {
|
|
12
|
+
toolDescriptorsOf
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=tool-catalog.mjs.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../src/sandboxes/tool-catalog.ts"],
|
|
4
|
+
"sourcesContent": ["import {\n toolDescriptorSchema,\n type JsonObject,\n type ToolDescriptorIface,\n} from '@finalai/agent-provider';\n\n// A hosted server's tools as a backend recorded them, as tool descriptors: a\n// tool without a description is described by its title or name; one that is\n// not a valid descriptor is left out.\nexport const toolDescriptorsOf = (tools: readonly JsonObject[]): ToolDescriptorIface[] =>\n tools.flatMap((tool) => {\n const parsed = toolDescriptorSchema.safeParse({\n ...tool,\n description: tool.description ?? tool.title ?? tool.name,\n });\n return parsed.success ? [parsed.data] : [];\n });\n"],
|
|
5
|
+
"mappings": "AAAA;AAAA,EACE;AAAA,OAGK;AAKA,MAAM,oBAAoB,CAAC,UAChC,MAAM,QAAQ,CAAC,SAAS;AACtB,QAAM,SAAS,qBAAqB,UAAU;AAAA,IAC5C,GAAG;AAAA,IACH,aAAa,KAAK,eAAe,KAAK,SAAS,KAAK;AAAA,EACtD,CAAC;AACD,SAAO,OAAO,UAAU,CAAC,OAAO,IAAI,IAAI,CAAC;AAC3C,CAAC;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@finalai/final-agent-provider",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Final's harness and ACP adapter definitions and the general harness provider, computer, device and local sandbox providers, and Final's MCP gateway integration.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -132,11 +132,11 @@
|
|
|
132
132
|
},
|
|
133
133
|
"dependencies": {
|
|
134
134
|
"@agentclientprotocol/sdk": "1.8.0",
|
|
135
|
-
"@finalai/agent-protocol": "0.
|
|
136
|
-
"@finalai/agent-provider": "0.
|
|
135
|
+
"@finalai/agent-protocol": "0.13.0",
|
|
136
|
+
"@finalai/agent-provider": "0.14.0",
|
|
137
137
|
"@finalai/computers": "0.3.1",
|
|
138
138
|
"zod": "4.6.6",
|
|
139
|
-
"@finalai/agent-definition": "0.
|
|
139
|
+
"@finalai/agent-definition": "0.13.0"
|
|
140
140
|
},
|
|
141
141
|
"engines": {
|
|
142
142
|
"node": ">=26"
|