@finalai/final-agent-provider 0.5.0 → 0.6.1
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/HOSTING.md +3 -3
- package/README.md +4 -0
- package/WORKSPACE-EGRESS.md +7 -6
- package/dist/modules/channels/projection.d.mts +13 -7
- package/dist/modules/channels/projection.mjs +49 -31
- package/dist/modules/channels/projection.mjs.map +2 -2
- package/dist/modules/sandboxes/computer.d.mts +4 -3
- package/dist/modules/sandboxes/computer.mjs +22 -35
- package/dist/modules/sandboxes/computer.mjs.map +2 -2
- package/dist/modules/sandboxes/computers-api.d.mts +2 -17
- package/dist/modules/sandboxes/computers-api.mjs +27 -44
- package/dist/modules/sandboxes/computers-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device-api.d.mts +3 -8
- package/dist/modules/sandboxes/device-api.mjs +17 -28
- package/dist/modules/sandboxes/device-api.mjs.map +3 -3
- package/dist/modules/sandboxes/device.d.mts +2 -1
- package/dist/modules/sandboxes/device.mjs +13 -5
- package/dist/modules/sandboxes/device.mjs.map +2 -2
- package/dist/modules/sandboxes/egress.d.mts +4 -1
- package/dist/modules/sandboxes/egress.mjs +20 -2
- package/dist/modules/sandboxes/egress.mjs.map +2 -2
- package/dist/modules/sandboxes/environment.d.mts +0 -3
- package/dist/modules/sandboxes/environment.mjs +2 -8
- package/dist/modules/sandboxes/environment.mjs.map +2 -2
- package/dist/modules/sandboxes/index.d.mts +1 -1
- package/dist/modules/sandboxes/index.mjs +0 -2
- package/dist/modules/sandboxes/index.mjs.map +2 -2
- package/dist/modules/sandboxes/testing/fake-backends.mjs +2 -2
- package/dist/modules/sandboxes/testing/fake-backends.mjs.map +2 -2
- package/package.json +5 -5
|
@@ -1,17 +1,8 @@
|
|
|
1
1
|
import { type ProcessInspectionRequestIface, type ProcessInspectionResultIface } from '@finalai/agent-protocol/process-inspection';
|
|
2
|
-
import type
|
|
2
|
+
import { type JsonValue, type SandboxCredentialsIface } from '@finalai/agent-provider';
|
|
3
3
|
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';
|
|
4
4
|
import * as z from 'zod';
|
|
5
|
-
export interface ComputersApiCredentialIface {
|
|
6
|
-
apiKey: string;
|
|
7
|
-
teamId: string | null;
|
|
8
|
-
}
|
|
9
5
|
export interface ComputersApiConfigIface {
|
|
10
|
-
url: string;
|
|
11
|
-
credential: (args: {
|
|
12
|
-
organizationId: string;
|
|
13
|
-
}) => Promise<ComputersApiCredentialIface | null>;
|
|
14
|
-
credentialTtlMs?: number;
|
|
15
6
|
fetch?: typeof fetch;
|
|
16
7
|
requestTimeoutMs?: number;
|
|
17
8
|
}
|
|
@@ -204,14 +195,8 @@ export interface ComputersApiClientIface {
|
|
|
204
195
|
setBaseRetention(baseId: string, retained: boolean): Promise<ComputerBaseIface>;
|
|
205
196
|
getBase(baseId: string): Promise<ComputerBaseIface | null>;
|
|
206
197
|
}
|
|
207
|
-
export interface ComputersApiCredentialsIface {
|
|
208
|
-
get(organizationId: string): Promise<ComputersApiCredentialIface>;
|
|
209
|
-
invalidate(organizationId: string): void;
|
|
210
|
-
}
|
|
211
|
-
export declare const createComputersApiCredentials: (config: Pick<ComputersApiConfigIface, "credential" | "credentialTtlMs">, now?: () => number) => ComputersApiCredentialsIface;
|
|
212
198
|
export declare const createComputersApiClient: (args: {
|
|
213
199
|
config: ComputersApiConfigIface;
|
|
214
|
-
credentials:
|
|
215
|
-
organizationId: string;
|
|
200
|
+
credentials: SandboxCredentialsIface | undefined;
|
|
216
201
|
}) => ComputersApiClientIface;
|
|
217
202
|
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ProcessInspectionOperation
|
|
3
3
|
} from "@finalai/agent-protocol/process-inspection";
|
|
4
|
-
import {
|
|
4
|
+
import {
|
|
5
|
+
jsonValueSchema
|
|
6
|
+
} from "@finalai/agent-provider";
|
|
5
7
|
import {
|
|
6
8
|
computerBrowserAccessSchema,
|
|
7
9
|
ComputerImageState,
|
|
@@ -15,7 +17,6 @@ import {
|
|
|
15
17
|
} from "@finalai/computers";
|
|
16
18
|
import * as z from "zod";
|
|
17
19
|
import { inspectComputerProcesses } from "./computer-processes.mjs";
|
|
18
|
-
import { COMPUTERS_API_KEY_SECRET } from "./environment.mjs";
|
|
19
20
|
var ComputersApiErrorCode = /* @__PURE__ */ ((ComputersApiErrorCode2) => {
|
|
20
21
|
ComputersApiErrorCode2["CredentialMissing"] = "credential_missing";
|
|
21
22
|
ComputersApiErrorCode2["RequestFailed"] = "request_failed";
|
|
@@ -52,50 +53,34 @@ const computerResponseSchema = z.object({ computer: jsonValueSchema });
|
|
|
52
53
|
const imageResponseSchema = z.object({ image: jsonValueSchema });
|
|
53
54
|
const baseResponseSchema = z.object({ base: jsonValueSchema });
|
|
54
55
|
const imagesResponseSchema = z.object({ images: z.array(jsonValueSchema) });
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
const cached = cache.get(organizationId);
|
|
61
|
-
if (cached != null && cached.expiresAtMs > now()) return cached.value;
|
|
62
|
-
const value = await config.credential({ organizationId });
|
|
63
|
-
if (value == null) {
|
|
56
|
+
const createComputersApiClient = (args) => {
|
|
57
|
+
const request = async (req) => {
|
|
58
|
+
const send = async (refresh) => {
|
|
59
|
+
const access = await args.credentials?.computersAccess({ refresh });
|
|
60
|
+
if (access == null) {
|
|
64
61
|
throw computersApiError(
|
|
65
|
-
|
|
62
|
+
"the host granted the computer sandbox no Computers API access",
|
|
66
63
|
null,
|
|
67
64
|
"credential_missing" /* CredentialMissing */
|
|
68
65
|
);
|
|
69
66
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const response = await transport.request({
|
|
88
|
-
method: req.method,
|
|
89
|
-
path: req.path,
|
|
90
|
-
query: req.query,
|
|
91
|
-
jsonBody: req.body,
|
|
92
|
-
headers: req.headers,
|
|
93
|
-
signal: req.signal
|
|
94
|
-
});
|
|
95
|
-
if (!response.ok) {
|
|
96
|
-
if (response.statusCode === 401) args.credentials.invalidate(args.organizationId);
|
|
97
|
-
throw computersApiError(response.error, response.statusCode ?? null);
|
|
98
|
-
}
|
|
67
|
+
return createTransport({
|
|
68
|
+
baseUrl: access.baseUrl,
|
|
69
|
+
auth: { apiKey: access.token },
|
|
70
|
+
fetch: args.config.fetch,
|
|
71
|
+
requestTimeoutMs: args.config.requestTimeoutMs
|
|
72
|
+
}).request({
|
|
73
|
+
method: req.method,
|
|
74
|
+
path: req.path,
|
|
75
|
+
query: req.query,
|
|
76
|
+
jsonBody: req.body,
|
|
77
|
+
headers: req.headers,
|
|
78
|
+
signal: req.signal
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
let response = await send(false);
|
|
82
|
+
if (!response.ok && response.statusCode === 401) response = await send(true);
|
|
83
|
+
if (!response.ok) throw computersApiError(response.error, response.statusCode ?? null);
|
|
99
84
|
const parsed = response.data;
|
|
100
85
|
const result = req.schema.safeParse(parsed);
|
|
101
86
|
if (!result.success)
|
|
@@ -140,11 +125,10 @@ const createComputersApiClient = (args) => {
|
|
|
140
125
|
return input.operation === ProcessInspectionOperation.Available && "available" in result.data ? { ...result.data, canStop: true } : result.data;
|
|
141
126
|
},
|
|
142
127
|
createComputer: async (body, idempotencyKey) => {
|
|
143
|
-
const { teamId } = await args.credentials.get(args.organizationId);
|
|
144
128
|
const response = await request({
|
|
145
129
|
method: "POST",
|
|
146
130
|
path: "/computers",
|
|
147
|
-
body
|
|
131
|
+
body,
|
|
148
132
|
headers: { "idempotency-key": idempotencyKey },
|
|
149
133
|
schema: computerResponseSchema
|
|
150
134
|
});
|
|
@@ -388,7 +372,6 @@ export {
|
|
|
388
372
|
ComputersApiErrorCode,
|
|
389
373
|
computersApiError,
|
|
390
374
|
createComputersApiClient,
|
|
391
|
-
createComputersApiCredentials,
|
|
392
375
|
isComputersApiError,
|
|
393
376
|
isComputersApiStatus
|
|
394
377
|
};
|
|
@@ -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 type { JsonValue } from '@finalai/agent-provider';\nimport { jsonValueSchema } from '@finalai/agent-provider';\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\";\nimport { COMPUTERS_API_KEY_SECRET } from \"./environment.mjs\";\n\n// The public Computers API (`/v1`, vm-service/docs/v1-api.md), authenticated the\n// way any developer's code is: an organization API key as the bearer. The\n// provider holds no platform credential and reaches no `/internal` route. This\n// speaks the REST surface directly, reusing @finalai/computers's row\n// normalization, because the provider needs an injected fetch and per-call\n// abort signals that the SDK's client does not take.\n\n// An organization's Computers API credential. `teamId` (`team_...`) owns the\n// computers when the key has no owning user (an organization or team key),\n// which POST /v1/computers requires.\nexport interface ComputersApiCredentialIface {\n apiKey: string;\n teamId: string | null;\n}\n\nexport interface ComputersApiConfigIface {\n // Public Computers API origin (VM_SERVICE_WORKER_DOMAIN); requests go to `<url>/v1/...`.\n url: string;\n // The organization's credential, null when it has none.\n credential: (args: { organizationId: string }) => Promise<ComputersApiCredentialIface | null>;\n // How long a resolved credential is reused before it is read again; a 401 drops it at once.\n credentialTtlMs?: number;\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 (vm-service\n// docs/v1-api.md).\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\ninterface CachedCredentialIface {\n value: ComputersApiCredentialIface;\n expiresAtMs: number;\n}\n\nexport interface ComputersApiCredentialsIface {\n get(organizationId: string): Promise<ComputersApiCredentialIface>;\n invalidate(organizationId: string): void;\n}\n\n// Credentials per organization, reused for `credentialTtlMs` (default 60 s, as\n// vm-service caches an API key's validation) so a handle's calls do not each\n// read the secret store.\nexport const createComputersApiCredentials = (\n config: Pick<ComputersApiConfigIface, 'credential' | 'credentialTtlMs'>,\n now: () => number = () => Date.now(),\n): ComputersApiCredentialsIface => {\n const cache = new Map<string, CachedCredentialIface>();\n const ttlMs = config.credentialTtlMs ?? 60_000;\n return {\n get: async (organizationId) => {\n const cached = cache.get(organizationId);\n if (cached != null && cached.expiresAtMs > now()) return cached.value;\n const value = await config.credential({ organizationId });\n if (value == null) {\n throw computersApiError(\n `this organization has no Computers API key for the computer sandbox: create an organization API key and store it as the organization secret ${COMPUTERS_API_KEY_SECRET}`,\n null,\n ComputersApiErrorCode.CredentialMissing,\n );\n }\n cache.set(organizationId, { value, expiresAtMs: now() + ttlMs });\n return value;\n },\n invalidate: (organizationId) => {\n cache.delete(organizationId);\n },\n };\n};\n\nexport const createComputersApiClient = (args: {\n config: ComputersApiConfigIface;\n credentials: ComputersApiCredentialsIface;\n organizationId: string;\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 credential = await args.credentials.get(args.organizationId);\n const transport = createTransport({\n baseUrl: args.config.url,\n auth: { apiKey: credential.apiKey },\n fetch: args.config.fetch,\n requestTimeoutMs: args.config.requestTimeoutMs,\n });\n const response = await transport.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 if (!response.ok) {\n if (response.statusCode === 401) args.credentials.invalidate(args.organizationId);\n throw computersApiError(response.error, response.statusCode ?? null);\n }\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 const { teamId } = await args.credentials.get(args.organizationId);\n const response = await request({\n method: 'POST',\n path: '/computers',\n body: teamId == null ? body : { ...body, teamId },\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;
|
|
4
|
+
"sourcesContent": ["import {\n ProcessInspectionOperation,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport {\n jsonValueSchema,\n type JsonValue,\n type SandboxCredentialsIface,\n} from '@finalai/agent-provider';\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 context's\n// `credentials.computersAccess`. 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\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 // The context's credentials; asked for access before each request.\n credentials: SandboxCredentialsIface | 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 host granted the computer sandbox 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": "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",
|
|
6
6
|
"names": ["ComputersApiErrorCode", "args"]
|
|
7
7
|
}
|
|
@@ -1,20 +1,15 @@
|
|
|
1
1
|
import { deviceEgressEnrollmentSchema, deviceEgressLeaseSchema, deviceEgressWorkspaceSchema, deviceWorkspaceNetworkStateSchema, type WorkspaceNetworkPolicyIface } from '@finalai/agent-protocol/device-egress';
|
|
2
2
|
import { type ProcessInspectionRequestIface, type ProcessInspectionResultIface } from '@finalai/agent-protocol/process-inspection';
|
|
3
|
-
import { type SandboxActingUserIface } from '@finalai/agent-provider/sandbox';
|
|
3
|
+
import { type SandboxActingUserIface, type SandboxCredentialsIface } from '@finalai/agent-provider/sandbox';
|
|
4
4
|
import * as z from 'zod';
|
|
5
5
|
import type { SandboxTransportIface } from "./transport.mjs";
|
|
6
6
|
export { DEVICE_API_ACTING_USER_HEADER } from "./environment.mjs";
|
|
7
7
|
export interface DeviceApiCallerIface {
|
|
8
8
|
organizationId: string;
|
|
9
|
+
credentials?: SandboxCredentialsIface;
|
|
9
10
|
actingUser: SandboxActingUserIface;
|
|
10
11
|
}
|
|
11
12
|
export interface DeviceApiConfigIface {
|
|
12
|
-
url: string;
|
|
13
|
-
credential: (args: {
|
|
14
|
-
organizationId: string;
|
|
15
|
-
actingUserId: string | null;
|
|
16
|
-
}) => Promise<string | null>;
|
|
17
|
-
credentialTtlMs?: number;
|
|
18
13
|
fetch?: DeviceApiFetchIface;
|
|
19
14
|
}
|
|
20
15
|
export interface DeviceApiFetchIface {
|
|
@@ -82,6 +77,7 @@ export interface DeviceApiClientIface {
|
|
|
82
77
|
egress: {
|
|
83
78
|
networkState(args: {
|
|
84
79
|
organizationId: string;
|
|
80
|
+
credentials?: SandboxCredentialsIface;
|
|
85
81
|
workspaceId: string;
|
|
86
82
|
}): Promise<z.infer<typeof deviceWorkspaceNetworkStateSchema>>;
|
|
87
83
|
setNetworkPolicy(args: {
|
|
@@ -204,5 +200,4 @@ export interface DeviceApiClientIface {
|
|
|
204
200
|
export declare const createDeviceApiClient: (config: {
|
|
205
201
|
api: DeviceApiConfigIface | (() => DeviceApiConfigIface);
|
|
206
202
|
fetch?: DeviceApiFetchIface;
|
|
207
|
-
now?: () => number;
|
|
208
203
|
}) => DeviceApiClientIface;
|
|
@@ -12,7 +12,9 @@ import {
|
|
|
12
12
|
processInspectionResultSchema
|
|
13
13
|
} from "@finalai/agent-protocol/process-inspection";
|
|
14
14
|
import { jsonObjectSchema, jsonValueSchema } from "@finalai/agent-provider";
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
SandboxEntryType
|
|
17
|
+
} from "@finalai/agent-provider/sandbox";
|
|
16
18
|
import * as z from "zod";
|
|
17
19
|
import { decodeBase64, encodeBase64 } from "./bytes.mjs";
|
|
18
20
|
import { DEVICE_API_ACTING_USER_HEADER } from "./environment.mjs";
|
|
@@ -111,7 +113,7 @@ var DeviceApiClientErrorCode = /* @__PURE__ */ ((DeviceApiClientErrorCode2) => {
|
|
|
111
113
|
const apiError = (status, code, message) => Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });
|
|
112
114
|
const credentialMissing = (actingUserId) => Object.assign(
|
|
113
115
|
new Error(
|
|
114
|
-
`Device API access is unavailable ${actingUserId == null ? "for workspace networking (no acting user)" : "for this acting user"}:
|
|
116
|
+
`Device API access is unavailable ${actingUserId == null ? "for workspace networking (no acting user)" : "for this acting user"}: the host's credentials.deviceAccess granted none`
|
|
115
117
|
),
|
|
116
118
|
{ status: null, code: "credential_missing" /* CredentialMissing */ }
|
|
117
119
|
);
|
|
@@ -142,42 +144,29 @@ const leaseOf = (raw) => ({
|
|
|
142
144
|
expiresAtMs: Date.parse(raw.expiresAt)
|
|
143
145
|
});
|
|
144
146
|
const createDeviceApiClient = (config) => {
|
|
145
|
-
const now = config.now ?? Date.now;
|
|
146
147
|
const readApi = () => typeof config.api === "function" ? config.api() : config.api;
|
|
147
|
-
const keys = /* @__PURE__ */ new Map();
|
|
148
148
|
const failure = async (response) => {
|
|
149
149
|
const text = await response.text().catch(() => "");
|
|
150
150
|
const body = errorBodySchema.safeParse(parseJson(text));
|
|
151
151
|
return body.success ? apiError(response.status, body.data.error.code, body.data.error.message) : apiError(response.status, "http", text.slice(0, 200) || response.statusText);
|
|
152
152
|
};
|
|
153
|
-
const
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const cached = keys.get(cacheKey);
|
|
161
|
-
if (cached != null && !reread) return cached.key;
|
|
162
|
-
const key = await api.credential({ organizationId, actingUserId });
|
|
163
|
-
if (key == null) {
|
|
164
|
-
keys.delete(cacheKey);
|
|
165
|
-
throw credentialMissing(actingUserId);
|
|
166
|
-
}
|
|
167
|
-
keys.set(cacheKey, { key, expiresAtMs: now() + (api.credentialTtlMs ?? 6e4) });
|
|
168
|
-
return key;
|
|
153
|
+
const accessFor = async (args) => {
|
|
154
|
+
const access = await args.caller.credentials?.deviceAccess({
|
|
155
|
+
actingUserId: args.actingUserId,
|
|
156
|
+
refresh: args.refresh
|
|
157
|
+
});
|
|
158
|
+
if (access == null) throw credentialMissing(args.actingUserId);
|
|
159
|
+
return access;
|
|
169
160
|
};
|
|
170
161
|
const send = async (args) => {
|
|
171
162
|
const api = readApi();
|
|
172
|
-
const origin = api.url.replace(/\/+$/, "");
|
|
173
|
-
const url = new URL(`${origin}${args.path}`);
|
|
174
|
-
for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);
|
|
175
163
|
const actingUserId = await args.caller.actingUser.current();
|
|
176
164
|
if (actingUserId == null && !args.anonymous) throw noActingUser();
|
|
177
165
|
const attempt = async (refresh) => {
|
|
178
|
-
const
|
|
179
|
-
|
|
180
|
-
});
|
|
166
|
+
const access = await accessFor({ caller: args.caller, actingUserId, refresh });
|
|
167
|
+
const url = new URL(`${access.baseUrl.replace(/\/+$/, "")}${args.path}`);
|
|
168
|
+
for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);
|
|
169
|
+
const headers = new Headers({ authorization: `Bearer ${access.token}` });
|
|
181
170
|
if (actingUserId != null) headers.set(DEVICE_API_ACTING_USER_HEADER, actingUserId);
|
|
182
171
|
if (args.contentType != null) headers.set("content-type", args.contentType);
|
|
183
172
|
return (config.fetch ?? api.fetch ?? fetch)(url.toString(), {
|
|
@@ -324,8 +313,8 @@ const createDeviceApiClient = (config) => {
|
|
|
324
313
|
};
|
|
325
314
|
return {
|
|
326
315
|
egress: {
|
|
327
|
-
networkState: ({ organizationId, workspaceId }) => json(deviceWorkspaceNetworkStateSchema, {
|
|
328
|
-
caller: { organizationId, actingUser: { current: async () => null } },
|
|
316
|
+
networkState: ({ organizationId, credentials, workspaceId }) => json(deviceWorkspaceNetworkStateSchema, {
|
|
317
|
+
caller: { organizationId, credentials, actingUser: { current: async () => null } },
|
|
329
318
|
anonymous: true,
|
|
330
319
|
method: "GET",
|
|
331
320
|
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/network-state`,
|