@finalai/final-agent-provider 0.11.0 → 0.13.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/README.md +1 -14
- package/dist/modules/integrations.d.mts +0 -1
- package/dist/modules/integrations.mjs +0 -2
- package/dist/modules/integrations.mjs.map +2 -2
- package/dist/modules/sandboxes/computer.d.mts +2 -4
- package/dist/modules/sandboxes/computer.mjs +110 -480
- package/dist/modules/sandboxes/computer.mjs.map +2 -2
- package/dist/modules/sandboxes/computers-api.d.mts +6 -1
- package/dist/modules/sandboxes/computers-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device-api.d.mts +8 -48
- package/dist/modules/sandboxes/device-api.mjs +2 -92
- package/dist/modules/sandboxes/device-api.mjs.map +2 -2
- package/dist/modules/sandboxes/device.d.mts +1 -1
- package/dist/modules/sandboxes/device.mjs.map +2 -2
- package/dist/modules/sandboxes/environment.d.mts +4 -0
- package/dist/modules/sandboxes/environment.mjs.map +2 -2
- package/dist/modules/sandboxes/local.d.mts +2 -1
- package/dist/modules/sandboxes/local.mjs +64 -8
- package/dist/modules/sandboxes/local.mjs.map +2 -2
- package/dist/modules/sandboxes/session.mjs +0 -1
- package/dist/modules/sandboxes/session.mjs.map +2 -2
- package/package.json +5 -57
- package/WORKSPACE-EGRESS.md +0 -184
- package/dist/modules/authoring-final-channel.d.mts +0 -3
- package/dist/modules/authoring-final-channel.mjs +0 -10
- package/dist/modules/authoring-final-channel.mjs.map +0 -7
- package/dist/modules/channel-factories.d.mts +0 -40
- package/dist/modules/channel-factories.mjs +0 -212
- package/dist/modules/channel-factories.mjs.map +0 -7
- package/dist/modules/channels/content.d.mts +0 -6
- package/dist/modules/channels/content.mjs +0 -31
- package/dist/modules/channels/content.mjs.map +0 -7
- package/dist/modules/channels/delivery.d.mts +0 -54
- package/dist/modules/channels/delivery.mjs +0 -243
- package/dist/modules/channels/delivery.mjs.map +0 -7
- package/dist/modules/channels/direct-messaging.d.mts +0 -5
- package/dist/modules/channels/direct-messaging.mjs +0 -8
- package/dist/modules/channels/direct-messaging.mjs.map +0 -7
- package/dist/modules/channels/fake-platform.d.mts +0 -36
- package/dist/modules/channels/fake-platform.mjs +0 -168
- package/dist/modules/channels/fake-platform.mjs.map +0 -7
- package/dist/modules/channels/group-messaging.d.mts +0 -5
- package/dist/modules/channels/group-messaging.mjs +0 -8
- package/dist/modules/channels/group-messaging.mjs.map +0 -7
- package/dist/modules/channels/inbound.d.mts +0 -52
- package/dist/modules/channels/inbound.mjs +0 -42
- package/dist/modules/channels/inbound.mjs.map +0 -7
- package/dist/modules/channels/index.d.mts +0 -9
- package/dist/modules/channels/index.mjs +0 -10
- package/dist/modules/channels/index.mjs.map +0 -7
- package/dist/modules/channels/messaging-channel.d.mts +0 -7
- package/dist/modules/channels/messaging-channel.mjs +0 -99
- package/dist/modules/channels/messaging-channel.mjs.map +0 -7
- package/dist/modules/channels/projection.d.mts +0 -36
- package/dist/modules/channels/projection.mjs +0 -233
- package/dist/modules/channels/projection.mjs.map +0 -7
- package/dist/modules/channels/prompt.d.mts +0 -72
- package/dist/modules/channels/prompt.mjs +0 -208
- package/dist/modules/channels/prompt.mjs.map +0 -7
- package/dist/modules/channels/routing.d.mts +0 -5
- package/dist/modules/channels/routing.mjs +0 -53
- package/dist/modules/channels/routing.mjs.map +0 -7
- package/dist/modules/sandboxes/access.d.mts +0 -34
- package/dist/modules/sandboxes/access.mjs +0 -15
- package/dist/modules/sandboxes/access.mjs.map +0 -7
- package/dist/modules/sandboxes/egress-bootstrap.d.mts +0 -3
- package/dist/modules/sandboxes/egress-bootstrap.mjs +0 -929
- package/dist/modules/sandboxes/egress-bootstrap.mjs.map +0 -7
- package/dist/modules/sandboxes/egress.d.mts +0 -94
- package/dist/modules/sandboxes/egress.mjs +0 -1561
- package/dist/modules/sandboxes/egress.mjs.map +0 -7
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import { deviceEgressEnrollmentSchema, deviceEgressLeaseSchema, deviceEgressWorkspaceSchema, deviceWorkspaceNetworkStateSchema, type WorkspaceNetworkPolicyIface } from '@finalai/agent-protocol/device-egress';
|
|
2
1
|
import { type ProcessInspectionRequestIface, type ProcessInspectionResultIface } from '@finalai/agent-protocol/process-inspection';
|
|
3
2
|
import { type SandboxActingUserIface } from '@finalai/agent-provider/sandbox';
|
|
4
|
-
import type { DeviceApiCredentialsIface } from "./access.mjs";
|
|
5
3
|
import * as z from 'zod';
|
|
4
|
+
import { type FinalPlatformAccessIface } from "./environment.mjs";
|
|
6
5
|
import type { SandboxTransportIface } from "./transport.mjs";
|
|
6
|
+
export interface DeviceApiCredentialsIface {
|
|
7
|
+
deviceAccess(args?: {
|
|
8
|
+
actingUserId?: string | null;
|
|
9
|
+
refresh?: boolean;
|
|
10
|
+
}): Promise<FinalPlatformAccessIface | null>;
|
|
11
|
+
}
|
|
7
12
|
export { DEVICE_API_ACTING_USER_HEADER } from "./environment.mjs";
|
|
8
13
|
export interface DeviceApiCallerIface {
|
|
9
14
|
organizationId: string;
|
|
@@ -65,8 +70,7 @@ export declare const DEVICE_API_FILE_CHUNK_BYTES: number;
|
|
|
65
70
|
export declare const DEVICE_API_OUTPUT_WAIT_MS = 15000;
|
|
66
71
|
export declare enum DeviceApiClientErrorCode {
|
|
67
72
|
CredentialMissing = "credential_missing",
|
|
68
|
-
NoActingUser = "no_acting_user"
|
|
69
|
-
EgressEnrollmentLost = "egress_enrollment_lost"
|
|
73
|
+
NoActingUser = "no_acting_user"
|
|
70
74
|
}
|
|
71
75
|
export interface DeviceApiErrorIface extends Error {
|
|
72
76
|
status: number | null;
|
|
@@ -75,50 +79,6 @@ export interface DeviceApiErrorIface extends Error {
|
|
|
75
79
|
export declare const deviceApiCodeOf: (cause: unknown) => string | null;
|
|
76
80
|
export declare const deviceApiStatusOf: (cause: Error) => number | null;
|
|
77
81
|
export interface DeviceApiClientIface {
|
|
78
|
-
egress: {
|
|
79
|
-
networkState(args: {
|
|
80
|
-
organizationId: string;
|
|
81
|
-
credentials?: DeviceApiCredentialsIface;
|
|
82
|
-
workspaceId: string;
|
|
83
|
-
}): Promise<z.infer<typeof deviceWorkspaceNetworkStateSchema>>;
|
|
84
|
-
setNetworkPolicy(args: {
|
|
85
|
-
caller: DeviceApiCallerIface;
|
|
86
|
-
workspaceId: string;
|
|
87
|
-
policy: WorkspaceNetworkPolicyIface;
|
|
88
|
-
initializeIfMissing?: boolean;
|
|
89
|
-
}): Promise<void>;
|
|
90
|
-
workspace(args: {
|
|
91
|
-
caller: DeviceApiCallerIface;
|
|
92
|
-
workspaceId: string;
|
|
93
|
-
}): Promise<z.infer<typeof deviceEgressWorkspaceSchema>>;
|
|
94
|
-
create(args: {
|
|
95
|
-
caller: DeviceApiCallerIface;
|
|
96
|
-
workspaceId: string;
|
|
97
|
-
deviceIds: string[];
|
|
98
|
-
dnsResolvers?: string[];
|
|
99
|
-
}): Promise<z.infer<typeof deviceEgressEnrollmentSchema>>;
|
|
100
|
-
renew(args: {
|
|
101
|
-
caller: DeviceApiCallerIface;
|
|
102
|
-
leaseId: string;
|
|
103
|
-
}): Promise<z.infer<typeof deviceEgressLeaseSchema>>;
|
|
104
|
-
activate(args: {
|
|
105
|
-
caller: DeviceApiCallerIface;
|
|
106
|
-
leaseId: string;
|
|
107
|
-
}): Promise<z.infer<typeof deviceEgressLeaseSchema>>;
|
|
108
|
-
revoke(args: {
|
|
109
|
-
caller: DeviceApiCallerIface;
|
|
110
|
-
leaseId: string;
|
|
111
|
-
workspaceId: string;
|
|
112
|
-
}): Promise<void>;
|
|
113
|
-
disable(args: {
|
|
114
|
-
caller: DeviceApiCallerIface;
|
|
115
|
-
workspaceId: string;
|
|
116
|
-
}): Promise<void>;
|
|
117
|
-
suspend(args: {
|
|
118
|
-
caller: DeviceApiCallerIface;
|
|
119
|
-
workspaceId: string;
|
|
120
|
-
}): Promise<void>;
|
|
121
|
-
};
|
|
122
82
|
releaseWorkspaceLeases(args: {
|
|
123
83
|
caller: DeviceApiCallerIface;
|
|
124
84
|
deviceId: string;
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
deviceEgressCreateRequestSchema,
|
|
3
|
-
deviceEgressWorkspaceIdSchema,
|
|
4
|
-
deviceEgressEnrollmentSchema,
|
|
5
|
-
deviceEgressLeaseSchema,
|
|
6
|
-
deviceEgressWorkspaceSchema,
|
|
7
|
-
workspaceNetworkPolicySchema,
|
|
8
|
-
deviceWorkspaceNetworkStateSchema
|
|
9
|
-
} from "@finalai/agent-protocol/device-egress";
|
|
10
1
|
import {
|
|
11
2
|
ProcessInspectionOperation,
|
|
12
3
|
processInspectionResultSchema
|
|
@@ -106,13 +97,12 @@ const DEVICE_PROCESS_GONE_MESSAGE = /unknown process|belongs to another device r
|
|
|
106
97
|
var DeviceApiClientErrorCode = /* @__PURE__ */ ((DeviceApiClientErrorCode2) => {
|
|
107
98
|
DeviceApiClientErrorCode2["CredentialMissing"] = "credential_missing";
|
|
108
99
|
DeviceApiClientErrorCode2["NoActingUser"] = "no_acting_user";
|
|
109
|
-
DeviceApiClientErrorCode2["EgressEnrollmentLost"] = "egress_enrollment_lost";
|
|
110
100
|
return DeviceApiClientErrorCode2;
|
|
111
101
|
})(DeviceApiClientErrorCode || {});
|
|
112
102
|
const apiError = (status, code, message) => Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });
|
|
113
103
|
const credentialMissing = (actingUserId) => Object.assign(
|
|
114
104
|
new Error(
|
|
115
|
-
`Device API access is unavailable ${actingUserId == null ? "
|
|
105
|
+
`Device API access is unavailable ${actingUserId == null ? "without an acting user" : "for this acting user"}: the provider's configured Device API access granted none`
|
|
116
106
|
),
|
|
117
107
|
{ status: null, code: "credential_missing" /* CredentialMissing */ }
|
|
118
108
|
);
|
|
@@ -160,7 +150,7 @@ const createDeviceApiClient = (config) => {
|
|
|
160
150
|
const send = async (args) => {
|
|
161
151
|
const api = readApi();
|
|
162
152
|
const actingUserId = await args.caller.actingUser.current();
|
|
163
|
-
if (actingUserId == null
|
|
153
|
+
if (actingUserId == null) throw noActingUser();
|
|
164
154
|
const attempt = async (refresh) => {
|
|
165
155
|
const access = await accessFor({ caller: args.caller, actingUserId, refresh });
|
|
166
156
|
const url = new URL(`${access.baseUrl.replace(/\/+$/, "")}${args.path}`);
|
|
@@ -318,86 +308,6 @@ const createDeviceApiClient = (config) => {
|
|
|
318
308
|
};
|
|
319
309
|
};
|
|
320
310
|
return {
|
|
321
|
-
egress: {
|
|
322
|
-
networkState: ({ organizationId, credentials, workspaceId }) => json(deviceWorkspaceNetworkStateSchema, {
|
|
323
|
-
caller: { organizationId, credentials, actingUser: { current: async () => null } },
|
|
324
|
-
anonymous: true,
|
|
325
|
-
method: "GET",
|
|
326
|
-
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/network-state`,
|
|
327
|
-
signal: AbortSignal.timeout(3e4)
|
|
328
|
-
}),
|
|
329
|
-
setNetworkPolicy: async ({ caller, workspaceId, policy, initializeIfMissing }) => {
|
|
330
|
-
const userId = await caller.actingUser.current();
|
|
331
|
-
const anonymous = userId == null;
|
|
332
|
-
const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };
|
|
333
|
-
const result = await json(z.object({ ok: z.boolean() }), {
|
|
334
|
-
caller: resolvedCaller,
|
|
335
|
-
method: initializeIfMissing === true ? "POST" : "PUT",
|
|
336
|
-
anonymous,
|
|
337
|
-
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${initializeIfMissing === true ? "network-state/initialize" : anonymous ? "network-state" : "network-policy"}`,
|
|
338
|
-
json: workspaceNetworkPolicySchema.parse(policy),
|
|
339
|
-
signal: AbortSignal.timeout(3e4)
|
|
340
|
-
});
|
|
341
|
-
if (!result.ok) throw new Error("Device API did not save the workspace network policy");
|
|
342
|
-
},
|
|
343
|
-
workspace: ({ caller, workspaceId }) => json(deviceEgressWorkspaceSchema, {
|
|
344
|
-
caller,
|
|
345
|
-
method: "GET",
|
|
346
|
-
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,
|
|
347
|
-
signal: AbortSignal.timeout(3e4)
|
|
348
|
-
}),
|
|
349
|
-
create: ({ caller, ...input }) => json(deviceEgressEnrollmentSchema, {
|
|
350
|
-
caller,
|
|
351
|
-
method: "POST",
|
|
352
|
-
path: "/v1/egress/leases",
|
|
353
|
-
json: deviceEgressCreateRequestSchema.parse(input),
|
|
354
|
-
signal: AbortSignal.timeout(18e4)
|
|
355
|
-
}),
|
|
356
|
-
renew: ({ caller, leaseId }) => json(deviceEgressLeaseSchema, {
|
|
357
|
-
caller,
|
|
358
|
-
method: "POST",
|
|
359
|
-
path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/renew`,
|
|
360
|
-
signal: AbortSignal.timeout(18e4)
|
|
361
|
-
}),
|
|
362
|
-
activate: ({ caller, leaseId }) => json(deviceEgressLeaseSchema, {
|
|
363
|
-
caller,
|
|
364
|
-
method: "POST",
|
|
365
|
-
path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/activate`,
|
|
366
|
-
signal: AbortSignal.timeout(6e4)
|
|
367
|
-
}),
|
|
368
|
-
revoke: async ({ caller, leaseId, workspaceId }) => {
|
|
369
|
-
await json(emptySchema, {
|
|
370
|
-
caller,
|
|
371
|
-
method: "DELETE",
|
|
372
|
-
json: { workspaceId },
|
|
373
|
-
path: `/v1/egress/leases/${encodeURIComponent(leaseId)}`,
|
|
374
|
-
signal: AbortSignal.timeout(6e4)
|
|
375
|
-
});
|
|
376
|
-
},
|
|
377
|
-
suspend: async ({
|
|
378
|
-
caller,
|
|
379
|
-
workspaceId
|
|
380
|
-
}) => {
|
|
381
|
-
const userId = await caller.actingUser.current();
|
|
382
|
-
const anonymous = userId == null;
|
|
383
|
-
const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };
|
|
384
|
-
await json(emptySchema, {
|
|
385
|
-
caller: resolvedCaller,
|
|
386
|
-
anonymous,
|
|
387
|
-
method: "POST",
|
|
388
|
-
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${anonymous ? "network-state/suspend" : "suspend"}`,
|
|
389
|
-
signal: AbortSignal.timeout(6e4)
|
|
390
|
-
});
|
|
391
|
-
},
|
|
392
|
-
disable: async ({ caller, workspaceId }) => {
|
|
393
|
-
await json(emptySchema, {
|
|
394
|
-
caller,
|
|
395
|
-
method: "DELETE",
|
|
396
|
-
path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,
|
|
397
|
-
signal: AbortSignal.timeout(6e4)
|
|
398
|
-
});
|
|
399
|
-
}
|
|
400
|
-
},
|
|
401
311
|
releaseWorkspaceLeases: async ({ caller, deviceId, bindingId }) => {
|
|
402
312
|
const result = await json(z.object({ released: z.boolean() }), {
|
|
403
313
|
caller,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/device-api.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n deviceEgressCreateRequestSchema,\n deviceEgressWorkspaceIdSchema,\n deviceEgressEnrollmentSchema,\n deviceEgressLeaseSchema,\n deviceEgressWorkspaceSchema,\n workspaceNetworkPolicySchema,\n deviceWorkspaceNetworkStateSchema,\n type WorkspaceNetworkPolicyIface,\n} from '@finalai/agent-protocol/device-egress';\nimport {\n ProcessInspectionOperation,\n processInspectionResultSchema,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport { jsonObjectSchema, jsonValueSchema, type JsonValue } from '@finalai/agent-provider';\nimport { SandboxEntryType, type SandboxActingUserIface } from '@finalai/agent-provider/sandbox';\nimport type { DeviceApiCredentialsIface, FinalPlatformAccessIface } from \"./access.mjs\";\nimport * as z from 'zod';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// A client of the Device API, authenticated with the provider's configured\n// access (./access.ts). Device operations also name the acting user; the API\n// enforces ownership independently of the token.\n\n// The Device API's header naming the user a request acts for (a Final user id).\nexport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\n\n// The organization, credentials and user a call acts for; the user is read on each\n// call. Workspace networking also calls with no user (admission, policy\n// persistence and cleanup), which needs service access from `deviceAccess`.\nexport interface DeviceApiCallerIface {\n organizationId: string;\n credentials?: DeviceApiCredentialsIface;\n actingUser: SandboxActingUserIface;\n}\n\n// Transport options; the API origin and token come from the caller's credentials.\nexport interface DeviceApiConfigIface {\n fetch?: DeviceApiFetchIface;\n}\n\nexport interface DeviceApiFetchIface {\n (input: string, init: RequestInit): Promise<Response>;\n}\n\nexport enum DeviceApiLeaseAccess {\n Read = 'read',\n Write = 'write',\n}\n\nexport enum DeviceApiCapability {\n Files = 'files',\n Process = 'process',\n ComputerUse = 'computer-use',\n LocalMcp = 'local-mcp',\n}\n\nexport const DEVICE_API_COMPUTER_USE_SERVER = 'computer-use';\n\n// Unknown values from a newer API read as absent rather than failing the call.\nconst tolerantEnum = <T extends Record<string, string>>(values: T) =>\n z.string().transform((value): T[keyof T] | null => {\n const parsed = z.nativeEnum(values).safeParse(value);\n return parsed.success ? parsed.data : null;\n });\n\nconst deviceSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n displayName: z.string(),\n os: z.string(),\n online: z.boolean(),\n writable: z.boolean(),\n allowProcesses: z.boolean(),\n computerUseReady: z.boolean(),\n screenReady: z.boolean(),\n});\nexport type DeviceApiDeviceIface = z.infer<typeof deviceSchema>;\n\nconst leaseSchema = z.object({\n lease: z.string(),\n deviceId: z.string(),\n generation: z.number(),\n workspaceRoot: z.string(),\n platform: z.string(),\n access: z.nativeEnum(DeviceApiLeaseAccess),\n capabilities: z.array(tolerantEnum(DeviceApiCapability)),\n expiresAt: z.string(),\n});\nexport interface DeviceApiLeaseIface {\n lease: string;\n deviceId: string;\n generation: number;\n workspaceRoot: string;\n platform: string;\n access: DeviceApiLeaseAccess;\n capabilities: DeviceApiCapability[];\n expiresAtMs: number;\n}\n\ninterface ProcessInputBodyIface {\n bootId: string;\n dataBase64?: string;\n eof?: boolean;\n}\n\nconst errorBodySchema = z.object({ error: z.object({ code: z.string(), message: z.string() }) });\nconst statBodySchema = z.object({\n stat: z\n .object({\n type: tolerantEnum(SandboxEntryType),\n size: z.number(),\n modifiedAtMs: z.number().nullable(),\n mode: z.number().nullable(),\n })\n .nullable(),\n});\nconst dirBodySchema = z.object({\n entries: z.array(\n z.object({\n name: z.string(),\n type: tolerantEnum(SandboxEntryType),\n size: z.number().nullable(),\n }),\n ),\n});\nconst processSchema = z.object({ id: z.string(), bootId: z.string() });\nconst outputStreamSchema = z.object({\n dataBase64: z.string(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst outputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n exited: z.boolean(),\n exitCode: z.number().nullable(),\n exitSignal: z.string().nullable(),\n});\nconst devicesSchema = z.object({ devices: z.array(deviceSchema) });\nconst serversSchema = z.object({ servers: z.array(z.string()) });\n// A Device server's tool as the API recorded it; checked against the tool\n// descriptor contract where the provider hands it on.\nconst catalogToolSchema = jsonObjectSchema;\nconst mcpCatalogSchema = z.object({\n computerUse: z.object({ tools: z.array(catalogToolSchema) }).nullable(),\n localServers: z\n .object({\n servers: z.array(\n z.object({ name: z.string(), tools: z.array(catalogToolSchema).nullable() }),\n ),\n })\n .nullable(),\n});\nexport type DeviceApiMcpCatalogIface = z.infer<typeof mcpCatalogSchema>;\nconst pipeReadSchema = z.object({ dataBase64: z.string().optional() });\nconst screenSchema = z.object({ url: z.string(), token: z.string(), expiresAt: z.string() });\nconst emptySchema = z.unknown();\n\n// One ranged read or write; the API splits it into the Device's own chunks.\nexport const DEVICE_API_FILE_CHUNK_BYTES = 4 * 1024 * 1024;\n// The API long-polls the Device for output up to this long.\nexport const DEVICE_API_OUTPUT_WAIT_MS = 15_000;\n// How the Device reports a lease process it no longer has (relayed as a 502):\n// unknown in this lease, from an earlier runtime, or retired after its output\n// was read to the end.\nconst DEVICE_PROCESS_GONE_MESSAGE =\n /unknown process|belongs to another device runtime|consumed output has expired/i;\n\nexport enum DeviceApiClientErrorCode {\n // The host granted no access for this user or trusted service call.\n CredentialMissing = 'credential_missing',\n // The session acts for no user, and a Device is only used for its owner.\n NoActingUser = 'no_acting_user',\n EgressEnrollmentLost = 'egress_enrollment_lost',\n}\n\nexport interface DeviceApiErrorIface extends Error {\n status: number | null;\n code: string;\n}\n\nconst apiError = (status: number, code: string, message: string): DeviceApiErrorIface =>\n Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });\n\nconst credentialMissing = (actingUserId: string | null): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n `Device API access is unavailable ${actingUserId == null ? 'for workspace networking (no acting user)' : 'for this acting user'}: the provider's configured Device API access granted none`,\n ),\n { status: null, code: DeviceApiClientErrorCode.CredentialMissing },\n );\n\nconst noActingUser = (): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n 'this session acts for no user, and a Final Device is only used by sessions acting for its owner',\n ),\n { status: null, code: DeviceApiClientErrorCode.NoActingUser },\n );\n\nconst statusSchema = z.object({ status: z.number() });\nexport const deviceApiCodeOf = (cause: unknown): string | null =>\n z.object({ code: z.string() }).safeParse(cause).data?.code ?? null;\n\nexport const deviceApiStatusOf = (cause: Error): number | null =>\n statusSchema.safeParse(cause).data?.status ?? null;\n\nconst parseJson = (text: string): JsonValue => {\n try {\n return jsonValueSchema.parse(JSON.parse(text));\n } catch {\n return null;\n }\n};\n\nconst leaseOf = (raw: z.infer<typeof leaseSchema>): DeviceApiLeaseIface => ({\n lease: raw.lease,\n deviceId: raw.deviceId,\n generation: raw.generation,\n workspaceRoot: raw.workspaceRoot,\n platform: raw.platform,\n access: raw.access,\n capabilities: raw.capabilities.filter((capability) => capability != null),\n expiresAtMs: Date.parse(raw.expiresAt),\n});\n\nexport interface DeviceApiClientIface {\n egress: {\n networkState(args: {\n organizationId: string;\n credentials?: DeviceApiCredentialsIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceWorkspaceNetworkStateSchema>>;\n setNetworkPolicy(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n policy: WorkspaceNetworkPolicyIface;\n initializeIfMissing?: boolean;\n }): Promise<void>;\n workspace(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }): Promise<z.infer<typeof deviceEgressWorkspaceSchema>>;\n create(args: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n deviceIds: string[];\n dnsResolvers?: string[];\n }): Promise<z.infer<typeof deviceEgressEnrollmentSchema>>;\n renew(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n activate(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n }): Promise<z.infer<typeof deviceEgressLeaseSchema>>;\n revoke(args: {\n caller: DeviceApiCallerIface;\n leaseId: string;\n workspaceId: string;\n }): Promise<void>;\n disable(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n suspend(args: { caller: DeviceApiCallerIface; workspaceId: string }): Promise<void>;\n };\n releaseWorkspaceLeases(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n }): Promise<void>;\n inspectProcesses(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n request: ProcessInspectionRequestIface;\n }): Promise<ProcessInspectionResultIface>;\n getDevice(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiDeviceIface | null>;\n // The Devices of the user the call acts for.\n listDevices(args: { caller: DeviceApiCallerIface }): Promise<DeviceApiDeviceIface[]>;\n resolvePairing(args: {\n caller: DeviceApiCallerIface;\n code: string;\n }): Promise<DeviceApiDeviceIface | null>;\n lease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n ttlMs: number;\n afterGeneration?: number;\n }): Promise<DeviceApiLeaseIface>;\n recoverLease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n }): Promise<DeviceApiLeaseIface>;\n renew(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n ttlMs: number;\n }): Promise<DeviceApiLeaseIface>;\n release(args: { caller: DeviceApiCallerIface; lease: string }): Promise<void>;\n // The sandbox transport over one lease; `lease()` is the current handle.\n transport(args: {\n caller: DeviceApiCallerIface;\n lease: () => Promise<string>;\n }): SandboxTransportIface;\n localMcpServers(args: { caller: DeviceApiCallerIface; lease: string }): Promise<string[]>;\n // What the Device's MCP servers last listed through the API, without a lease.\n mcpCatalog(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiMcpCatalogIface>;\n pipe(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n server: string;\n action: 'open' | 'write' | 'read' | 'close';\n clientId: string;\n dataBase64?: string;\n signal?: AbortSignal;\n }): Promise<string>;\n screen(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n viewOnly?: boolean;\n }): Promise<{ url: string; token: string; expiresAt: string }>;\n}\n\nexport const createDeviceApiClient = (config: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n fetch?: DeviceApiFetchIface;\n}): DeviceApiClientIface => {\n const readApi = () => (typeof config.api === 'function' ? config.api() : config.api);\n const failure = async (response: Response): Promise<DeviceApiErrorIface> => {\n // Read as text so proxy and load balancer error pages survive.\n const text = await response.text().catch(() => '');\n const body = errorBodySchema.safeParse(parseJson(text));\n return body.success\n ? apiError(response.status, body.data.error.code, body.data.error.message)\n : apiError(response.status, 'http', text.slice(0, 200) || response.statusText);\n };\n\n const accessFor = async (args: {\n caller: DeviceApiCallerIface;\n actingUserId: string | null;\n refresh: boolean;\n }): Promise<FinalPlatformAccessIface> => {\n const access = await args.caller.credentials?.deviceAccess({\n actingUserId: args.actingUserId,\n refresh: args.refresh,\n });\n if (access == null) throw credentialMissing(args.actingUserId);\n return access;\n };\n\n // One authenticated call for the user it acts for; rejected access is asked for\n // again once, in case it expired.\n const send = async (args: {\n caller: DeviceApiCallerIface;\n method: string;\n path: string;\n query?: Record<string, string>;\n body?: BodyInit;\n contentType?: string;\n signal?: AbortSignal;\n anonymous?: boolean;\n }): Promise<Response> => {\n const api = readApi();\n const actingUserId = await args.caller.actingUser.current();\n if (actingUserId == null && !args.anonymous) throw noActingUser();\n const attempt = async (refresh: boolean): Promise<Response> => {\n const access = await accessFor({ caller: args.caller, actingUserId, refresh });\n const url = new URL(`${access.baseUrl.replace(/\\/+$/, '')}${args.path}`);\n for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);\n const headers = new Headers({ authorization: `Bearer ${access.token}` });\n if (actingUserId != null) headers.set(DEVICE_API_ACTING_USER_HEADER, actingUserId);\n if (args.contentType != null) headers.set('content-type', args.contentType);\n return (config.fetch ?? api.fetch ?? fetch)(url.toString(), {\n method: args.method,\n headers,\n body: args.body,\n signal: args.signal,\n });\n };\n let response = await attempt(false);\n if (response.status === 401) {\n await response.text().catch(() => '');\n response = await attempt(true);\n }\n return response;\n };\n\n const json = async <T extends z.ZodType>(\n schema: T,\n args: Parameters<typeof send>[0] & { json?: unknown },\n ): Promise<z.infer<T>> => {\n const response = await send({\n ...args,\n body: args.json === undefined ? args.body : JSON.stringify(args.json),\n contentType: args.json === undefined ? args.contentType : 'application/json',\n });\n if (!response.ok) throw await failure(response);\n const text = await response.text();\n return schema.parse(text === '' ? null : parseJson(text));\n };\n\n // A 404 reads as absent.\n const orNull = async <T>(work: Promise<T>): Promise<T | null> => {\n try {\n return await work;\n } catch (cause) {\n if (cause instanceof Error && deviceApiStatusOf(cause) === 404) return null;\n throw cause;\n }\n };\n\n const leasePath = (lease: string, rest: string): string =>\n `/v1/leases/${encodeURIComponent(lease)}${rest}`;\n\n const transport: DeviceApiClientIface['transport'] = ({ caller, lease }) => {\n const call = async <T extends z.ZodType>(\n schema: T,\n args: Omit<Parameters<typeof json>[1], 'caller' | 'path'> & { path: string },\n ): Promise<z.infer<T>> =>\n json(schema, { ...args, caller, path: leasePath(await lease(), args.path) });\n const processPath = (id: string, rest: string): string =>\n `/processes/${encodeURIComponent(id)}${rest}`;\n return {\n kind: 'device-api',\n fileChunkBytes: DEVICE_API_FILE_CHUNK_BYTES,\n outputWaitMs: DEVICE_API_OUTPUT_WAIT_MS,\n stat: async ({ path, signal }): Promise<TransportStatIface | null> => {\n const { stat } = await call(statBodySchema, {\n method: 'GET',\n path: '/files/stat',\n query: { path },\n signal,\n });\n return stat == null ? null : { ...stat, type: stat.type ?? SandboxEntryType.Other };\n },\n readDir: async ({ path, signal }): Promise<TransportDirEntryIface[]> =>\n (\n await call(dirBodySchema, { method: 'GET', path: '/files/dir', query: { path }, signal })\n ).entries.map((entry) => ({ ...entry, type: entry.type ?? SandboxEntryType.Other })),\n readChunk: async ({ path, offset, length, signal }) => {\n const response = await send({\n caller,\n method: 'GET',\n path: leasePath(await lease(), '/files/content'),\n query: { path, offset: String(offset), length: String(length) },\n signal,\n });\n if (!response.ok) throw await failure(response);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return { bytes, eof: bytes.byteLength < length };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await call(emptySchema, {\n method: 'PUT',\n path: '/files/content',\n query: { path, offset: String(offset) },\n body: new Blob([bytes.slice()]),\n contentType: 'application/octet-stream',\n signal,\n });\n },\n createDirectory: async ({ path, signal }) => {\n await call(emptySchema, {\n method: 'POST',\n path: '/files/directories',\n json: { path },\n signal,\n });\n },\n remove: async ({ path, recursive, force, signal }) => {\n await call(emptySchema, {\n method: 'DELETE',\n path: '/files',\n query: { path, recursive: String(recursive), force: String(force) },\n signal,\n });\n },\n exec: async ({ id, command, cwd, env, timeoutMs, signal }) =>\n call(processSchema, {\n method: 'POST',\n path: '/processes',\n json: { id, command, cwd, env, timeoutMs },\n signal,\n }),\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) => {\n const output = await call(outputSchema, {\n method: 'POST',\n path: processPath(process.id, '/output'),\n json: { bootId: process.bootId, stdoutOffset, stderrOffset, waitMs },\n signal,\n });\n const stream = (value: z.infer<typeof outputStreamSchema>) => ({\n data: decodeBase64(value.dataBase64),\n nextOffset: value.nextOffset,\n eof: value.eof,\n });\n const result: TransportOutputIface = {\n stdout: stream(output.stdout),\n stderr: stream(output.stderr),\n exited: output.exited,\n exitCode: output.exitCode,\n exitSignal: output.exitSignal,\n };\n return result;\n },\n input: async ({ process, data, eof, signal, terminate, abortSignal }) => {\n if (terminate === true || signal != null) {\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/kill'),\n json:\n terminate === true ? { bootId: process.bootId } : { bootId: process.bootId, signal },\n signal: abortSignal,\n });\n if (terminate === true) return;\n }\n if ((data != null && data.byteLength > 0) || eof === true) {\n const body: ProcessInputBodyIface = {\n bootId: process.bootId,\n };\n if (data != null && data.byteLength > 0) body.dataBase64 = encodeBase64(data);\n if (eof === true) body.eof = true;\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/input'),\n json: body,\n signal: abortSignal,\n });\n }\n },\n // Lease processes run on the Device and are found again by id and boot\n // while the lease generation lasts.\n processGone: (cause) => {\n if (!(cause instanceof Error)) return false;\n const status = deviceApiStatusOf(cause);\n return (\n status === 404 || (status === 502 && DEVICE_PROCESS_GONE_MESSAGE.test(cause.message))\n );\n },\n close: () => undefined,\n };\n };\n\n return {\n egress: {\n networkState: ({ organizationId, credentials, workspaceId }) =>\n json(deviceWorkspaceNetworkStateSchema, {\n caller: { organizationId, credentials, actingUser: { current: async () => null } },\n anonymous: true,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/network-state`,\n signal: AbortSignal.timeout(30_000),\n }),\n setNetworkPolicy: async ({ caller, workspaceId, policy, initializeIfMissing }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n const result = await json(z.object({ ok: z.boolean() }), {\n caller: resolvedCaller,\n method: initializeIfMissing === true ? 'POST' : 'PUT',\n anonymous,\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${initializeIfMissing === true ? 'network-state/initialize' : anonymous ? 'network-state' : 'network-policy'}`,\n json: workspaceNetworkPolicySchema.parse(policy),\n signal: AbortSignal.timeout(30_000),\n });\n if (!result.ok) throw new Error('Device API did not save the workspace network policy');\n },\n workspace: ({ caller, workspaceId }) =>\n json(deviceEgressWorkspaceSchema, {\n caller,\n method: 'GET',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(30_000),\n }),\n create: ({ caller, ...input }) =>\n json(deviceEgressEnrollmentSchema, {\n caller,\n method: 'POST',\n path: '/v1/egress/leases',\n json: deviceEgressCreateRequestSchema.parse(input),\n signal: AbortSignal.timeout(180_000),\n }),\n renew: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/renew`,\n signal: AbortSignal.timeout(180_000),\n }),\n activate: ({ caller, leaseId }) =>\n json(deviceEgressLeaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}/activate`,\n signal: AbortSignal.timeout(60_000),\n }),\n revoke: async ({ caller, leaseId, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n json: { workspaceId },\n path: `/v1/egress/leases/${encodeURIComponent(leaseId)}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n suspend: async ({\n caller,\n workspaceId,\n }: {\n caller: DeviceApiCallerIface;\n workspaceId: string;\n }) => {\n const userId = await caller.actingUser.current();\n const anonymous = userId == null;\n const resolvedCaller = { ...caller, actingUser: { current: async () => userId } };\n await json(emptySchema, {\n caller: resolvedCaller,\n anonymous,\n method: 'POST',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}/${anonymous ? 'network-state/suspend' : 'suspend'}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n disable: async ({ caller, workspaceId }) => {\n await json(emptySchema, {\n caller,\n method: 'DELETE',\n path: `/v1/egress/workspaces/${encodeURIComponent(deviceEgressWorkspaceIdSchema.parse(workspaceId))}`,\n signal: AbortSignal.timeout(60_000),\n });\n },\n },\n releaseWorkspaceLeases: async ({ caller, deviceId, bindingId }) => {\n const result = await json(z.object({ released: z.boolean() }), {\n caller,\n method: 'DELETE',\n path:\n '/v1/devices/' +\n encodeURIComponent(deviceId) +\n '/workspaces/' +\n encodeURIComponent(bindingId) +\n '/leases',\n });\n if (!result.released) throw new Error('The Device did not release its workspace leases');\n },\n inspectProcesses: ({ caller, deviceId, bindingId, request }) => {\n const suffix =\n request.operation === ProcessInspectionOperation.Available\n ? '/available'\n : 'processId' in request\n ? '/' + encodeURIComponent(request.processId)\n : '';\n const query: Record<string, string> = {};\n if (bindingId != null) query.bindingId = bindingId;\n if ('bootId' in request) query.bootId = request.bootId;\n if ('cursor' in request && request.cursor != null) query.cursor = request.cursor;\n if ('limit' in request && request.limit != null) query.limit = String(request.limit);\n return json(processInspectionResultSchema, {\n caller,\n method: request.operation === ProcessInspectionOperation.Stop ? 'DELETE' : 'GET',\n path: '/v1/devices/' + encodeURIComponent(deviceId) + '/processes' + suffix,\n query,\n });\n },\n getDevice: ({ caller, deviceId }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}`,\n }),\n ),\n listDevices: async ({ caller }) =>\n (await json(devicesSchema, { caller, method: 'GET', path: '/v1/devices' })).devices,\n resolvePairing: ({ caller, code }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'POST',\n path: '/v1/pairings/resolve',\n json: { code },\n }),\n ),\n lease: async ({ caller, deviceId, sessionId, bindingId, access, ttlMs, afterGeneration }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases`,\n json: { sessionId, bindingId, access, ttlMs, afterGeneration },\n }),\n ),\n recoverLease: async ({ caller, deviceId, sessionId, bindingId, access }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases/recover`,\n json: { sessionId, bindingId, access },\n }),\n ),\n renew: async ({ caller, lease, ttlMs }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, '/renew'),\n json: { ttlMs },\n }),\n ),\n release: async ({ caller, lease }) => {\n await json(emptySchema, { caller, method: 'DELETE', path: leasePath(lease, '') });\n },\n transport,\n mcpCatalog: ({ caller, deviceId }) =>\n json(mcpCatalogSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/mcp`,\n }),\n localMcpServers: async ({ caller, lease }) =>\n (await json(serversSchema, { caller, method: 'GET', path: leasePath(lease, '/mcp') }))\n .servers,\n pipe: async ({ caller, lease, server, action, clientId, dataBase64, signal }) =>\n (\n await json(pipeReadSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, `/mcp/${encodeURIComponent(server)}/${action}`),\n json: dataBase64 == null ? { clientId } : { clientId, dataBase64 },\n signal,\n })\n ).dataBase64 ?? '',\n screen: ({ caller, deviceId, sessionId, viewOnly }) =>\n json(screenSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/screen`,\n json: { sessionId, viewOnly },\n }),\n };\n};\n"],
|
|
5
|
-
"mappings": "AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAGK;AACP,SAAS,kBAAkB,uBAAuC;AAClE,SAAS,wBAAqD;AAE9D,YAAY,OAAO;AACnB,SAAS,cAAc,oBAAoB;AAC3C,SAAS,qCAAqC;AAa9C,SAAS,iCAAAA,sCAAqC;AAoBvC,IAAK,uBAAL,kBAAKC,0BAAL;AACL,EAAAA,sBAAA,UAAO;AACP,EAAAA,sBAAA,WAAQ;AAFE,SAAAA;AAAA,GAAA;AAKL,IAAK,sBAAL,kBAAKC,yBAAL;AACL,EAAAA,qBAAA,WAAQ;AACR,EAAAA,qBAAA,aAAU;AACV,EAAAA,qBAAA,iBAAc;AACd,EAAAA,qBAAA,cAAW;AAJD,SAAAA;AAAA,GAAA;AAOL,MAAM,iCAAiC;AAG9C,MAAM,eAAe,CAAmC,WACtD,EAAE,OAAO,EAAE,UAAU,CAAC,UAA6B;AACjD,QAAM,SAAS,EAAE,WAAW,MAAM,EAAE,UAAU,KAAK;AACnD,SAAO,OAAO,UAAU,OAAO,OAAO;AACxC,CAAC;AAEH,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,IAAI,EAAE,OAAO;AAAA,EACb,gBAAgB,EAAE,OAAO;AAAA,EACzB,aAAa,EAAE,OAAO;AAAA,EACtB,IAAI,EAAE,OAAO;AAAA,EACb,QAAQ,EAAE,QAAQ;AAAA,EAClB,UAAU,EAAE,QAAQ;AAAA,EACpB,gBAAgB,EAAE,QAAQ;AAAA,EAC1B,kBAAkB,EAAE,QAAQ;AAAA,EAC5B,aAAa,EAAE,QAAQ;AACzB,CAAC;AAGD,MAAM,cAAc,EAAE,OAAO;AAAA,EAC3B,OAAO,EAAE,OAAO;AAAA,EAChB,UAAU,EAAE,OAAO;AAAA,EACnB,YAAY,EAAE,OAAO;AAAA,EACrB,eAAe,EAAE,OAAO;AAAA,EACxB,UAAU,EAAE,OAAO;AAAA,EACnB,QAAQ,EAAE,WAAW,oBAAoB;AAAA,EACzC,cAAc,EAAE,MAAM,aAAa,mBAAmB,CAAC;AAAA,EACvD,WAAW,EAAE,OAAO;AACtB,CAAC;AAkBD,MAAM,kBAAkB,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;AAC/F,MAAM,iBAAiB,EAAE,OAAO;AAAA,EAC9B,MAAM,EACH,OAAO;AAAA,IACN,MAAM,aAAa,gBAAgB;AAAA,IACnC,MAAM,EAAE,OAAO;AAAA,IACf,cAAc,EAAE,OAAO,EAAE,SAAS;AAAA,IAClC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5B,CAAC,EACA,SAAS;AACd,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,SAAS,EAAE;AAAA,IACT,EAAE,OAAO;AAAA,MACP,MAAM,EAAE,OAAO;AAAA,MACf,MAAM,aAAa,gBAAgB;AAAA,MACnC,MAAM,EAAE,OAAO,EAAE,SAAS;AAAA,IAC5B,CAAC;AAAA,EACH;AACF,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,OAAO,EAAE,CAAC;AACrE,MAAM,qBAAqB,EAAE,OAAO;AAAA,EAClC,YAAY,EAAE,OAAO;AAAA,EACrB,YAAY,EAAE,OAAO;AAAA,EACrB,KAAK,EAAE,QAAQ;AACjB,CAAC;AACD,MAAM,eAAe,EAAE,OAAO;AAAA,EAC5B,QAAQ;AAAA,EACR,QAAQ;AAAA,EACR,QAAQ,EAAE,QAAQ;AAAA,EAClB,UAAU,EAAE,OAAO,EAAE,SAAS;AAAA,EAC9B,YAAY,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AACD,MAAM,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,EAAE,CAAC;AACjE,MAAM,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,CAAC;AAG/D,MAAM,oBAAoB;AAC1B,MAAM,mBAAmB,EAAE,OAAO;AAAA,EAChC,aAAa,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,EAAE,CAAC,EAAE,SAAS;AAAA,EACtE,cAAc,EACX,OAAO;AAAA,IACN,SAAS,EAAE;AAAA,MACT,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,EAAE,MAAM,iBAAiB,EAAE,SAAS,EAAE,CAAC;AAAA,IAC7E;AAAA,EACF,CAAC,EACA,SAAS;AACd,CAAC;AAED,MAAM,iBAAiB,EAAE,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC;AACrE,MAAM,eAAe,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,EAAE,OAAO,GAAG,WAAW,EAAE,OAAO,EAAE,CAAC;AAC3F,MAAM,cAAc,EAAE,QAAQ;AAGvB,MAAM,8BAA8B,IAAI,OAAO;AAE/C,MAAM,4BAA4B;AAIzC,MAAM,8BACJ;AAEK,IAAK,2BAAL,kBAAKC,8BAAL;AAEL,EAAAA,0BAAA,uBAAoB;AAEpB,EAAAA,0BAAA,kBAAe;AACf,EAAAA,0BAAA,0BAAuB;AALb,SAAAA;AAAA,GAAA;AAaZ,MAAM,WAAW,CAAC,QAAgB,MAAc,YAC9C,OAAO,OAAO,IAAI,MAAM,cAAc,MAAM,IAAI,IAAI,KAAK,OAAO,EAAE,GAAG,EAAE,QAAQ,KAAK,CAAC;AAEvF,MAAM,oBAAoB,CAAC,iBACzB,OAAO;AAAA,EACL,IAAI;AAAA,IACF,oCAAoC,gBAAgB,OAAO,8CAA8C,sBAAsB;AAAA,EACjI;AAAA,EACA,EAAE,QAAQ,MAAM,MAAM,6CAA2C;AACnE;AAEF,MAAM,eAAe,MACnB,OAAO;AAAA,EACL,IAAI;AAAA,IACF;AAAA,EACF;AAAA,EACA,EAAE,QAAQ,MAAM,MAAM,oCAAsC;AAC9D;AAEF,MAAM,eAAe,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;AAC7C,MAAM,kBAAkB,CAAC,UAC9B,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,KAAK,EAAE,MAAM,QAAQ;AAEzD,MAAM,oBAAoB,CAAC,UAChC,aAAa,UAAU,KAAK,EAAE,MAAM,UAAU;AAEhD,MAAM,YAAY,CAAC,SAA4B;AAC7C,MAAI;AACF,WAAO,gBAAgB,MAAM,KAAK,MAAM,IAAI,CAAC;AAAA,EAC/C,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,MAAM,UAAU,CAAC,SAA2D;AAAA,EAC1E,OAAO,IAAI;AAAA,EACX,UAAU,IAAI;AAAA,EACd,YAAY,IAAI;AAAA,EAChB,eAAe,IAAI;AAAA,EACnB,UAAU,IAAI;AAAA,EACd,QAAQ,IAAI;AAAA,EACZ,cAAc,IAAI,aAAa,OAAO,CAAC,eAAe,cAAc,IAAI;AAAA,EACxE,aAAa,KAAK,MAAM,IAAI,SAAS;AACvC;AAgHO,MAAM,wBAAwB,CAAC,WAGV;AAC1B,QAAM,UAAU,MAAO,OAAO,OAAO,QAAQ,aAAa,OAAO,IAAI,IAAI,OAAO;AAChF,QAAM,UAAU,OAAO,aAAqD;AAE1E,UAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,UAAM,OAAO,gBAAgB,UAAU,UAAU,IAAI,CAAC;AACtD,WAAO,KAAK,UACR,SAAS,SAAS,QAAQ,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM,OAAO,IACvE,SAAS,SAAS,QAAQ,QAAQ,KAAK,MAAM,GAAG,GAAG,KAAK,SAAS,UAAU;AAAA,EACjF;AAEA,QAAM,YAAY,OAAO,SAIgB;AACvC,UAAM,SAAS,MAAM,KAAK,OAAO,aAAa,aAAa;AAAA,MACzD,cAAc,KAAK;AAAA,MACnB,SAAS,KAAK;AAAA,IAChB,CAAC;AACD,QAAI,UAAU,KAAM,OAAM,kBAAkB,KAAK,YAAY;AAC7D,WAAO;AAAA,EACT;AAIA,QAAM,OAAO,OAAO,SASK;AACvB,UAAM,MAAM,QAAQ;AACpB,UAAM,eAAe,MAAM,KAAK,OAAO,WAAW,QAAQ;AAC1D,QAAI,gBAAgB,QAAQ,CAAC,KAAK,UAAW,OAAM,aAAa;AAChE,UAAM,UAAU,OAAO,YAAwC;AAC7D,YAAM,SAAS,MAAM,UAAU,EAAE,QAAQ,KAAK,QAAQ,cAAc,QAAQ,CAAC;AAC7E,YAAM,MAAM,IAAI,IAAI,GAAG,OAAO,QAAQ,QAAQ,QAAQ,EAAE,CAAC,GAAG,KAAK,IAAI,EAAE;AACvE,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,SAAS,CAAC,CAAC,EAAG,KAAI,aAAa,IAAI,KAAK,KAAK;AAC5F,YAAM,UAAU,IAAI,QAAQ,EAAE,eAAe,UAAU,OAAO,KAAK,GAAG,CAAC;AACvE,UAAI,gBAAgB,KAAM,SAAQ,IAAI,+BAA+B,YAAY;AACjF,UAAI,KAAK,eAAe,KAAM,SAAQ,IAAI,gBAAgB,KAAK,WAAW;AAC1E,cAAQ,OAAO,SAAS,IAAI,SAAS,OAAO,IAAI,SAAS,GAAG;AAAA,QAC1D,QAAQ,KAAK;AAAA,QACb;AAAA,QACA,MAAM,KAAK;AAAA,QACX,QAAQ,KAAK;AAAA,MACf,CAAC;AAAA,IACH;AACA,QAAI,WAAW,MAAM,QAAQ,KAAK;AAClC,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACpC,iBAAW,MAAM,QAAQ,IAAI;AAAA,IAC/B;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAO,OACX,QACA,SACwB;AACxB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,GAAG;AAAA,MACH,MAAM,KAAK,SAAS,SAAY,KAAK,OAAO,KAAK,UAAU,KAAK,IAAI;AAAA,MACpE,aAAa,KAAK,SAAS,SAAY,KAAK,cAAc;AAAA,IAC5D,CAAC;AACD,QAAI,CAAC,SAAS,GAAI,OAAM,MAAM,QAAQ,QAAQ;AAC9C,UAAM,OAAO,MAAM,SAAS,KAAK;AACjC,WAAO,OAAO,MAAM,SAAS,KAAK,OAAO,UAAU,IAAI,CAAC;AAAA,EAC1D;AAGA,QAAM,SAAS,OAAU,SAAwC;AAC/D,QAAI;AACF,aAAO,MAAM;AAAA,IACf,SAAS,OAAO;AACd,UAAI,iBAAiB,SAAS,kBAAkB,KAAK,MAAM,IAAK,QAAO;AACvE,YAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,YAAY,CAAC,OAAe,SAChC,cAAc,mBAAmB,KAAK,CAAC,GAAG,IAAI;AAEhD,QAAM,YAA+C,CAAC,EAAE,QAAQ,MAAM,MAAM;AAC1E,UAAM,OAAO,OACX,QACA,SAEA,KAAK,QAAQ,EAAE,GAAG,MAAM,QAAQ,MAAM,UAAU,MAAM,MAAM,GAAG,KAAK,IAAI,EAAE,CAAC;AAC7E,UAAM,cAAc,CAAC,IAAY,SAC/B,cAAc,mBAAmB,EAAE,CAAC,GAAG,IAAI;AAC7C,WAAO;AAAA,MACL,MAAM;AAAA,MACN,gBAAgB;AAAA,MAChB,cAAc;AAAA,MACd,MAAM,OAAO,EAAE,MAAM,OAAO,MAA0C;AACpE,cAAM,EAAE,KAAK,IAAI,MAAM,KAAK,gBAAgB;AAAA,UAC1C,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,KAAK;AAAA,UACd;AAAA,QACF,CAAC;AACD,eAAO,QAAQ,OAAO,OAAO,EAAE,GAAG,MAAM,MAAM,KAAK,QAAQ,iBAAiB,MAAM;AAAA,MACpF;AAAA,MACA,SAAS,OAAO,EAAE,MAAM,OAAO,OAE3B,MAAM,KAAK,eAAe,EAAE,QAAQ,OAAO,MAAM,cAAc,OAAO,EAAE,KAAK,GAAG,OAAO,CAAC,GACxF,QAAQ,IAAI,CAAC,WAAW,EAAE,GAAG,OAAO,MAAM,MAAM,QAAQ,iBAAiB,MAAM,EAAE;AAAA,MACrF,WAAW,OAAO,EAAE,MAAM,QAAQ,QAAQ,OAAO,MAAM;AACrD,cAAM,WAAW,MAAM,KAAK;AAAA,UAC1B;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,UAAU,MAAM,MAAM,GAAG,gBAAgB;AAAA,UAC/C,OAAO,EAAE,MAAM,QAAQ,OAAO,MAAM,GAAG,QAAQ,OAAO,MAAM,EAAE;AAAA,UAC9D;AAAA,QACF,CAAC;AACD,YAAI,CAAC,SAAS,GAAI,OAAM,MAAM,QAAQ,QAAQ;AAC9C,cAAM,QAAQ,IAAI,WAAW,MAAM,SAAS,YAAY,CAAC;AACzD,eAAO,EAAE,OAAO,KAAK,MAAM,aAAa,OAAO;AAAA,MACjD;AAAA,MACA,YAAY,OAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,MAAM;AACrD,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,QAAQ,OAAO,MAAM,EAAE;AAAA,UACtC,MAAM,IAAI,KAAK,CAAC,MAAM,MAAM,CAAC,CAAC;AAAA,UAC9B,aAAa;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,iBAAiB,OAAO,EAAE,MAAM,OAAO,MAAM;AAC3C,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,MAAM,EAAE,KAAK;AAAA,UACb;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,QAAQ,OAAO,EAAE,MAAM,WAAW,OAAO,OAAO,MAAM;AACpD,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR,MAAM;AAAA,UACN,OAAO,EAAE,MAAM,WAAW,OAAO,SAAS,GAAG,OAAO,OAAO,KAAK,EAAE;AAAA,UAClE;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MACA,MAAM,OAAO,EAAE,IAAI,SAAS,KAAK,KAAK,WAAW,OAAO,MACtD,KAAK,eAAe;AAAA,QAClB,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,EAAE,IAAI,SAAS,KAAK,KAAK,UAAU;AAAA,QACzC;AAAA,MACF,CAAC;AAAA,MACH,QAAQ,OAAO,EAAE,SAAS,cAAc,cAAc,QAAQ,OAAO,MAAM;AACzE,cAAM,SAAS,MAAM,KAAK,cAAc;AAAA,UACtC,QAAQ;AAAA,UACR,MAAM,YAAY,QAAQ,IAAI,SAAS;AAAA,UACvC,MAAM,EAAE,QAAQ,QAAQ,QAAQ,cAAc,cAAc,OAAO;AAAA,UACnE;AAAA,QACF,CAAC;AACD,cAAM,SAAS,CAAC,WAA+C;AAAA,UAC7D,MAAM,aAAa,MAAM,UAAU;AAAA,UACnC,YAAY,MAAM;AAAA,UAClB,KAAK,MAAM;AAAA,QACb;AACA,cAAM,SAA+B;AAAA,UACnC,QAAQ,OAAO,OAAO,MAAM;AAAA,UAC5B,QAAQ,OAAO,OAAO,MAAM;AAAA,UAC5B,QAAQ,OAAO;AAAA,UACf,UAAU,OAAO;AAAA,UACjB,YAAY,OAAO;AAAA,QACrB;AACA,eAAO;AAAA,MACT;AAAA,MACA,OAAO,OAAO,EAAE,SAAS,MAAM,KAAK,QAAQ,WAAW,YAAY,MAAM;AACvE,YAAI,cAAc,QAAQ,UAAU,MAAM;AACxC,gBAAM,KAAK,aAAa;AAAA,YACtB,QAAQ;AAAA,YACR,MAAM,YAAY,QAAQ,IAAI,OAAO;AAAA,YACrC,MACE,cAAc,OAAO,EAAE,QAAQ,QAAQ,OAAO,IAAI,EAAE,QAAQ,QAAQ,QAAQ,OAAO;AAAA,YACrF,QAAQ;AAAA,UACV,CAAC;AACD,cAAI,cAAc,KAAM;AAAA,QAC1B;AACA,YAAK,QAAQ,QAAQ,KAAK,aAAa,KAAM,QAAQ,MAAM;AACzD,gBAAM,OAA8B;AAAA,YAClC,QAAQ,QAAQ;AAAA,UAClB;AACA,cAAI,QAAQ,QAAQ,KAAK,aAAa,EAAG,MAAK,aAAa,aAAa,IAAI;AAC5E,cAAI,QAAQ,KAAM,MAAK,MAAM;AAC7B,gBAAM,KAAK,aAAa;AAAA,YACtB,QAAQ;AAAA,YACR,MAAM,YAAY,QAAQ,IAAI,QAAQ;AAAA,YACtC,MAAM;AAAA,YACN,QAAQ;AAAA,UACV,CAAC;AAAA,QACH;AAAA,MACF;AAAA;AAAA;AAAA,MAGA,aAAa,CAAC,UAAU;AACtB,YAAI,EAAE,iBAAiB,OAAQ,QAAO;AACtC,cAAM,SAAS,kBAAkB,KAAK;AACtC,eACE,WAAW,OAAQ,WAAW,OAAO,4BAA4B,KAAK,MAAM,OAAO;AAAA,MAEvF;AAAA,MACA,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,SAAO;AAAA,IACL,QAAQ;AAAA,MACN,cAAc,CAAC,EAAE,gBAAgB,aAAa,YAAY,MACxD,KAAK,mCAAmC;AAAA,QACtC,QAAQ,EAAE,gBAAgB,aAAa,YAAY,EAAE,SAAS,YAAY,KAAK,EAAE;AAAA,QACjF,WAAW;AAAA,QACX,QAAQ;AAAA,QACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,QACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,kBAAkB,OAAO,EAAE,QAAQ,aAAa,QAAQ,oBAAoB,MAAM;AAChF,cAAM,SAAS,MAAM,OAAO,WAAW,QAAQ;AAC/C,cAAM,YAAY,UAAU;AAC5B,cAAM,iBAAiB,EAAE,GAAG,QAAQ,YAAY,EAAE,SAAS,YAAY,OAAO,EAAE;AAChF,cAAM,SAAS,MAAM,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG;AAAA,UACvD,QAAQ;AAAA,UACR,QAAQ,wBAAwB,OAAO,SAAS;AAAA,UAChD;AAAA,UACA,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC,IAAI,wBAAwB,OAAO,6BAA6B,YAAY,kBAAkB,gBAAgB;AAAA,UACjN,MAAM,6BAA6B,MAAM,MAAM;AAAA,UAC/C,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AACD,YAAI,CAAC,OAAO,GAAI,OAAM,IAAI,MAAM,sDAAsD;AAAA,MACxF;AAAA,MACA,WAAW,CAAC,EAAE,QAAQ,YAAY,MAChC,KAAK,6BAA6B;AAAA,QAChC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,QACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,QAAQ,CAAC,EAAE,QAAQ,GAAG,MAAM,MAC1B,KAAK,8BAA8B;AAAA,QACjC;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,gCAAgC,MAAM,KAAK;AAAA,QACjD,QAAQ,YAAY,QAAQ,IAAO;AAAA,MACrC,CAAC;AAAA,MACH,OAAO,CAAC,EAAE,QAAQ,QAAQ,MACxB,KAAK,yBAAyB;AAAA,QAC5B;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,QACtD,QAAQ,YAAY,QAAQ,IAAO;AAAA,MACrC,CAAC;AAAA,MACH,UAAU,CAAC,EAAE,QAAQ,QAAQ,MAC3B,KAAK,yBAAyB;AAAA,QAC5B;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,QACtD,QAAQ,YAAY,QAAQ,GAAM;AAAA,MACpC,CAAC;AAAA,MACH,QAAQ,OAAO,EAAE,QAAQ,SAAS,YAAY,MAAM;AAClD,cAAM,KAAK,aAAa;AAAA,UACtB;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,EAAE,YAAY;AAAA,UACpB,MAAM,qBAAqB,mBAAmB,OAAO,CAAC;AAAA,UACtD,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,MACA,SAAS,OAAO;AAAA,QACd;AAAA,QACA;AAAA,MACF,MAGM;AACJ,cAAM,SAAS,MAAM,OAAO,WAAW,QAAQ;AAC/C,cAAM,YAAY,UAAU;AAC5B,cAAM,iBAAiB,EAAE,GAAG,QAAQ,YAAY,EAAE,SAAS,YAAY,OAAO,EAAE;AAChF,cAAM,KAAK,aAAa;AAAA,UACtB,QAAQ;AAAA,UACR;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC,IAAI,YAAY,0BAA0B,SAAS;AAAA,UACtJ,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,MACA,SAAS,OAAO,EAAE,QAAQ,YAAY,MAAM;AAC1C,cAAM,KAAK,aAAa;AAAA,UACtB;AAAA,UACA,QAAQ;AAAA,UACR,MAAM,yBAAyB,mBAAmB,8BAA8B,MAAM,WAAW,CAAC,CAAC;AAAA,UACnG,QAAQ,YAAY,QAAQ,GAAM;AAAA,QACpC,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IACA,wBAAwB,OAAO,EAAE,QAAQ,UAAU,UAAU,MAAM;AACjE,YAAM,SAAS,MAAM,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG;AAAA,QAC7D;AAAA,QACA,QAAQ;AAAA,QACR,MACE,iBACA,mBAAmB,QAAQ,IAC3B,iBACA,mBAAmB,SAAS,IAC5B;AAAA,MACJ,CAAC;AACD,UAAI,CAAC,OAAO,SAAU,OAAM,IAAI,MAAM,iDAAiD;AAAA,IACzF;AAAA,IACA,kBAAkB,CAAC,EAAE,QAAQ,UAAU,WAAW,QAAQ,MAAM;AAC9D,YAAM,SACJ,QAAQ,cAAc,2BAA2B,YAC7C,eACA,eAAe,UACb,MAAM,mBAAmB,QAAQ,SAAS,IAC1C;AACR,YAAM,QAAgC,CAAC;AACvC,UAAI,aAAa,KAAM,OAAM,YAAY;AACzC,UAAI,YAAY,QAAS,OAAM,SAAS,QAAQ;AAChD,UAAI,YAAY,WAAW,QAAQ,UAAU,KAAM,OAAM,SAAS,QAAQ;AAC1E,UAAI,WAAW,WAAW,QAAQ,SAAS,KAAM,OAAM,QAAQ,OAAO,QAAQ,KAAK;AACnF,aAAO,KAAK,+BAA+B;AAAA,QACzC;AAAA,QACA,QAAQ,QAAQ,cAAc,2BAA2B,OAAO,WAAW;AAAA,QAC3E,MAAM,iBAAiB,mBAAmB,QAAQ,IAAI,eAAe;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IACA,WAAW,CAAC,EAAE,QAAQ,SAAS,MAC7B;AAAA,MACE,KAAK,cAAc;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,MACnD,CAAC;AAAA,IACH;AAAA,IACF,aAAa,OAAO,EAAE,OAAO,OAC1B,MAAM,KAAK,eAAe,EAAE,QAAQ,QAAQ,OAAO,MAAM,cAAc,CAAC,GAAG;AAAA,IAC9E,gBAAgB,CAAC,EAAE,QAAQ,KAAK,MAC9B;AAAA,MACE,KAAK,cAAc;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM;AAAA,QACN,MAAM,EAAE,KAAK;AAAA,MACf,CAAC;AAAA,IACH;AAAA,IACF,OAAO,OAAO,EAAE,QAAQ,UAAU,WAAW,WAAW,QAAQ,OAAO,gBAAgB,MACrF;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,QACjD,MAAM,EAAE,WAAW,WAAW,QAAQ,OAAO,gBAAgB;AAAA,MAC/D,CAAC;AAAA,IACH;AAAA,IACF,cAAc,OAAO,EAAE,QAAQ,UAAU,WAAW,WAAW,OAAO,MACpE;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,QACjD,MAAM,EAAE,WAAW,WAAW,OAAO;AAAA,MACvC,CAAC;AAAA,IACH;AAAA,IACF,OAAO,OAAO,EAAE,QAAQ,OAAO,MAAM,MACnC;AAAA,MACE,MAAM,KAAK,aAAa;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,MAAM,UAAU,OAAO,QAAQ;AAAA,QAC/B,MAAM,EAAE,MAAM;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,IACF,SAAS,OAAO,EAAE,QAAQ,MAAM,MAAM;AACpC,YAAM,KAAK,aAAa,EAAE,QAAQ,QAAQ,UAAU,MAAM,UAAU,OAAO,EAAE,EAAE,CAAC;AAAA,IAClF;AAAA,IACA;AAAA,IACA,YAAY,CAAC,EAAE,QAAQ,SAAS,MAC9B,KAAK,kBAAkB;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,IACnD,CAAC;AAAA,IACH,iBAAiB,OAAO,EAAE,QAAQ,MAAM,OACrC,MAAM,KAAK,eAAe,EAAE,QAAQ,QAAQ,OAAO,MAAM,UAAU,OAAO,MAAM,EAAE,CAAC,GACjF;AAAA,IACL,MAAM,OAAO,EAAE,QAAQ,OAAO,QAAQ,QAAQ,UAAU,YAAY,OAAO,OAEvE,MAAM,KAAK,gBAAgB;AAAA,MACzB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,UAAU,OAAO,QAAQ,mBAAmB,MAAM,CAAC,IAAI,MAAM,EAAE;AAAA,MACrE,MAAM,cAAc,OAAO,EAAE,SAAS,IAAI,EAAE,UAAU,WAAW;AAAA,MACjE;AAAA,IACF,CAAC,GACD,cAAc;AAAA,IAClB,QAAQ,CAAC,EAAE,QAAQ,UAAU,WAAW,SAAS,MAC/C,KAAK,cAAc;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR,MAAM,eAAe,mBAAmB,QAAQ,CAAC;AAAA,MACjD,MAAM,EAAE,WAAW,SAAS;AAAA,IAC9B,CAAC;AAAA,EACL;AACF;",
|
|
4
|
+
"sourcesContent": ["import {\n ProcessInspectionOperation,\n processInspectionResultSchema,\n type ProcessInspectionRequestIface,\n type ProcessInspectionResultIface,\n} from '@finalai/agent-protocol/process-inspection';\nimport { jsonObjectSchema, jsonValueSchema, type JsonValue } from '@finalai/agent-provider';\nimport { SandboxEntryType, type SandboxActingUserIface } from '@finalai/agent-provider/sandbox';\nimport * as z from 'zod';\nimport { decodeBase64, encodeBase64 } from \"./bytes.mjs\";\nimport { DEVICE_API_ACTING_USER_HEADER, type FinalPlatformAccessIface } from \"./environment.mjs\";\nimport type {\n SandboxTransportIface,\n TransportDirEntryIface,\n TransportOutputIface,\n TransportStatIface,\n} from \"./transport.mjs\";\n\n// A client of the Device API, authenticated with the provider's platform\n// identity for it. Device operations also name the acting user; the API\n// enforces ownership independently of the token.\n\n// The access asked for before each request, and again after the API rejected\n// the last token. Null: none granted.\nexport interface DeviceApiCredentialsIface {\n deviceAccess(args?: {\n actingUserId?: string | null;\n refresh?: boolean;\n }): Promise<FinalPlatformAccessIface | null>;\n}\n\n// The Device API's header naming the user a request acts for (a Final user id).\nexport { DEVICE_API_ACTING_USER_HEADER } from \"./environment.mjs\";\n\n// The organization, credentials and user a call acts for; the user is read on each\n// call.\nexport interface DeviceApiCallerIface {\n organizationId: string;\n credentials?: DeviceApiCredentialsIface;\n actingUser: SandboxActingUserIface;\n}\n\n// Transport options; the API origin and token come from the caller's credentials.\nexport interface DeviceApiConfigIface {\n fetch?: DeviceApiFetchIface;\n}\n\nexport interface DeviceApiFetchIface {\n (input: string, init: RequestInit): Promise<Response>;\n}\n\nexport enum DeviceApiLeaseAccess {\n Read = 'read',\n Write = 'write',\n}\n\nexport enum DeviceApiCapability {\n Files = 'files',\n Process = 'process',\n ComputerUse = 'computer-use',\n LocalMcp = 'local-mcp',\n}\n\nexport const DEVICE_API_COMPUTER_USE_SERVER = 'computer-use';\n\n// Unknown values from a newer API read as absent rather than failing the call.\nconst tolerantEnum = <T extends Record<string, string>>(values: T) =>\n z.string().transform((value): T[keyof T] | null => {\n const parsed = z.nativeEnum(values).safeParse(value);\n return parsed.success ? parsed.data : null;\n });\n\nconst deviceSchema = z.object({\n id: z.string(),\n organizationId: z.string(),\n displayName: z.string(),\n os: z.string(),\n online: z.boolean(),\n writable: z.boolean(),\n allowProcesses: z.boolean(),\n computerUseReady: z.boolean(),\n screenReady: z.boolean(),\n});\nexport type DeviceApiDeviceIface = z.infer<typeof deviceSchema>;\n\nconst leaseSchema = z.object({\n lease: z.string(),\n deviceId: z.string(),\n generation: z.number(),\n workspaceRoot: z.string(),\n platform: z.string(),\n access: z.nativeEnum(DeviceApiLeaseAccess),\n capabilities: z.array(tolerantEnum(DeviceApiCapability)),\n expiresAt: z.string(),\n});\nexport interface DeviceApiLeaseIface {\n lease: string;\n deviceId: string;\n generation: number;\n workspaceRoot: string;\n platform: string;\n access: DeviceApiLeaseAccess;\n capabilities: DeviceApiCapability[];\n expiresAtMs: number;\n}\n\ninterface ProcessInputBodyIface {\n bootId: string;\n dataBase64?: string;\n eof?: boolean;\n}\n\nconst errorBodySchema = z.object({ error: z.object({ code: z.string(), message: z.string() }) });\nconst statBodySchema = z.object({\n stat: z\n .object({\n type: tolerantEnum(SandboxEntryType),\n size: z.number(),\n modifiedAtMs: z.number().nullable(),\n mode: z.number().nullable(),\n })\n .nullable(),\n});\nconst dirBodySchema = z.object({\n entries: z.array(\n z.object({\n name: z.string(),\n type: tolerantEnum(SandboxEntryType),\n size: z.number().nullable(),\n }),\n ),\n});\nconst processSchema = z.object({ id: z.string(), bootId: z.string() });\nconst outputStreamSchema = z.object({\n dataBase64: z.string(),\n nextOffset: z.number(),\n eof: z.boolean(),\n});\nconst outputSchema = z.object({\n stdout: outputStreamSchema,\n stderr: outputStreamSchema,\n exited: z.boolean(),\n exitCode: z.number().nullable(),\n exitSignal: z.string().nullable(),\n});\nconst devicesSchema = z.object({ devices: z.array(deviceSchema) });\nconst serversSchema = z.object({ servers: z.array(z.string()) });\n// A Device server's tool as the API recorded it; checked against the tool\n// descriptor contract where the provider hands it on.\nconst catalogToolSchema = jsonObjectSchema;\nconst mcpCatalogSchema = z.object({\n computerUse: z.object({ tools: z.array(catalogToolSchema) }).nullable(),\n localServers: z\n .object({\n servers: z.array(\n z.object({ name: z.string(), tools: z.array(catalogToolSchema).nullable() }),\n ),\n })\n .nullable(),\n});\nexport type DeviceApiMcpCatalogIface = z.infer<typeof mcpCatalogSchema>;\nconst pipeReadSchema = z.object({ dataBase64: z.string().optional() });\nconst screenSchema = z.object({ url: z.string(), token: z.string(), expiresAt: z.string() });\nconst emptySchema = z.unknown();\n\n// One ranged read or write; the API splits it into the Device's own chunks.\nexport const DEVICE_API_FILE_CHUNK_BYTES = 4 * 1024 * 1024;\n// The API long-polls the Device for output up to this long.\nexport const DEVICE_API_OUTPUT_WAIT_MS = 15_000;\n// How the Device reports a lease process it no longer has (relayed as a 502):\n// unknown in this lease, from an earlier runtime, or retired after its output\n// was read to the end.\nconst DEVICE_PROCESS_GONE_MESSAGE =\n /unknown process|belongs to another device runtime|consumed output has expired/i;\n\nexport enum DeviceApiClientErrorCode {\n // The host granted no access for this user or trusted service call.\n CredentialMissing = 'credential_missing',\n // The session acts for no user, and a Device is only used for its owner.\n NoActingUser = 'no_acting_user',\n}\n\nexport interface DeviceApiErrorIface extends Error {\n status: number | null;\n code: string;\n}\n\nconst apiError = (status: number, code: string, message: string): DeviceApiErrorIface =>\n Object.assign(new Error(`Device API ${status} ${code}: ${message}`), { status, code });\n\nconst credentialMissing = (actingUserId: string | null): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n `Device API access is unavailable ${actingUserId == null ? 'without an acting user' : 'for this acting user'}: the provider's configured Device API access granted none`,\n ),\n { status: null, code: DeviceApiClientErrorCode.CredentialMissing },\n );\n\nconst noActingUser = (): DeviceApiErrorIface =>\n Object.assign(\n new Error(\n 'this session acts for no user, and a Final Device is only used by sessions acting for its owner',\n ),\n { status: null, code: DeviceApiClientErrorCode.NoActingUser },\n );\n\nconst statusSchema = z.object({ status: z.number() });\nexport const deviceApiCodeOf = (cause: unknown): string | null =>\n z.object({ code: z.string() }).safeParse(cause).data?.code ?? null;\n\nexport const deviceApiStatusOf = (cause: Error): number | null =>\n statusSchema.safeParse(cause).data?.status ?? null;\n\nconst parseJson = (text: string): JsonValue => {\n try {\n return jsonValueSchema.parse(JSON.parse(text));\n } catch {\n return null;\n }\n};\n\nconst leaseOf = (raw: z.infer<typeof leaseSchema>): DeviceApiLeaseIface => ({\n lease: raw.lease,\n deviceId: raw.deviceId,\n generation: raw.generation,\n workspaceRoot: raw.workspaceRoot,\n platform: raw.platform,\n access: raw.access,\n capabilities: raw.capabilities.filter((capability) => capability != null),\n expiresAtMs: Date.parse(raw.expiresAt),\n});\n\nexport interface DeviceApiClientIface {\n releaseWorkspaceLeases(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n }): Promise<void>;\n inspectProcesses(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n bindingId: string;\n request: ProcessInspectionRequestIface;\n }): Promise<ProcessInspectionResultIface>;\n getDevice(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiDeviceIface | null>;\n // The Devices of the user the call acts for.\n listDevices(args: { caller: DeviceApiCallerIface }): Promise<DeviceApiDeviceIface[]>;\n resolvePairing(args: {\n caller: DeviceApiCallerIface;\n code: string;\n }): Promise<DeviceApiDeviceIface | null>;\n lease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n ttlMs: number;\n afterGeneration?: number;\n }): Promise<DeviceApiLeaseIface>;\n recoverLease(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n bindingId: string;\n access: DeviceApiLeaseAccess;\n }): Promise<DeviceApiLeaseIface>;\n renew(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n ttlMs: number;\n }): Promise<DeviceApiLeaseIface>;\n release(args: { caller: DeviceApiCallerIface; lease: string }): Promise<void>;\n // The sandbox transport over one lease; `lease()` is the current handle.\n transport(args: {\n caller: DeviceApiCallerIface;\n lease: () => Promise<string>;\n }): SandboxTransportIface;\n localMcpServers(args: { caller: DeviceApiCallerIface; lease: string }): Promise<string[]>;\n // What the Device's MCP servers last listed through the API, without a lease.\n mcpCatalog(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n }): Promise<DeviceApiMcpCatalogIface>;\n pipe(args: {\n caller: DeviceApiCallerIface;\n lease: string;\n server: string;\n action: 'open' | 'write' | 'read' | 'close';\n clientId: string;\n dataBase64?: string;\n signal?: AbortSignal;\n }): Promise<string>;\n screen(args: {\n caller: DeviceApiCallerIface;\n deviceId: string;\n sessionId: string;\n viewOnly?: boolean;\n }): Promise<{ url: string; token: string; expiresAt: string }>;\n}\n\nexport const createDeviceApiClient = (config: {\n api: DeviceApiConfigIface | (() => DeviceApiConfigIface);\n fetch?: DeviceApiFetchIface;\n}): DeviceApiClientIface => {\n const readApi = () => (typeof config.api === 'function' ? config.api() : config.api);\n const failure = async (response: Response): Promise<DeviceApiErrorIface> => {\n // Read as text so proxy and load balancer error pages survive.\n const text = await response.text().catch(() => '');\n const body = errorBodySchema.safeParse(parseJson(text));\n return body.success\n ? apiError(response.status, body.data.error.code, body.data.error.message)\n : apiError(response.status, 'http', text.slice(0, 200) || response.statusText);\n };\n\n const accessFor = async (args: {\n caller: DeviceApiCallerIface;\n actingUserId: string | null;\n refresh: boolean;\n }): Promise<FinalPlatformAccessIface> => {\n const access = await args.caller.credentials?.deviceAccess({\n actingUserId: args.actingUserId,\n refresh: args.refresh,\n });\n if (access == null) throw credentialMissing(args.actingUserId);\n return access;\n };\n\n // One authenticated call for the user it acts for; rejected access is asked for\n // again once, in case it expired.\n const send = async (args: {\n caller: DeviceApiCallerIface;\n method: string;\n path: string;\n query?: Record<string, string>;\n body?: BodyInit;\n contentType?: string;\n signal?: AbortSignal;\n }): Promise<Response> => {\n const api = readApi();\n const actingUserId = await args.caller.actingUser.current();\n if (actingUserId == null) throw noActingUser();\n const attempt = async (refresh: boolean): Promise<Response> => {\n const access = await accessFor({ caller: args.caller, actingUserId, refresh });\n const url = new URL(`${access.baseUrl.replace(/\\/+$/, '')}${args.path}`);\n for (const [key, value] of Object.entries(args.query ?? {})) url.searchParams.set(key, value);\n const headers = new Headers({ authorization: `Bearer ${access.token}` });\n if (actingUserId != null) headers.set(DEVICE_API_ACTING_USER_HEADER, actingUserId);\n if (args.contentType != null) headers.set('content-type', args.contentType);\n return (config.fetch ?? api.fetch ?? fetch)(url.toString(), {\n method: args.method,\n headers,\n body: args.body,\n signal: args.signal,\n });\n };\n let response = await attempt(false);\n if (response.status === 401) {\n await response.text().catch(() => '');\n response = await attempt(true);\n }\n return response;\n };\n\n const json = async <T extends z.ZodType>(\n schema: T,\n args: Parameters<typeof send>[0] & { json?: unknown },\n ): Promise<z.infer<T>> => {\n const response = await send({\n ...args,\n body: args.json === undefined ? args.body : JSON.stringify(args.json),\n contentType: args.json === undefined ? args.contentType : 'application/json',\n });\n if (!response.ok) throw await failure(response);\n const text = await response.text();\n return schema.parse(text === '' ? null : parseJson(text));\n };\n\n // A 404 reads as absent.\n const orNull = async <T>(work: Promise<T>): Promise<T | null> => {\n try {\n return await work;\n } catch (cause) {\n if (cause instanceof Error && deviceApiStatusOf(cause) === 404) return null;\n throw cause;\n }\n };\n\n const leasePath = (lease: string, rest: string): string =>\n `/v1/leases/${encodeURIComponent(lease)}${rest}`;\n\n const transport: DeviceApiClientIface['transport'] = ({ caller, lease }) => {\n const call = async <T extends z.ZodType>(\n schema: T,\n args: Omit<Parameters<typeof json>[1], 'caller' | 'path'> & { path: string },\n ): Promise<z.infer<T>> =>\n json(schema, { ...args, caller, path: leasePath(await lease(), args.path) });\n const processPath = (id: string, rest: string): string =>\n `/processes/${encodeURIComponent(id)}${rest}`;\n return {\n kind: 'device-api',\n fileChunkBytes: DEVICE_API_FILE_CHUNK_BYTES,\n outputWaitMs: DEVICE_API_OUTPUT_WAIT_MS,\n stat: async ({ path, signal }): Promise<TransportStatIface | null> => {\n const { stat } = await call(statBodySchema, {\n method: 'GET',\n path: '/files/stat',\n query: { path },\n signal,\n });\n return stat == null ? null : { ...stat, type: stat.type ?? SandboxEntryType.Other };\n },\n readDir: async ({ path, signal }): Promise<TransportDirEntryIface[]> =>\n (\n await call(dirBodySchema, { method: 'GET', path: '/files/dir', query: { path }, signal })\n ).entries.map((entry) => ({ ...entry, type: entry.type ?? SandboxEntryType.Other })),\n readChunk: async ({ path, offset, length, signal }) => {\n const response = await send({\n caller,\n method: 'GET',\n path: leasePath(await lease(), '/files/content'),\n query: { path, offset: String(offset), length: String(length) },\n signal,\n });\n if (!response.ok) throw await failure(response);\n const bytes = new Uint8Array(await response.arrayBuffer());\n return { bytes, eof: bytes.byteLength < length };\n },\n writeChunk: async ({ path, offset, bytes, signal }) => {\n await call(emptySchema, {\n method: 'PUT',\n path: '/files/content',\n query: { path, offset: String(offset) },\n body: new Blob([bytes.slice()]),\n contentType: 'application/octet-stream',\n signal,\n });\n },\n createDirectory: async ({ path, signal }) => {\n await call(emptySchema, {\n method: 'POST',\n path: '/files/directories',\n json: { path },\n signal,\n });\n },\n remove: async ({ path, recursive, force, signal }) => {\n await call(emptySchema, {\n method: 'DELETE',\n path: '/files',\n query: { path, recursive: String(recursive), force: String(force) },\n signal,\n });\n },\n exec: async ({ id, command, cwd, env, timeoutMs, signal }) =>\n call(processSchema, {\n method: 'POST',\n path: '/processes',\n json: { id, command, cwd, env, timeoutMs },\n signal,\n }),\n output: async ({ process, stdoutOffset, stderrOffset, waitMs, signal }) => {\n const output = await call(outputSchema, {\n method: 'POST',\n path: processPath(process.id, '/output'),\n json: { bootId: process.bootId, stdoutOffset, stderrOffset, waitMs },\n signal,\n });\n const stream = (value: z.infer<typeof outputStreamSchema>) => ({\n data: decodeBase64(value.dataBase64),\n nextOffset: value.nextOffset,\n eof: value.eof,\n });\n const result: TransportOutputIface = {\n stdout: stream(output.stdout),\n stderr: stream(output.stderr),\n exited: output.exited,\n exitCode: output.exitCode,\n exitSignal: output.exitSignal,\n };\n return result;\n },\n input: async ({ process, data, eof, signal, terminate, abortSignal }) => {\n if (terminate === true || signal != null) {\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/kill'),\n json:\n terminate === true ? { bootId: process.bootId } : { bootId: process.bootId, signal },\n signal: abortSignal,\n });\n if (terminate === true) return;\n }\n if ((data != null && data.byteLength > 0) || eof === true) {\n const body: ProcessInputBodyIface = {\n bootId: process.bootId,\n };\n if (data != null && data.byteLength > 0) body.dataBase64 = encodeBase64(data);\n if (eof === true) body.eof = true;\n await call(emptySchema, {\n method: 'POST',\n path: processPath(process.id, '/input'),\n json: body,\n signal: abortSignal,\n });\n }\n },\n // Lease processes run on the Device and are found again by id and boot\n // while the lease generation lasts.\n processGone: (cause) => {\n if (!(cause instanceof Error)) return false;\n const status = deviceApiStatusOf(cause);\n return (\n status === 404 || (status === 502 && DEVICE_PROCESS_GONE_MESSAGE.test(cause.message))\n );\n },\n close: () => undefined,\n };\n };\n\n return {\n releaseWorkspaceLeases: async ({ caller, deviceId, bindingId }) => {\n const result = await json(z.object({ released: z.boolean() }), {\n caller,\n method: 'DELETE',\n path:\n '/v1/devices/' +\n encodeURIComponent(deviceId) +\n '/workspaces/' +\n encodeURIComponent(bindingId) +\n '/leases',\n });\n if (!result.released) throw new Error('The Device did not release its workspace leases');\n },\n inspectProcesses: ({ caller, deviceId, bindingId, request }) => {\n const suffix =\n request.operation === ProcessInspectionOperation.Available\n ? '/available'\n : 'processId' in request\n ? '/' + encodeURIComponent(request.processId)\n : '';\n const query: Record<string, string> = {};\n if (bindingId != null) query.bindingId = bindingId;\n if ('bootId' in request) query.bootId = request.bootId;\n if ('cursor' in request && request.cursor != null) query.cursor = request.cursor;\n if ('limit' in request && request.limit != null) query.limit = String(request.limit);\n return json(processInspectionResultSchema, {\n caller,\n method: request.operation === ProcessInspectionOperation.Stop ? 'DELETE' : 'GET',\n path: '/v1/devices/' + encodeURIComponent(deviceId) + '/processes' + suffix,\n query,\n });\n },\n getDevice: ({ caller, deviceId }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}`,\n }),\n ),\n listDevices: async ({ caller }) =>\n (await json(devicesSchema, { caller, method: 'GET', path: '/v1/devices' })).devices,\n resolvePairing: ({ caller, code }) =>\n orNull(\n json(deviceSchema, {\n caller,\n method: 'POST',\n path: '/v1/pairings/resolve',\n json: { code },\n }),\n ),\n lease: async ({ caller, deviceId, sessionId, bindingId, access, ttlMs, afterGeneration }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases`,\n json: { sessionId, bindingId, access, ttlMs, afterGeneration },\n }),\n ),\n recoverLease: async ({ caller, deviceId, sessionId, bindingId, access }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/leases/recover`,\n json: { sessionId, bindingId, access },\n }),\n ),\n renew: async ({ caller, lease, ttlMs }) =>\n leaseOf(\n await json(leaseSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, '/renew'),\n json: { ttlMs },\n }),\n ),\n release: async ({ caller, lease }) => {\n await json(emptySchema, { caller, method: 'DELETE', path: leasePath(lease, '') });\n },\n transport,\n mcpCatalog: ({ caller, deviceId }) =>\n json(mcpCatalogSchema, {\n caller,\n method: 'GET',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/mcp`,\n }),\n localMcpServers: async ({ caller, lease }) =>\n (await json(serversSchema, { caller, method: 'GET', path: leasePath(lease, '/mcp') }))\n .servers,\n pipe: async ({ caller, lease, server, action, clientId, dataBase64, signal }) =>\n (\n await json(pipeReadSchema, {\n caller,\n method: 'POST',\n path: leasePath(lease, `/mcp/${encodeURIComponent(server)}/${action}`),\n json: dataBase64 == null ? { clientId } : { clientId, dataBase64 },\n signal,\n })\n ).dataBase64 ?? '',\n screen: ({ caller, deviceId, sessionId, viewOnly }) =>\n json(screenSchema, {\n caller,\n method: 'POST',\n path: `/v1/devices/${encodeURIComponent(deviceId)}/screen`,\n json: { sessionId, viewOnly },\n }),\n };\n};\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["DEVICE_API_ACTING_USER_HEADER", "DeviceApiLeaseAccess", "DeviceApiCapability", "DeviceApiClientErrorCode"]
|
|
7
7
|
}
|
|
@@ -5,7 +5,7 @@ import { type DeviceApiConfigIface, type DeviceApiFetchIface } from "./device-ap
|
|
|
5
5
|
export { DEVICE_API_ACTING_USER_HEADER, DeviceApiClientErrorCode } from "./device-api.mjs";
|
|
6
6
|
export type { DeviceApiConfigIface, DeviceApiFetchIface } from "./device-api.mjs";
|
|
7
7
|
export { DEVICE_PROVIDER } from "./environment.mjs";
|
|
8
|
-
export type { FinalPlatformAccessIface } from "./
|
|
8
|
+
export type { FinalPlatformAccessIface } from "./environment.mjs";
|
|
9
9
|
export { SandboxPlatform } from "./paths.mjs";
|
|
10
10
|
export interface DeviceSandboxProviderConfigIface {
|
|
11
11
|
api: DeviceApiConfigIface;
|
|
@@ -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 type { DeviceApiCredentialsIface } from \"./access.mjs\";\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 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 \"./access.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;AAAA,EACE;AAAA,OAIK;AACP;AAAA,EACE;AAAA,EACA;AAAA,OAUK;AACP,YAAY,OAAO;
|
|
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": "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",
|
|
6
6
|
"names": ["DEVICE_PROVIDER", "SandboxPlatform"]
|
|
7
7
|
}
|
|
@@ -2,6 +2,10 @@ import * as z from 'zod';
|
|
|
2
2
|
export declare const COMPUTER_PROVIDER = "computer";
|
|
3
3
|
export declare const DEVICE_PROVIDER = "device";
|
|
4
4
|
export declare const DEVICE_API_ACTING_USER_HEADER = "Final-Acting-User-Id";
|
|
5
|
+
export interface FinalPlatformAccessIface {
|
|
6
|
+
baseUrl: string;
|
|
7
|
+
token: string;
|
|
8
|
+
}
|
|
5
9
|
export declare const DEFAULT_COMPUTER_IMAGE = "lineage:sandbox";
|
|
6
10
|
export declare const computerBuildSchema: z.ZodObject<{
|
|
7
11
|
steps: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../../../src/sandboxes/environment.ts"],
|
|
4
|
-
"sourcesContent": ["import * as z from 'zod';\n\n// Environment options of the `computer` and `device` providers: what a\n// `project.sandboxes.create(computer({...}))` call carries as the environment,\n// validated by the provider. Only what the provider itself controls lives\n// here (image, build, machine, region, idle policy); what should be on the\n// machine is the provider-neutral sandbox setup, which the platform applies.\n// Pure (no I/O) so callers can import it anywhere.\n\nexport const COMPUTER_PROVIDER = 'computer';\nexport const DEVICE_PROVIDER = 'device';\n\n// The Device API's header naming the user a request acts for.\nexport const DEVICE_API_ACTING_USER_HEADER = 'Final-Acting-User-Id';\n\n// The platform's image lineage computers start from when none is named.\nexport const DEFAULT_COMPUTER_IMAGE = 'lineage:sandbox';\n\nconst buildStepSchema = z.strictObject({\n run: z\n .string()\n .min(1)\n .max(10 * 1024),\n timeoutMinutes: z.number().int().min(1).max(120).default(20),\n});\n\n// Steps baked into a base once (the provider's preparation), never run per sandbox.\nexport const computerBuildSchema = z.strictObject({\n steps: z.array(buildStepSchema).max(30).default([]),\n // Checks that the built base works; a failing one fails the build.\n verify: z.array(buildStepSchema).max(30).default([]),\n});\n\nexport const computerMachineSchema = z.strictObject({\n vcpu: z.number().int().min(1).max(64).optional(),\n memoryMb: z.number().int().min(512).max(262_144).optional(),\n diskGb: z.number().int().min(1).max(2048).optional(),\n});\n\nexport const computerEnvironmentSchema = z.strictObject({\n // An OCI image reference, or `lineage:<name>` for a platform image lineage.\n image: z.string().min(1).max(512).optional(),\n build: computerBuildSchema.optional(),\n machine: computerMachineSchema.optional(),\n region: z.string().min(1).max(64).optional(),\n // Idle time before the computer pauses (its disk and processes kept).\n idleTimeoutSeconds: z\n .number()\n .int()\n .min(60)\n .max(7 * 24 * 60 * 60)\n .optional(),\n});\n\nexport const deviceEnvironmentSchema = z.union([\n z.strictObject({ deviceId: z.string().uuid() }),\n // A pairing code the owner approved; resolved to a device at prepare.\n z.strictObject({ pairing: z.string().min(1) }),\n]);\n\nexport type ComputerBuildIface = z.output<typeof computerBuildSchema>;\nexport type ComputerEnvironmentIface = z.output<typeof computerEnvironmentSchema>;\nexport type ComputerEnvironmentInputIface = z.input<typeof computerEnvironmentSchema>;\nexport type DeviceEnvironmentIface = z.output<typeof deviceEnvironmentSchema>;\nexport type DeviceEnvironmentInputIface = z.input<typeof deviceEnvironmentSchema>;\n"],
|
|
5
|
-
"mappings": "AAAA,YAAY,OAAO;AASZ,MAAM,oBAAoB;AAC1B,MAAM,kBAAkB;AAGxB,MAAM,gCAAgC;
|
|
4
|
+
"sourcesContent": ["import * as z from 'zod';\n\n// Environment options of the `computer` and `device` providers: what a\n// `project.sandboxes.create(computer({...}))` call carries as the environment,\n// validated by the provider. Only what the provider itself controls lives\n// here (image, build, machine, region, idle policy); what should be on the\n// machine is the provider-neutral sandbox setup, which the platform applies.\n// Pure (no I/O) so callers can import it anywhere.\n\nexport const COMPUTER_PROVIDER = 'computer';\nexport const DEVICE_PROVIDER = 'device';\n\n// The Device API's header naming the user a request acts for.\nexport const DEVICE_API_ACTING_USER_HEADER = 'Final-Acting-User-Id';\n\n// Access to the Computers or Device API: its origin (requests go to\n// `<baseUrl>/v1/...`) and a bearer token.\nexport interface FinalPlatformAccessIface {\n baseUrl: string;\n token: string;\n}\n\n// The platform's image lineage computers start from when none is named.\nexport const DEFAULT_COMPUTER_IMAGE = 'lineage:sandbox';\n\nconst buildStepSchema = z.strictObject({\n run: z\n .string()\n .min(1)\n .max(10 * 1024),\n timeoutMinutes: z.number().int().min(1).max(120).default(20),\n});\n\n// Steps baked into a base once (the provider's preparation), never run per sandbox.\nexport const computerBuildSchema = z.strictObject({\n steps: z.array(buildStepSchema).max(30).default([]),\n // Checks that the built base works; a failing one fails the build.\n verify: z.array(buildStepSchema).max(30).default([]),\n});\n\nexport const computerMachineSchema = z.strictObject({\n vcpu: z.number().int().min(1).max(64).optional(),\n memoryMb: z.number().int().min(512).max(262_144).optional(),\n diskGb: z.number().int().min(1).max(2048).optional(),\n});\n\nexport const computerEnvironmentSchema = z.strictObject({\n // An OCI image reference, or `lineage:<name>` for a platform image lineage.\n image: z.string().min(1).max(512).optional(),\n build: computerBuildSchema.optional(),\n machine: computerMachineSchema.optional(),\n region: z.string().min(1).max(64).optional(),\n // Idle time before the computer pauses (its disk and processes kept).\n idleTimeoutSeconds: z\n .number()\n .int()\n .min(60)\n .max(7 * 24 * 60 * 60)\n .optional(),\n});\n\nexport const deviceEnvironmentSchema = z.union([\n z.strictObject({ deviceId: z.string().uuid() }),\n // A pairing code the owner approved; resolved to a device at prepare.\n z.strictObject({ pairing: z.string().min(1) }),\n]);\n\nexport type ComputerBuildIface = z.output<typeof computerBuildSchema>;\nexport type ComputerEnvironmentIface = z.output<typeof computerEnvironmentSchema>;\nexport type ComputerEnvironmentInputIface = z.input<typeof computerEnvironmentSchema>;\nexport type DeviceEnvironmentIface = z.output<typeof deviceEnvironmentSchema>;\nexport type DeviceEnvironmentInputIface = z.input<typeof deviceEnvironmentSchema>;\n"],
|
|
5
|
+
"mappings": "AAAA,YAAY,OAAO;AASZ,MAAM,oBAAoB;AAC1B,MAAM,kBAAkB;AAGxB,MAAM,gCAAgC;AAUtC,MAAM,yBAAyB;AAEtC,MAAM,kBAAkB,EAAE,aAAa;AAAA,EACrC,KAAK,EACF,OAAO,EACP,IAAI,CAAC,EACL,IAAI,KAAK,IAAI;AAAA,EAChB,gBAAgB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE;AAC7D,CAAC;AAGM,MAAM,sBAAsB,EAAE,aAAa;AAAA,EAChD,OAAO,EAAE,MAAM,eAAe,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;AAAA;AAAA,EAElD,QAAQ,EAAE,MAAM,eAAe,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,CAAC;AACrD,CAAC;AAEM,MAAM,wBAAwB,EAAE,aAAa;AAAA,EAClD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EAC/C,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,MAAO,EAAE,SAAS;AAAA,EAC1D,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,IAAI,EAAE,SAAS;AACrD,CAAC;AAEM,MAAM,4BAA4B,EAAE,aAAa;AAAA;AAAA,EAEtD,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAAA,EAC3C,OAAO,oBAAoB,SAAS;AAAA,EACpC,SAAS,sBAAsB,SAAS;AAAA,EACxC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA;AAAA,EAE3C,oBAAoB,EACjB,OAAO,EACP,IAAI,EACJ,IAAI,EAAE,EACN,IAAI,IAAI,KAAK,KAAK,EAAE,EACpB,SAAS;AACd,CAAC;AAEM,MAAM,0BAA0B,EAAE,MAAM;AAAA,EAC7C,EAAE,aAAa,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAAA;AAAA,EAE9C,EAAE,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,CAAC;AAC/C,CAAC;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type JsonValue } from '@finalai/agent-provider';
|
|
2
2
|
import { type NetworkSandboxSessionIface, type SandboxProviderIface } from '@finalai/agent-provider/sandbox';
|
|
3
3
|
import * as z from 'zod';
|
|
4
4
|
export declare const LOCAL_PROVIDER = "local";
|
|
@@ -19,6 +19,7 @@ declare const localStateSchema: z.ZodObject<{
|
|
|
19
19
|
version: z.ZodLiteral<1>;
|
|
20
20
|
root: z.ZodString;
|
|
21
21
|
}, z.core.$strip>;
|
|
22
|
+
export declare const LOCAL_PLATFORM_DIRECTORY = ".final";
|
|
22
23
|
type LocalArtifact = {
|
|
23
24
|
version: 1;
|
|
24
25
|
root: string;
|