@finalai/final-agent-provider 0.12.0 → 0.14.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.
@@ -2,20 +2,17 @@ import { Capability, FilesAccess, ScreenAccess, ShellAccess } from "@finalai/age
2
2
  import { NetworkPolicy } from "@finalai/agent-provider";
3
3
  import {
4
4
  defineSandboxProvider,
5
- FULL_SANDBOX_GRANT,
6
5
  materializeSandboxSeeds,
7
6
  platformProcessEnvironment,
8
7
  PortProtocol,
9
8
  reportPlatformNetworkPolicy,
10
9
  SandboxCapability,
11
- SandboxExecutionOperation,
12
10
  sandboxSeedArtifact,
13
11
  sandboxSeedArtifactSchema,
14
12
  sandboxSeedFiles,
15
13
  sandboxSeedFilesForAttach,
16
14
  sandboxSeedIdentity,
17
15
  withPlatformEgressHosts,
18
- withSandboxNetworking,
19
16
  writePlatformFiles
20
17
  } from "@finalai/agent-provider/sandbox";
21
18
  import {
@@ -79,9 +76,7 @@ const computerStateSchema = z.object({
79
76
  // The sandbox setup's network policy, enforced from the computer's first boot.
80
77
  network: networkPolicySchema,
81
78
  // Ports the setup's services listen on.
82
- ports: z.array(z.number().int()).default([]),
83
- // Workspace Device egress manages this computer's network.
84
- networkPolicySaved: z.boolean().default(false)
79
+ ports: z.array(z.number().int()).default([])
85
80
  });
86
81
  const computerSandboxError = (code, message) => Object.assign(new Error(message), { name: "ComputerSandboxError", code });
87
82
  const HTTP_TOKEN_LIFETIME_MS = 60 * 6e4;
@@ -107,10 +102,6 @@ const CAPTURE_SCRUBBED_PATHS = [
107
102
  const BUILDER_IDLE_TIMEOUT_SECONDS = 2 * 60 * 60;
108
103
  const ARTIFACT_KEY_VERSION = 1;
109
104
  const PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION = 2;
110
- const networkPolicyFor = (network) => ({
111
- mode: network?.egress === ComputerEgressPolicy.Internet ? NetworkPolicy.AllowAll : network?.egress === ComputerEgressPolicy.Allowlist ? NetworkPolicy.Allowlist : NetworkPolicy.DenyAll,
112
- allow: network?.allow ?? []
113
- });
114
105
  const computerEgressOf = (policy) => {
115
106
  if (policy.mode === NetworkPolicy.AllowAll) return { egress: ComputerEgressPolicy.Internet };
116
107
  if (policy.mode === NetworkPolicy.DenyAll) return { egress: ComputerEgressPolicy.None };
@@ -151,16 +142,6 @@ const computeComputerArtifactKey = async (inputs) => {
151
142
  );
152
143
  return `pa-g${hex.slice(0, 16)}-c${PROJECT_ARTIFACT_CAPTURE_PROTOCOL_VERSION}`;
153
144
  };
154
- const offerContextOf = (ctx) => ({
155
- organizationId: ctx.organizationId,
156
- projectId: ctx.projectId,
157
- sandboxId: ctx.sandboxId,
158
- credentials: ctx.credentials,
159
- actingUser: ctx.actingUser,
160
- identity: ctx.identity,
161
- platformEgressHosts: ctx.platformEgressHosts,
162
- platformNetworkPolicy: ctx.platformNetworkPolicy
163
- });
164
145
  const createComputerSandboxProvider = (config) => {
165
146
  const log = config.log ?? (() => void 0);
166
147
  const randomUuid = config.randomUuid ?? (() => crypto.randomUUID());
@@ -237,102 +218,6 @@ const createComputerSandboxProvider = (config) => {
237
218
  );
238
219
  }
239
220
  };
240
- const createNetworkingController = (options) => {
241
- try {
242
- if (config.networking == null) throw new Error("Workspace networking extension is required");
243
- return config.networking.controller(options);
244
- } catch (cause) {
245
- options.onClose?.();
246
- throw cause;
247
- }
248
- };
249
- const managedWorkspaces = /* @__PURE__ */ new Set();
250
- const savedPolicyWorkspaces = /* @__PURE__ */ new Set();
251
- const workspaceKey = (ctx) => `${ctx.organizationId}:${ctx.sandboxId}`;
252
- const needsWorkspaceNetworking = async (ctx, query = {}) => {
253
- const needed = await config.networking?.enabled({
254
- ctx,
255
- workspaceId: ctx.sandboxId,
256
- grant: FULL_SANDBOX_GRANT,
257
- ...query
258
- }) ?? false;
259
- if (needed) managedWorkspaces.add(workspaceKey(ctx));
260
- return needed || managedWorkspaces.has(workspaceKey(ctx));
261
- };
262
- const preservePolicy = async (args) => {
263
- if (config.networking == null) throw new Error("Workspace networking extension is required");
264
- const retained = await config.networking.prepare({
265
- ctx: args.ctx,
266
- workspaceId: args.ctx.sandboxId,
267
- policy: args.policy
268
- });
269
- await args.ctx.platformNetworkPolicy?.(retained ?? args.policy);
270
- savedPolicyWorkspaces.add(workspaceKey(args.ctx));
271
- };
272
- const teardownComputer = async (args) => {
273
- const failures = [];
274
- let managed = args.policySaved || managedWorkspaces.has(workspaceKey(args.ctx));
275
- let queryFailed = false;
276
- try {
277
- managed = await needsWorkspaceNetworking(args.ctx, { teardown: true }) || args.policySaved;
278
- } catch (cause) {
279
- failures.push(cause);
280
- queryFailed = true;
281
- }
282
- const results = await Promise.allSettled([
283
- (async () => {
284
- if (managed && args.fence) {
285
- const client = clientFor(args.ctx);
286
- let mayFence = args.policySaved || savedPolicyWorkspaces.has(workspaceKey(args.ctx));
287
- try {
288
- if (config.networking != null) {
289
- await preservePolicy({
290
- ctx: args.ctx,
291
- policy: networkPolicyFor(await client.getNetworkPolicy(args.computerId))
292
- });
293
- mayFence = true;
294
- }
295
- } catch (cause) {
296
- if (isComputersApiStatus(cause, 404)) mayFence = false;
297
- else failures.push(cause);
298
- }
299
- if (mayFence) {
300
- try {
301
- await client.setNetworkPolicy(
302
- args.computerId,
303
- { egress: ComputerEgressPolicy.None },
304
- { autoResume: false }
305
- );
306
- } catch (cause) {
307
- let settled = isComputersApiStatus(cause, 404);
308
- if (!settled && isComputersApiStatus(cause, 409)) {
309
- try {
310
- const latest = await client.getComputer(args.computerId);
311
- settled = latest == null || latest.state === ComputerState.Deleted;
312
- } catch (lookup) {
313
- failures.push(lookup);
314
- }
315
- }
316
- if (!settled) failures.push(cause);
317
- }
318
- }
319
- }
320
- await args.finish();
321
- })(),
322
- (async () => {
323
- if (managed && config.networking == null)
324
- throw new Error(
325
- "Managed Computer teardown requires the workspace egress integration to revoke Device access"
326
- );
327
- if (config.networking != null && (managed || queryFailed))
328
- await config.networking.suspend({ ctx: args.ctx, workspaceId: args.ctx.sandboxId });
329
- })()
330
- ]);
331
- for (const result of results) if (result.status === "rejected") failures.push(result.reason);
332
- if (failures.length === 1) throw failures[0];
333
- if (failures.length > 1)
334
- throw new AggregateError(failures, "Computer teardown and egress revocation failed");
335
- };
336
221
  const setupSession = (args) => {
337
222
  const transport = createComputersApiTransport({
338
223
  client: args.client,
@@ -356,53 +241,10 @@ const createComputerSandboxProvider = (config) => {
356
241
  });
357
242
  return { sandbox, transport };
358
243
  };
359
- const workspaceNetworking = (args) => {
360
- if (config.networking == null || !args.enabled) return void 0;
361
- return createNetworkingController({
362
- ctx: args.ctx,
363
- sandbox: args.sandbox,
364
- workspaceId: args.ctx.sandboxId,
365
- grant: FULL_SANDBOX_GRANT,
366
- onClose: args.onClose,
367
- initialNetworkPolicy: args.initialNetworkPolicy,
368
- namespaceExists: async () => {
369
- const current = await args.client.getComputer(args.info.id);
370
- return current?.state === ComputerState.Running;
371
- },
372
- log,
373
- afterBlock: () => args.client.setNetworkPolicy(
374
- args.info.id,
375
- { egress: ComputerEgressPolicy.None },
376
- { autoResume: false }
377
- ),
378
- afterGuard: (policy) => args.client.setNetworkPolicy(
379
- args.info.id,
380
- egressFor(args.ctx, policy ?? { mode: NetworkPolicy.DenyAll }),
381
- { autoResume: false }
382
- )
383
- });
384
- };
385
244
  const buildHandle = async (args) => {
386
245
  const { client, info } = args;
387
246
  const transport = createComputersApiTransport({ client, computerId: info.id });
388
247
  let httpToken = null;
389
- const fenceOnStop = async () => {
390
- if (args.networking != null)
391
- await client.setNetworkPolicy(
392
- info.id,
393
- { egress: ComputerEgressPolicy.None },
394
- { autoResume: false }
395
- );
396
- else if (!args.passive)
397
- await teardownComputer({
398
- ctx: args.ctx,
399
- computerId: info.id,
400
- policySaved: args.networkingManaged,
401
- fence: true,
402
- finish: async () => {
403
- }
404
- });
405
- };
406
248
  const session = createTransportSession({
407
249
  id: info.id,
408
250
  description: `Final computer ${info.name}`,
@@ -414,16 +256,10 @@ const createComputerSandboxProvider = (config) => {
414
256
  ports: [...args.ports],
415
257
  // The computer's hostname with a preview token, which opens its HTTP ports only.
416
258
  getPortEndpoint: async ({ port, protocol }) => {
417
- const managed = args.networkingManaged || args.passive && await needsWorkspaceNetworking(args.ctx);
418
- if (managed && args.networking == null)
419
- throw new Error("Managed workspace previews require an attached sandbox");
420
- const deadline = (await args.networking?.authorizeExternalAccess())?.expiresAtMs;
421
- if (deadline != null && deadline <= now())
422
- throw new Error("Refresh workspace networking before preview access");
423
259
  const hostname = info.hostname ?? (await client.getComputer(info.id))?.hostname ?? null;
424
260
  if (hostname == null) throw new Error(`computer ${info.name} has no public hostname`);
425
- if (httpToken == null || httpToken.expiresAtMs - now() < HTTP_TOKEN_RENEW_MS || deadline != null && httpToken.expiresAtMs > deadline) {
426
- const expiresAtMs = Math.min(now() + HTTP_TOKEN_LIFETIME_MS, deadline ?? Infinity);
261
+ if (httpToken == null || httpToken.expiresAtMs - now() < HTTP_TOKEN_RENEW_MS) {
262
+ const expiresAtMs = now() + HTTP_TOKEN_LIFETIME_MS;
427
263
  const token = await client.createPreviewToken({
428
264
  computerId: info.id,
429
265
  name: `agent sandbox ${args.ctx.sandboxId}`,
@@ -439,16 +275,6 @@ const createComputerSandboxProvider = (config) => {
439
275
  },
440
276
  stop: async () => {
441
277
  const failures = [];
442
- try {
443
- await fenceOnStop();
444
- } catch (cause) {
445
- try {
446
- if (!await deletedAfterFenceError({ client, computerId: info.id, cause }))
447
- failures.push(cause);
448
- } catch (lookup) {
449
- failures.push(lookup);
450
- }
451
- }
452
278
  try {
453
279
  await closeComputerMcp(info.id);
454
280
  } catch (cause) {
@@ -463,35 +289,24 @@ const createComputerSandboxProvider = (config) => {
463
289
  args.closeSetup?.();
464
290
  if (failures.length === 1) throw failures[0];
465
291
  if (failures.length > 1)
466
- throw new AggregateError(failures, "Computer stop or networking fence failed");
292
+ throw new AggregateError(failures, "Computer stop or MCP cleanup failed");
467
293
  },
468
294
  destroy: async () => {
469
- const finish = async () => {
470
- const failures = [];
471
- try {
472
- await closeComputerMcp(info.id);
473
- } catch (cause) {
474
- failures.push(cause);
475
- }
476
- transport.close();
477
- try {
478
- await client.action(info.id, "delete");
479
- } catch (cause) {
480
- if (!isComputersApiStatus(cause, 404)) failures.push(cause);
481
- }
482
- if (failures.length === 1) throw failures[0];
483
- if (failures.length > 1)
484
- throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
485
- };
486
- if (args.networking == null && !args.passive)
487
- await teardownComputer({
488
- ctx: args.ctx,
489
- computerId: info.id,
490
- policySaved: args.networkingManaged,
491
- fence: true,
492
- finish
493
- });
494
- else await finish();
295
+ const failures = [];
296
+ try {
297
+ await closeComputerMcp(info.id);
298
+ } catch (cause) {
299
+ failures.push(cause);
300
+ }
301
+ transport.close();
302
+ try {
303
+ await client.action(info.id, "delete");
304
+ } catch (cause) {
305
+ if (!isComputersApiStatus(cause, 404)) failures.push(cause);
306
+ }
307
+ if (failures.length === 1) throw failures[0];
308
+ if (failures.length > 1)
309
+ throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
495
310
  }
496
311
  }
497
312
  });
@@ -535,8 +350,6 @@ const createComputerSandboxProvider = (config) => {
535
350
  SandboxCapability.DurableProcesses,
536
351
  SandboxCapability.NetworkPolicy
537
352
  );
538
- if (!args.passive && args.networking != null)
539
- capabilities.push(...config.networking?.capabilities ?? []);
540
353
  const full = {
541
354
  ...session,
542
355
  setNetworkPolicy: async (policy) => {
@@ -547,20 +360,10 @@ const createComputerSandboxProvider = (config) => {
547
360
  };
548
361
  if (computerUse != null) full.computerUse = async () => computerUse.endpoint;
549
362
  if (screenAvailable) full.screen = (options) => client.openScreen(info.id, options);
550
- let handle = {
363
+ return {
551
364
  sandbox: args.passive ? readOnlySession(full) : full,
552
365
  onSandboxStop: async () => {
553
366
  const failures = [];
554
- try {
555
- await fenceOnStop();
556
- } catch (cause) {
557
- try {
558
- if (!await deletedAfterFenceError({ client, computerId: info.id, cause }))
559
- failures.push(cause);
560
- } catch (lookup) {
561
- failures.push(lookup);
562
- }
563
- }
564
367
  for (const finish of [closeMcp, () => transport.close(), () => args.closeSetup?.()]) {
565
368
  try {
566
369
  await finish();
@@ -569,37 +372,25 @@ const createComputerSandboxProvider = (config) => {
569
372
  }
570
373
  }
571
374
  if (failures.length === 1) throw failures[0];
572
- if (failures.length > 1)
573
- throw new AggregateError(failures, "Computer fence and MCP cleanup failed");
375
+ if (failures.length > 1) throw new AggregateError(failures, "Computer MCP cleanup failed");
574
376
  },
575
377
  onSandboxDelete: async () => {
576
- const finish = async () => {
577
- const failures = [];
578
- try {
579
- await closeMcp();
580
- } catch (cause) {
581
- failures.push(cause);
582
- }
583
- transport.close();
584
- args.closeSetup?.();
585
- try {
586
- await client.action(info.id, "delete");
587
- } catch (cause) {
588
- if (!isComputersApiStatus(cause, 404)) failures.push(cause);
589
- }
590
- if (failures.length === 1) throw failures[0];
591
- if (failures.length > 1)
592
- throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
593
- };
594
- if (args.networking == null)
595
- await teardownComputer({
596
- ctx: args.ctx,
597
- computerId: info.id,
598
- policySaved: args.networkingManaged,
599
- fence: true,
600
- finish
601
- });
602
- else await finish();
378
+ const failures = [];
379
+ try {
380
+ await closeMcp();
381
+ } catch (cause) {
382
+ failures.push(cause);
383
+ }
384
+ transport.close();
385
+ args.closeSetup?.();
386
+ try {
387
+ await client.action(info.id, "delete");
388
+ } catch (cause) {
389
+ if (!isComputersApiStatus(cause, 404)) failures.push(cause);
390
+ }
391
+ if (failures.length === 1) throw failures[0];
392
+ if (failures.length > 1)
393
+ throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
603
394
  },
604
395
  onRuntimeShutdown: async () => {
605
396
  try {
@@ -610,31 +401,6 @@ const createComputerSandboxProvider = (config) => {
610
401
  }
611
402
  }
612
403
  };
613
- if (args.passive) return handle;
614
- if (args.networking != null)
615
- handle = await withSandboxNetworking({
616
- handle,
617
- controller: args.networking,
618
- grant: FULL_SANDBOX_GRANT,
619
- initialized: true,
620
- fetch: config.networking?.fetch,
621
- executionPolicy: args.ctx.executionPolicy,
622
- beforeUse: args.beforeUse
623
- });
624
- else if (config.networking != null)
625
- handle = await withSandboxNetworking({
626
- handle,
627
- grant: FULL_SANDBOX_GRANT,
628
- fetch: config.networking.fetch,
629
- executionPolicy: args.ctx.executionPolicy,
630
- admission: async () => {
631
- if (await needsWorkspaceNetworking(args.ctx))
632
- throw new Error(
633
- "Workspace networking changed; reconnect this sandbox before running tools"
634
- );
635
- }
636
- });
637
- return handle;
638
404
  };
639
405
  const awaitBase = async (client, baseId, key) => {
640
406
  const deadline = now() + (config.buildWaitMs ?? 30 * 6e4);
@@ -840,8 +606,6 @@ ${step.run}`,
840
606
  [Capability.Shell]: ShellAccess.Execute,
841
607
  [Capability.ComputerUse]: ScreenAccess.Control
842
608
  }),
843
- // Screen and computer-use availability is known only after attaching the actual Computer.
844
- additionalFeatures: async () => config.networking?.capabilities.slice() ?? [],
845
609
  processes: async (ctx, rawState, request) => {
846
610
  const state = stateOf(rawState);
847
611
  if (state.computerId == null) throw new Error("this computer has not started yet");
@@ -862,52 +626,7 @@ ${step.run}`,
862
626
  randomUuid,
863
627
  expiresAtMs
864
628
  });
865
- if (request.operation === "available" || request.operation === "close") return open();
866
- if (config.networking == null) {
867
- if (state.networkPolicySaved)
868
- throw new Error("Device networking control is required before opening this editor");
869
- return open();
870
- }
871
- if (ctx.sandboxId == null)
872
- throw new Error("The host must name the sandbox before opening an egress-aware editor");
873
- const networkingCtx = { ...ctx, sandboxId: ctx.sandboxId };
874
- const managed = state.networkPolicySaved || await needsWorkspaceNetworking(networkingCtx);
875
- if (!managed) return open();
876
- config.networking.validateWorkspaceId?.(ctx.sandboxId);
877
- const info = await client.getComputer(computerId);
878
- if (info == null || info.state !== ComputerState.Running)
879
- throw new Error("Computer must be running before editor access");
880
- const initialNetworkPolicy = networkPolicyFor(await client.getNetworkPolicy(info.id));
881
- const setup = setupSession({ client, info, env: async () => ({}) });
882
- const manager = createNetworkingController({
883
- sandbox: setup.sandbox,
884
- onClose: () => setup.transport.close(),
885
- workspaceId: ctx.sandboxId,
886
- ctx,
887
- grant: FULL_SANDBOX_GRANT,
888
- initialNetworkPolicy,
889
- afterBlock: () => client.setNetworkPolicy(
890
- info.id,
891
- { egress: ComputerEgressPolicy.None },
892
- { autoResume: false }
893
- ),
894
- afterGuard: async (policy) => client.setNetworkPolicy(
895
- info.id,
896
- policy == null ? { egress: ComputerEgressPolicy.None } : egressFor(ctx, policy),
897
- { autoResume: false }
898
- ),
899
- allowOwnerChange: false
900
- });
901
- const { expiresAtMs: deadline } = await manager.authorizeExternalAccess().finally(async () => {
902
- try {
903
- await manager.close();
904
- } finally {
905
- setup.transport.close();
906
- }
907
- });
908
- if (deadline != null && deadline <= now())
909
- throw new Error("Refresh workspace egress before opening the editor");
910
- return open(deadline ?? void 0);
629
+ return open();
911
630
  },
912
631
  readSnapshot: async (ctx, rawState, request) => {
913
632
  const state = stateOf(rawState);
@@ -969,8 +688,7 @@ ${step.run}`,
969
688
  computerName: await computerNameFor(ctx.sandboxId),
970
689
  computerId: null,
971
690
  network,
972
- ports,
973
- networkPolicySaved: false
691
+ ports
974
692
  },
975
693
  region
976
694
  };
@@ -997,35 +715,21 @@ ${step.run}`,
997
715
  "artifact_unavailable",
998
716
  `computer base ${artifact.data.key} was prepared without its build steps; prepare it again`
999
717
  );
1000
- const networkingCtx = offerContextOf(ctx);
1001
718
  const client = clientFor(ctx);
1002
719
  const env = platformProcessEnvironment(ctx, {});
1003
720
  const policy = withPlatformEgressHosts(ctx, state.network);
1004
721
  const egress = computerEgressOf(policy);
1005
- const manageNetworking = state.networkPolicySaved || await needsWorkspaceNetworking(networkingCtx);
1006
- if (manageNetworking) config.networking?.validateWorkspaceId?.(ctx.sandboxId);
1007
722
  const existing = await findComputer(client, state);
1008
723
  if (existing?.state === ComputerState.Error)
1009
724
  throw computerSandboxError(
1010
725
  "computer_gone",
1011
726
  `Computer ${existing.id} (${existing.name}) is in the Error state. Recover it through the Computers API before retrying; its disk is preserved.`
1012
727
  );
1013
- const initialNetworkPolicy = manageNetworking && existing != null ? networkPolicyFor(await client.getNetworkPolicy(existing.id)) : networkPolicyFor(egress);
1014
- if (manageNetworking && existing?.state === ComputerState.Running)
1015
- await client.disableAutoResume(existing.id);
1016
- if (manageNetworking && config.networking != null)
1017
- await preservePolicy({ ctx: networkingCtx, policy: initialNetworkPolicy });
1018
728
  let info;
1019
729
  let booted;
1020
730
  if (existing != null) {
1021
731
  info = existing;
1022
732
  booted = !isRunningState(existing.state);
1023
- if (manageNetworking && existing.state !== ComputerState.Running)
1024
- await client.setNetworkPolicy(
1025
- existing.id,
1026
- { egress: ComputerEgressPolicy.None },
1027
- { autoResume: false }
1028
- );
1029
733
  if (existing.state === ComputerState.Paused) await client.action(existing.id, "resume");
1030
734
  else if (booted) await client.action(existing.id, "start");
1031
735
  } else {
@@ -1036,11 +740,11 @@ ${step.run}`,
1036
740
  ...source,
1037
741
  ...machine,
1038
742
  env: {},
1039
- autoResume: !manageNetworking,
743
+ autoResume: true,
1040
744
  idleTimeoutSeconds: idleTimeoutFor(ctx),
1041
745
  // The sandbox owns deletion; VM-level ephemeral disks cannot be paused.
1042
746
  ephemeral: false,
1043
- network: manageNetworking ? { egress: ComputerEgressPolicy.None } : egress,
747
+ network: egress,
1044
748
  tags: [
1045
749
  "final-agent-sandbox",
1046
750
  `agent-sandbox:${ctx.sandboxId}`,
@@ -1050,7 +754,7 @@ ${step.run}`,
1050
754
  };
1051
755
  body.idlePolicy = ComputerIdlePolicy.Pause;
1052
756
  if (region != null) body.regionSlug = region;
1053
- const idempotencyKey = `agent-sandbox-${(await sha256Hex(`${ctx.sandboxId}:${state.computerName}:${state.computerId ?? "first"}:${source.baseId ?? source.imageVersionId}:${manageNetworking}`)).slice(0, 32)}`;
757
+ const idempotencyKey = `agent-sandbox-${(await sha256Hex(`${ctx.sandboxId}:${state.computerName}:${state.computerId ?? "first"}:${source.baseId ?? source.imageVersionId}:false`)).slice(0, 32)}`;
1054
758
  info = await client.createComputer(body, idempotencyKey);
1055
759
  }
1056
760
  const fresh = existing == null;
@@ -1058,81 +762,35 @@ ${step.run}`,
1058
762
  let cleanup = null;
1059
763
  try {
1060
764
  info = await awaitComputerRunning(client, info.id, runningWaitMs);
1061
- if (!manageNetworking) {
1062
- if (!fresh) await client.setNetworkPolicy(info.id, egress);
1063
- await reportPlatformNetworkPolicy(ctx, policy);
1064
- }
765
+ if (!fresh) await client.setNetworkPolicy(info.id, egress);
766
+ await reportPlatformNetworkPolicy(ctx, policy);
1065
767
  const setup = setupSession({ client, info, env });
1066
768
  cleanup = async () => setup.transport.close();
1067
769
  await writePlatformFiles(ctx, setup.sandbox);
1068
- const manager = workspaceNetworking({
1069
- ctx: networkingCtx,
1070
- enabled: manageNetworking,
1071
- sandbox: setup.sandbox,
1072
- client,
1073
- info,
1074
- onClose: () => setup.transport.close(),
1075
- initialNetworkPolicy
1076
- });
1077
- cleanup = async () => {
1078
- try {
1079
- await manager?.closeOnFailure();
1080
- } finally {
1081
- setup.transport.close();
1082
- }
1083
- };
1084
- await manager?.initialize();
1085
- const seedMarker = `${WORKSPACE_ROOT}/.final/workspace-prepared/${await sha256Hex(artifact.data.key)}`;
1086
- let seeding = null;
1087
- const seedWorkspace = () => seeding ??= (async () => {
1088
- if (await setup.sandbox.stat({ path: seedMarker }) != null) return;
1089
- await materializeSandboxSeeds({
1090
- sandbox: setup.sandbox,
1091
- root: WORKSPACE_ROOT,
1092
- files: await sandboxSeedFilesForAttach(ctx, artifact.data)
1093
- });
1094
- await setup.sandbox.writeTextFile({ path: seedMarker, content: "complete" });
1095
- })().catch((cause) => {
1096
- seeding = null;
1097
- throw cause;
1098
- });
1099
- let ready = true;
1100
- if (manager != null) {
1101
- try {
1102
- await ctx.executionPolicy?.beforeExecution({
1103
- operation: SandboxExecutionOperation.Run,
1104
- background: false
1105
- });
1106
- await manager.guard();
1107
- } catch {
1108
- log("workspace_networking.setup_deferred", {
1109
- provider: COMPUTER_PROVIDER,
1110
- computerId: info.id
770
+ if (fresh) {
771
+ const seedMarker = `${WORKSPACE_ROOT}/.final/workspace-prepared/${await sha256Hex(artifact.data.key)}`;
772
+ if (await setup.sandbox.stat({ path: seedMarker }) == null) {
773
+ await materializeSandboxSeeds({
774
+ sandbox: setup.sandbox,
775
+ root: WORKSPACE_ROOT,
776
+ files: await sandboxSeedFilesForAttach(ctx, artifact.data)
1111
777
  });
1112
- ready = false;
778
+ await setup.sandbox.writeTextFile({ path: seedMarker, content: "complete" });
1113
779
  }
1114
780
  }
1115
- if (fresh && ready) await seedWorkspace();
1116
781
  const handle = await buildHandle({
1117
- ctx: { ...networkingCtx, executionPolicy: ctx.executionPolicy },
782
+ ctx,
1118
783
  client,
1119
784
  info,
1120
785
  env,
1121
786
  ports: state.ports,
1122
787
  passive: false,
1123
- networking: manager,
1124
- networkingManaged: manageNetworking,
1125
- closeSetup: () => setup.transport.close(),
1126
- beforeUse: fresh ? seedWorkspace : void 0
788
+ closeSetup: () => setup.transport.close()
1127
789
  });
1128
790
  return {
1129
791
  handle,
1130
792
  region: info.regionSlug ?? region,
1131
- state: {
1132
- ...state,
1133
- computerId: info.id,
1134
- networkPolicySaved: manageNetworking
1135
- },
793
+ state: { ...state, computerId: info.id },
1136
794
  fresh,
1137
795
  booted
1138
796
  };
@@ -1143,7 +801,7 @@ ${step.run}`,
1143
801
  } catch (cleanupError) {
1144
802
  cause = new AggregateError(
1145
803
  [error, cleanupError],
1146
- "Computer attach and egress cleanup failed"
804
+ "Computer attach and setup cleanup failed"
1147
805
  );
1148
806
  }
1149
807
  if (fresh) {
@@ -1169,13 +827,12 @@ ${step.run}`,
1169
827
  "computer is not running for passive access"
1170
828
  );
1171
829
  return buildHandle({
1172
- ctx: { ...offerContextOf(ctx), executionPolicy: ctx.executionPolicy },
830
+ ctx,
1173
831
  client,
1174
832
  info: await awaitComputerRunning(client, info.id, runningWaitMs),
1175
833
  env: platformProcessEnvironment(ctx, {}),
1176
834
  ports: state.ports,
1177
- passive: true,
1178
- networkingManaged: state.networkPolicySaved
835
+ passive: true
1179
836
  });
1180
837
  },
1181
838
  // The computer pauses on its own idle policy; nothing to do.
@@ -1184,94 +841,67 @@ ${step.run}`,
1184
841
  const state = stateOf(rawState);
1185
842
  if (state.computerId == null) return state;
1186
843
  const computerId = state.computerId;
1187
- const networkingCtx = offerContextOf(ctx);
1188
- await teardownComputer({
1189
- ctx: networkingCtx,
1190
- computerId,
1191
- policySaved: state.networkPolicySaved,
1192
- fence: true,
1193
- finish: async () => {
1194
- const failures = [];
1195
- try {
1196
- await closeComputerMcp(computerId);
1197
- } catch (cause) {
1198
- failures.push(cause);
1199
- }
844
+ const failures = [];
845
+ try {
846
+ await closeComputerMcp(computerId);
847
+ } catch (cause) {
848
+ failures.push(cause);
849
+ }
850
+ try {
851
+ const client = clientFor(ctx);
852
+ let current;
853
+ try {
854
+ current = await client.getComputer(computerId);
855
+ } catch (cause) {
856
+ failures.push(cause);
857
+ }
858
+ if (current !== void 0 && (current == null || hasNothingToPause(current.state))) {
859
+ log("computer_sandbox.park_at_rest", {
860
+ computerId,
861
+ state: current?.state ?? null
862
+ });
863
+ } else {
1200
864
  try {
1201
- const client = clientFor(ctx);
1202
- let current;
1203
- try {
1204
- current = await client.getComputer(computerId);
1205
- } catch (cause) {
1206
- failures.push(cause);
1207
- }
1208
- if (current !== void 0 && (current == null || hasNothingToPause(current.state))) {
1209
- log("computer_sandbox.park_at_rest", {
1210
- computerId,
1211
- state: current?.state ?? null
1212
- });
1213
- } else {
1214
- try {
1215
- await client.action(computerId, "pause");
1216
- } catch (error) {
1217
- if (!pauseMayHaveSettled(error)) throw error;
1218
- const settled = await client.getComputer(computerId);
1219
- if (settled != null && settled.state !== ComputerState.Paused && !hasNothingToPause(settled.state))
1220
- throw error;
1221
- log("computer_sandbox.park_at_rest", {
1222
- computerId,
1223
- state: settled?.state ?? null
1224
- });
1225
- }
1226
- }
1227
- } catch (cause) {
1228
- failures.push(cause);
865
+ await client.action(computerId, "pause");
866
+ } catch (error) {
867
+ if (!pauseMayHaveSettled(error)) throw error;
868
+ const settled = await client.getComputer(computerId);
869
+ if (settled != null && settled.state !== ComputerState.Paused && !hasNothingToPause(settled.state))
870
+ throw error;
871
+ log("computer_sandbox.park_at_rest", {
872
+ computerId,
873
+ state: settled?.state ?? null
874
+ });
1229
875
  }
1230
- if (failures.length === 1) throw failures[0];
1231
- if (failures.length > 1) throw new AggregateError(failures, "Computer pause failed");
1232
876
  }
1233
- });
1234
- return {
1235
- ...state,
1236
- networkPolicySaved: state.networkPolicySaved || savedPolicyWorkspaces.has(workspaceKey(networkingCtx))
1237
- };
877
+ } catch (cause) {
878
+ failures.push(cause);
879
+ }
880
+ if (failures.length === 1) throw failures[0];
881
+ if (failures.length > 1) throw new AggregateError(failures, "Computer pause failed");
882
+ return state;
1238
883
  },
1239
884
  delete: async (ctx, { state: rawState }) => {
1240
885
  const state = stateOf(rawState);
1241
886
  const client = clientFor(ctx);
1242
887
  const computer = await findComputer(client, state);
1243
- if (computer == null) {
1244
- if (state.networkPolicySaved && config.networking != null)
1245
- await config.networking.suspend({
1246
- ctx: offerContextOf(ctx),
1247
- workspaceId: ctx.sandboxId
1248
- });
1249
- return;
888
+ if (computer == null) return;
889
+ const failures = [];
890
+ try {
891
+ await closeComputerMcp(computer.id);
892
+ } catch (cause) {
893
+ failures.push(cause);
1250
894
  }
1251
- await teardownComputer({
1252
- ctx: offerContextOf(ctx),
1253
- computerId: computer.id,
1254
- policySaved: state.networkPolicySaved,
1255
- fence: false,
1256
- finish: async () => {
1257
- const failures = [];
1258
- try {
1259
- await closeComputerMcp(computer.id);
1260
- } catch (cause) {
1261
- failures.push(cause);
1262
- }
1263
- log("computer_sandbox.delete", { computerId: computer.id });
1264
- try {
1265
- await client.action(computer.id, "delete");
1266
- } catch (error) {
1267
- if (!await deletedAfterFenceError({ client, computerId: computer.id, cause: error }))
1268
- failures.push(error);
1269
- }
1270
- if (failures.length === 1) throw failures[0];
1271
- if (failures.length > 1)
1272
- throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
1273
- }
1274
- });
895
+ log("computer_sandbox.delete", { computerId: computer.id });
896
+ try {
897
+ await client.action(computer.id, "delete");
898
+ } catch (error) {
899
+ if (!await deletedAfterFenceError({ client, computerId: computer.id, cause: error }))
900
+ failures.push(error);
901
+ }
902
+ if (failures.length === 1) throw failures[0];
903
+ if (failures.length > 1)
904
+ throw new AggregateError(failures, "Computer delete or MCP cleanup failed");
1275
905
  }
1276
906
  };
1277
907
  };