@openai/agents-extensions 0.8.5 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/metadata.js +2 -2
- package/dist/metadata.mjs +2 -2
- package/dist/sandbox/blaxel/index.d.ts +2 -0
- package/dist/sandbox/blaxel/index.js +19 -0
- package/dist/sandbox/blaxel/index.js.map +1 -0
- package/dist/sandbox/blaxel/index.mjs +3 -0
- package/dist/sandbox/blaxel/index.mjs.map +1 -0
- package/dist/sandbox/blaxel/mounts.d.ts +101 -0
- package/dist/sandbox/blaxel/mounts.js +542 -0
- package/dist/sandbox/blaxel/mounts.js.map +1 -0
- package/dist/sandbox/blaxel/mounts.mjs +529 -0
- package/dist/sandbox/blaxel/mounts.mjs.map +1 -0
- package/dist/sandbox/blaxel/sandbox.d.ts +155 -0
- package/dist/sandbox/blaxel/sandbox.js +1110 -0
- package/dist/sandbox/blaxel/sandbox.js.map +1 -0
- package/dist/sandbox/blaxel/sandbox.mjs +1072 -0
- package/dist/sandbox/blaxel/sandbox.mjs.map +1 -0
- package/dist/sandbox/cloudflare/index.d.ts +2 -0
- package/dist/sandbox/cloudflare/index.js +19 -0
- package/dist/sandbox/cloudflare/index.js.map +1 -0
- package/dist/sandbox/cloudflare/index.mjs +3 -0
- package/dist/sandbox/cloudflare/index.mjs.map +1 -0
- package/dist/sandbox/cloudflare/mounts.d.ts +28 -0
- package/dist/sandbox/cloudflare/mounts.js +150 -0
- package/dist/sandbox/cloudflare/mounts.js.map +1 -0
- package/dist/sandbox/cloudflare/mounts.mjs +143 -0
- package/dist/sandbox/cloudflare/mounts.mjs.map +1 -0
- package/dist/sandbox/cloudflare/sandbox.d.ts +91 -0
- package/dist/sandbox/cloudflare/sandbox.js +1163 -0
- package/dist/sandbox/cloudflare/sandbox.js.map +1 -0
- package/dist/sandbox/cloudflare/sandbox.mjs +1125 -0
- package/dist/sandbox/cloudflare/sandbox.mjs.map +1 -0
- package/dist/sandbox/daytona/index.d.ts +2 -0
- package/dist/sandbox/daytona/index.js +19 -0
- package/dist/sandbox/daytona/index.js.map +1 -0
- package/dist/sandbox/daytona/index.mjs +3 -0
- package/dist/sandbox/daytona/index.mjs.map +1 -0
- package/dist/sandbox/daytona/mounts.d.ts +11 -0
- package/dist/sandbox/daytona/mounts.js +17 -0
- package/dist/sandbox/daytona/mounts.js.map +1 -0
- package/dist/sandbox/daytona/mounts.mjs +12 -0
- package/dist/sandbox/daytona/mounts.mjs.map +1 -0
- package/dist/sandbox/daytona/sandbox.d.ts +160 -0
- package/dist/sandbox/daytona/sandbox.js +938 -0
- package/dist/sandbox/daytona/sandbox.js.map +1 -0
- package/dist/sandbox/daytona/sandbox.mjs +900 -0
- package/dist/sandbox/daytona/sandbox.mjs.map +1 -0
- package/dist/sandbox/e2b/index.d.ts +2 -0
- package/dist/sandbox/e2b/index.js +19 -0
- package/dist/sandbox/e2b/index.js.map +1 -0
- package/dist/sandbox/e2b/index.mjs +3 -0
- package/dist/sandbox/e2b/index.mjs.map +1 -0
- package/dist/sandbox/e2b/mounts.d.ts +11 -0
- package/dist/sandbox/e2b/mounts.js +17 -0
- package/dist/sandbox/e2b/mounts.js.map +1 -0
- package/dist/sandbox/e2b/mounts.mjs +12 -0
- package/dist/sandbox/e2b/mounts.mjs.map +1 -0
- package/dist/sandbox/e2b/sandbox.d.ts +169 -0
- package/dist/sandbox/e2b/sandbox.js +829 -0
- package/dist/sandbox/e2b/sandbox.js.map +1 -0
- package/dist/sandbox/e2b/sandbox.mjs +791 -0
- package/dist/sandbox/e2b/sandbox.mjs.map +1 -0
- package/dist/sandbox/modal/index.d.ts +2 -0
- package/dist/sandbox/modal/index.js +19 -0
- package/dist/sandbox/modal/index.js.map +1 -0
- package/dist/sandbox/modal/index.mjs +3 -0
- package/dist/sandbox/modal/index.mjs.map +1 -0
- package/dist/sandbox/modal/mounts.d.ts +24 -0
- package/dist/sandbox/modal/mounts.js +194 -0
- package/dist/sandbox/modal/mounts.js.map +1 -0
- package/dist/sandbox/modal/mounts.mjs +188 -0
- package/dist/sandbox/modal/mounts.mjs.map +1 -0
- package/dist/sandbox/modal/sandbox.d.ts +220 -0
- package/dist/sandbox/modal/sandbox.js +1621 -0
- package/dist/sandbox/modal/sandbox.js.map +1 -0
- package/dist/sandbox/modal/sandbox.mjs +1581 -0
- package/dist/sandbox/modal/sandbox.mjs.map +1 -0
- package/dist/sandbox/runloop/index.d.ts +2 -0
- package/dist/sandbox/runloop/index.js +19 -0
- package/dist/sandbox/runloop/index.js.map +1 -0
- package/dist/sandbox/runloop/index.mjs +3 -0
- package/dist/sandbox/runloop/index.mjs.map +1 -0
- package/dist/sandbox/runloop/mounts.d.ts +11 -0
- package/dist/sandbox/runloop/mounts.js +17 -0
- package/dist/sandbox/runloop/mounts.js.map +1 -0
- package/dist/sandbox/runloop/mounts.mjs +12 -0
- package/dist/sandbox/runloop/mounts.mjs.map +1 -0
- package/dist/sandbox/runloop/sandbox.d.ts +266 -0
- package/dist/sandbox/runloop/sandbox.js +1390 -0
- package/dist/sandbox/runloop/sandbox.js.map +1 -0
- package/dist/sandbox/runloop/sandbox.mjs +1346 -0
- package/dist/sandbox/runloop/sandbox.mjs.map +1 -0
- package/dist/sandbox/shared/archive.d.ts +34 -0
- package/dist/sandbox/shared/archive.js +397 -0
- package/dist/sandbox/shared/archive.js.map +1 -0
- package/dist/sandbox/shared/archive.mjs +389 -0
- package/dist/sandbox/shared/archive.mjs.map +1 -0
- package/dist/sandbox/shared/editor.d.ts +17 -0
- package/dist/sandbox/shared/editor.js +65 -0
- package/dist/sandbox/shared/editor.js.map +1 -0
- package/dist/sandbox/shared/editor.mjs +61 -0
- package/dist/sandbox/shared/editor.mjs.map +1 -0
- package/dist/sandbox/shared/environment.d.ts +1 -0
- package/dist/sandbox/shared/environment.js +13 -0
- package/dist/sandbox/shared/environment.js.map +1 -0
- package/dist/sandbox/shared/environment.mjs +2 -0
- package/dist/sandbox/shared/environment.mjs.map +1 -0
- package/dist/sandbox/shared/git.d.ts +4 -0
- package/dist/sandbox/shared/git.js +20 -0
- package/dist/sandbox/shared/git.js.map +1 -0
- package/dist/sandbox/shared/git.mjs +17 -0
- package/dist/sandbox/shared/git.mjs.map +1 -0
- package/dist/sandbox/shared/inContainerMounts.d.ts +40 -0
- package/dist/sandbox/shared/inContainerMounts.js +670 -0
- package/dist/sandbox/shared/inContainerMounts.js.map +1 -0
- package/dist/sandbox/shared/inContainerMounts.mjs +662 -0
- package/dist/sandbox/shared/inContainerMounts.mjs.map +1 -0
- package/dist/sandbox/shared/index.d.ts +23 -0
- package/dist/sandbox/shared/index.js +112 -0
- package/dist/sandbox/shared/index.js.map +1 -0
- package/dist/sandbox/shared/index.mjs +18 -0
- package/dist/sandbox/shared/index.mjs.map +1 -0
- package/dist/sandbox/shared/localSources.d.ts +8 -0
- package/dist/sandbox/shared/localSources.js +378 -0
- package/dist/sandbox/shared/localSources.js.map +1 -0
- package/dist/sandbox/shared/localSources.mjs +372 -0
- package/dist/sandbox/shared/localSources.mjs.map +1 -0
- package/dist/sandbox/shared/manifest.d.ts +38 -0
- package/dist/sandbox/shared/manifest.js +254 -0
- package/dist/sandbox/shared/manifest.js.map +1 -0
- package/dist/sandbox/shared/manifest.mjs +233 -0
- package/dist/sandbox/shared/manifest.mjs.map +1 -0
- package/dist/sandbox/shared/media.d.ts +1 -0
- package/dist/sandbox/shared/media.js +10 -0
- package/dist/sandbox/shared/media.js.map +1 -0
- package/dist/sandbox/shared/media.mjs +2 -0
- package/dist/sandbox/shared/media.mjs.map +1 -0
- package/dist/sandbox/shared/metadata.d.ts +7 -0
- package/dist/sandbox/shared/metadata.js +87 -0
- package/dist/sandbox/shared/metadata.js.map +1 -0
- package/dist/sandbox/shared/metadata.mjs +81 -0
- package/dist/sandbox/shared/metadata.mjs.map +1 -0
- package/dist/sandbox/shared/output.d.ts +1 -0
- package/dist/sandbox/shared/output.js +8 -0
- package/dist/sandbox/shared/output.js.map +1 -0
- package/dist/sandbox/shared/output.mjs +2 -0
- package/dist/sandbox/shared/output.mjs.map +1 -0
- package/dist/sandbox/shared/paths.d.ts +27 -0
- package/dist/sandbox/shared/paths.js +245 -0
- package/dist/sandbox/shared/paths.js.map +1 -0
- package/dist/sandbox/shared/paths.mjs +236 -0
- package/dist/sandbox/shared/paths.mjs.map +1 -0
- package/dist/sandbox/shared/ports.d.ts +14 -0
- package/dist/sandbox/shared/ports.js +75 -0
- package/dist/sandbox/shared/ports.js.map +1 -0
- package/dist/sandbox/shared/ports.mjs +69 -0
- package/dist/sandbox/shared/ports.mjs.map +1 -0
- package/dist/sandbox/shared/process.d.ts +16 -0
- package/dist/sandbox/shared/process.js +90 -0
- package/dist/sandbox/shared/process.js.map +1 -0
- package/dist/sandbox/shared/process.mjs +86 -0
- package/dist/sandbox/shared/process.mjs.map +1 -0
- package/dist/sandbox/shared/pty.d.ts +81 -0
- package/dist/sandbox/shared/pty.js +382 -0
- package/dist/sandbox/shared/pty.js.map +1 -0
- package/dist/sandbox/shared/pty.mjs +335 -0
- package/dist/sandbox/shared/pty.mjs.map +1 -0
- package/dist/sandbox/shared/runAs.d.ts +46 -0
- package/dist/sandbox/shared/runAs.js +149 -0
- package/dist/sandbox/shared/runAs.js.map +1 -0
- package/dist/sandbox/shared/runAs.mjs +141 -0
- package/dist/sandbox/shared/runAs.mjs.map +1 -0
- package/dist/sandbox/shared/session.d.ts +16 -0
- package/dist/sandbox/shared/session.js +138 -0
- package/dist/sandbox/shared/session.js.map +1 -0
- package/dist/sandbox/shared/session.mjs +128 -0
- package/dist/sandbox/shared/session.mjs.map +1 -0
- package/dist/sandbox/shared/sessionBase.d.ts +90 -0
- package/dist/sandbox/shared/sessionBase.js +446 -0
- package/dist/sandbox/shared/sessionBase.js.map +1 -0
- package/dist/sandbox/shared/sessionBase.mjs +442 -0
- package/dist/sandbox/shared/sessionBase.mjs.map +1 -0
- package/dist/sandbox/shared/sessionState.d.ts +7 -0
- package/dist/sandbox/shared/sessionState.js +35 -0
- package/dist/sandbox/shared/sessionState.js.map +1 -0
- package/dist/sandbox/shared/sessionState.mjs +31 -0
- package/dist/sandbox/shared/sessionState.mjs.map +1 -0
- package/dist/sandbox/shared/snapshots.d.ts +9 -0
- package/dist/sandbox/shared/snapshots.js +62 -0
- package/dist/sandbox/shared/snapshots.js.map +1 -0
- package/dist/sandbox/shared/snapshots.mjs +57 -0
- package/dist/sandbox/shared/snapshots.mjs.map +1 -0
- package/dist/sandbox/shared/typeGuards.d.ts +10 -0
- package/dist/sandbox/shared/typeGuards.js +50 -0
- package/dist/sandbox/shared/typeGuards.js.map +1 -0
- package/dist/sandbox/shared/typeGuards.mjs +38 -0
- package/dist/sandbox/shared/typeGuards.mjs.map +1 -0
- package/dist/sandbox/shared/types.d.ts +24 -0
- package/dist/sandbox/shared/types.js +3 -0
- package/dist/sandbox/shared/types.js.map +1 -0
- package/dist/sandbox/shared/types.mjs +2 -0
- package/dist/sandbox/shared/types.mjs.map +1 -0
- package/dist/sandbox/vercel/index.d.ts +1 -0
- package/dist/sandbox/vercel/index.js +18 -0
- package/dist/sandbox/vercel/index.js.map +1 -0
- package/dist/sandbox/vercel/index.mjs +2 -0
- package/dist/sandbox/vercel/index.mjs.map +1 -0
- package/dist/sandbox/vercel/sandbox.d.ts +135 -0
- package/dist/sandbox/vercel/sandbox.js +1001 -0
- package/dist/sandbox/vercel/sandbox.js.map +1 -0
- package/dist/sandbox/vercel/sandbox.mjs +963 -0
- package/dist/sandbox/vercel/sandbox.mjs.map +1 -0
- package/package.json +108 -4
|
@@ -0,0 +1,1001 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.VercelSandboxClient = exports.VercelSandboxSession = void 0;
|
|
37
|
+
const agents_core_1 = require("@openai/agents-core");
|
|
38
|
+
const node_fs_1 = require("node:fs");
|
|
39
|
+
const node_path_1 = require("node:path");
|
|
40
|
+
const sandbox_1 = require("@openai/agents-core/sandbox");
|
|
41
|
+
const shared_1 = require("../shared/index.js");
|
|
42
|
+
const DEFAULT_VERCEL_WORKSPACE_ROOT = '/vercel/sandbox';
|
|
43
|
+
class VercelSandboxSession extends shared_1.RemoteSandboxSessionBase {
|
|
44
|
+
sandbox;
|
|
45
|
+
knownDirs;
|
|
46
|
+
pendingDirCreates = new Map();
|
|
47
|
+
closePromise;
|
|
48
|
+
closeCompleted = false;
|
|
49
|
+
credentials;
|
|
50
|
+
constructor(args) {
|
|
51
|
+
super({
|
|
52
|
+
state: args.state,
|
|
53
|
+
options: {
|
|
54
|
+
providerName: 'VercelSandboxClient',
|
|
55
|
+
providerId: 'vercel',
|
|
56
|
+
concurrencyLimits: args.concurrencyLimits,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
this.sandbox = args.sandbox;
|
|
60
|
+
this.credentials = args.credentials ?? {};
|
|
61
|
+
this.knownDirs = new Set();
|
|
62
|
+
this.resetKnownDirs();
|
|
63
|
+
}
|
|
64
|
+
supportsPty() {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
assertExecRunAs(runAs) {
|
|
68
|
+
(0, shared_1.assertRunAsUnsupported)('VercelSandboxClient', runAs);
|
|
69
|
+
}
|
|
70
|
+
assertFilesystemRunAs(runAs) {
|
|
71
|
+
assertFilesystemRunAs(runAs);
|
|
72
|
+
}
|
|
73
|
+
resolveManifestForApply(manifest) {
|
|
74
|
+
return resolveManifestRoot(manifest);
|
|
75
|
+
}
|
|
76
|
+
async beforeFilesystemMutation() {
|
|
77
|
+
this.markWorkspaceMutated();
|
|
78
|
+
}
|
|
79
|
+
async beforeExecCommand() {
|
|
80
|
+
this.markWorkspaceMutated();
|
|
81
|
+
this.resetKnownDirs();
|
|
82
|
+
}
|
|
83
|
+
async beforeMaterializeEntry() {
|
|
84
|
+
this.markWorkspaceMutated();
|
|
85
|
+
}
|
|
86
|
+
async beforeApplyManifest() {
|
|
87
|
+
this.markWorkspaceMutated();
|
|
88
|
+
}
|
|
89
|
+
runningWorkdir() {
|
|
90
|
+
return '/';
|
|
91
|
+
}
|
|
92
|
+
exposedPortSource() {
|
|
93
|
+
return 'domain';
|
|
94
|
+
}
|
|
95
|
+
async resolveRemoteExposedPort(requestedPort) {
|
|
96
|
+
if (!this.sandbox.domain) {
|
|
97
|
+
throw new sandbox_1.SandboxProviderError('VercelSandboxClient exposed port resolution requires @vercel/sandbox domain(port) support.', {
|
|
98
|
+
provider: 'vercel',
|
|
99
|
+
port: requestedPort,
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
try {
|
|
103
|
+
return this.sandbox.domain(requestedPort);
|
|
104
|
+
}
|
|
105
|
+
catch (error) {
|
|
106
|
+
throw new sandbox_1.SandboxProviderError(`VercelSandboxClient failed to resolve exposed port ${requestedPort}.`, {
|
|
107
|
+
provider: 'vercel',
|
|
108
|
+
port: requestedPort,
|
|
109
|
+
cause: error instanceof Error ? error.message : String(error),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
async materializeInitialManifest(manifest) {
|
|
114
|
+
this.markWorkspaceMutated();
|
|
115
|
+
await this.materializeManifestEntries(manifest);
|
|
116
|
+
}
|
|
117
|
+
async prepareWorkspaceRoot() {
|
|
118
|
+
this.markWorkspaceMutated();
|
|
119
|
+
await this.ensureDir(this.state.manifest.root);
|
|
120
|
+
}
|
|
121
|
+
async persistWorkspace() {
|
|
122
|
+
if (this.state.workspacePersistence === 'snapshot') {
|
|
123
|
+
await captureVercelSnapshot(this.state, {
|
|
124
|
+
sandbox: this.sandbox,
|
|
125
|
+
});
|
|
126
|
+
const snapshotId = this.state.snapshotId;
|
|
127
|
+
if (!snapshotId) {
|
|
128
|
+
throw new sandbox_1.SandboxProviderError('Vercel snapshot persistence did not produce a snapshot id.', {
|
|
129
|
+
provider: 'vercel',
|
|
130
|
+
sandboxId: this.state.sandboxId,
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
try {
|
|
134
|
+
await this.replaceSandboxFromSnapshot(snapshotId, {
|
|
135
|
+
snapshotFreshAfterRestore: true,
|
|
136
|
+
ignorePreviousStopFailure: true,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
await this.recoverSandboxAfterSnapshotRestoreFailure(snapshotId, error);
|
|
141
|
+
}
|
|
142
|
+
return (0, shared_1.encodeNativeSnapshotRef)({
|
|
143
|
+
provider: 'vercel',
|
|
144
|
+
snapshotId,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
return await this.persistWorkspaceTar();
|
|
148
|
+
}
|
|
149
|
+
async hydrateWorkspace(data) {
|
|
150
|
+
this.markWorkspaceMutated();
|
|
151
|
+
const snapshotRef = this.state.workspacePersistence === 'snapshot'
|
|
152
|
+
? (0, shared_1.decodeNativeSnapshotRef)(data)
|
|
153
|
+
: undefined;
|
|
154
|
+
if (snapshotRef?.provider === 'vercel') {
|
|
155
|
+
await this.replaceSandboxFromSnapshot(snapshotRef.snapshotId);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
await this.hydrateWorkspaceTar(data);
|
|
159
|
+
this.resetKnownDirs();
|
|
160
|
+
this.knownDirs.add(this.state.manifest.root);
|
|
161
|
+
}
|
|
162
|
+
async close() {
|
|
163
|
+
if (this.closeCompleted) {
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
this.closePromise ??= this.closeOnce().catch((error) => {
|
|
167
|
+
if (!this.closeCompleted) {
|
|
168
|
+
this.closePromise = undefined;
|
|
169
|
+
}
|
|
170
|
+
throw error;
|
|
171
|
+
});
|
|
172
|
+
await this.closePromise;
|
|
173
|
+
}
|
|
174
|
+
async closeOnce() {
|
|
175
|
+
let snapshotError;
|
|
176
|
+
let snapshotCapturedBeforeStop = false;
|
|
177
|
+
if (this.state.workspacePersistence === 'snapshot' &&
|
|
178
|
+
this.sandbox.snapshot &&
|
|
179
|
+
this.state.snapshotSandboxId !== this.sandbox.sandboxId) {
|
|
180
|
+
try {
|
|
181
|
+
await captureVercelSnapshot(this.state, {
|
|
182
|
+
sandbox: this.sandbox,
|
|
183
|
+
});
|
|
184
|
+
snapshotCapturedBeforeStop = true;
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
snapshotError = error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
try {
|
|
191
|
+
await stopVercelSandbox(this.sandbox);
|
|
192
|
+
this.closeCompleted = true;
|
|
193
|
+
}
|
|
194
|
+
catch (stopError) {
|
|
195
|
+
if (snapshotError) {
|
|
196
|
+
throw new agents_core_1.UserError(`Failed to capture a Vercel sandbox snapshot and stop the sandbox. Snapshot error: ${errorMessage(snapshotError)} Stop error: ${errorMessage(stopError)}`);
|
|
197
|
+
}
|
|
198
|
+
if (snapshotCapturedBeforeStop) {
|
|
199
|
+
this.closeCompleted = true;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
throw stopError;
|
|
203
|
+
}
|
|
204
|
+
if (snapshotError) {
|
|
205
|
+
throw snapshotError;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
async shutdown() {
|
|
209
|
+
await this.close();
|
|
210
|
+
}
|
|
211
|
+
async delete() {
|
|
212
|
+
await this.close();
|
|
213
|
+
}
|
|
214
|
+
async execShell(command, cwd, sudo) {
|
|
215
|
+
const result = await this.sandbox.runCommand({
|
|
216
|
+
cmd: '/bin/sh',
|
|
217
|
+
args: ['-lc', command],
|
|
218
|
+
cwd,
|
|
219
|
+
env: this.state.environment,
|
|
220
|
+
...(sudo ? { sudo: true } : {}),
|
|
221
|
+
});
|
|
222
|
+
return {
|
|
223
|
+
exitCode: result.exitCode ?? 1,
|
|
224
|
+
output: await result.output('both'),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
async replaceSandboxFromSnapshot(snapshotId, options = {}) {
|
|
228
|
+
const previousSandbox = this.sandbox;
|
|
229
|
+
const credentials = await this.resolveSnapshotCredentials();
|
|
230
|
+
const sandbox = await this.createAndPrepareSandboxFromSnapshot(snapshotId, credentials);
|
|
231
|
+
try {
|
|
232
|
+
await stopVercelSandbox(previousSandbox);
|
|
233
|
+
}
|
|
234
|
+
catch (error) {
|
|
235
|
+
if (options.ignorePreviousStopFailure &&
|
|
236
|
+
isVercelSandboxAlreadyStoppedError(error)) {
|
|
237
|
+
this.bindRestoredSandbox(sandbox, snapshotId, options.snapshotFreshAfterRestore);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
let replacementStopCause;
|
|
241
|
+
try {
|
|
242
|
+
await stopVercelSandbox(sandbox);
|
|
243
|
+
}
|
|
244
|
+
catch (replacementStopError) {
|
|
245
|
+
replacementStopCause = errorMessage(replacementStopError);
|
|
246
|
+
}
|
|
247
|
+
throw new sandbox_1.SandboxProviderError('Vercel snapshot restore created a replacement sandbox, but stopping the previous sandbox failed.', {
|
|
248
|
+
provider: 'vercel',
|
|
249
|
+
sandboxId: previousSandbox.sandboxId,
|
|
250
|
+
replacementSandboxId: sandbox.sandboxId,
|
|
251
|
+
cause: errorMessage(error),
|
|
252
|
+
...(replacementStopCause ? { replacementStopCause } : {}),
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
this.bindRestoredSandbox(sandbox, snapshotId, options.snapshotFreshAfterRestore);
|
|
256
|
+
}
|
|
257
|
+
async recoverSandboxAfterSnapshotRestoreFailure(snapshotId, restoreError) {
|
|
258
|
+
try {
|
|
259
|
+
await this.replaceSandboxFromSnapshot(snapshotId, {
|
|
260
|
+
snapshotFreshAfterRestore: true,
|
|
261
|
+
ignorePreviousStopFailure: true,
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
catch (recoveryError) {
|
|
265
|
+
throw new sandbox_1.SandboxProviderError('Vercel snapshot persistence captured a snapshot, but restoring the live session failed and recovery also failed.', {
|
|
266
|
+
provider: 'vercel',
|
|
267
|
+
sandboxId: this.state.sandboxId,
|
|
268
|
+
snapshotId,
|
|
269
|
+
cause: errorMessage(restoreError),
|
|
270
|
+
recoveryCause: errorMessage(recoveryError),
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async resolveSnapshotCredentials() {
|
|
275
|
+
const credentials = await resolveVercelCredentials({
|
|
276
|
+
...this.credentials,
|
|
277
|
+
projectId: this.state.projectId ?? this.credentials.projectId,
|
|
278
|
+
teamId: this.state.teamId ?? this.credentials.teamId,
|
|
279
|
+
token: this.state.token ?? this.credentials.token,
|
|
280
|
+
});
|
|
281
|
+
applyResolvedVercelCredentials(this.state, credentials);
|
|
282
|
+
return credentials;
|
|
283
|
+
}
|
|
284
|
+
async createAndPrepareSandboxFromSnapshot(snapshotId, credentials) {
|
|
285
|
+
const sandbox = await this.createSandboxFromSnapshot(snapshotId, credentials);
|
|
286
|
+
const replacementSession = new VercelSandboxSession({
|
|
287
|
+
credentials: { ...this.credentials, ...credentials },
|
|
288
|
+
sandbox,
|
|
289
|
+
state: {
|
|
290
|
+
...this.state,
|
|
291
|
+
sandboxId: sandbox.sandboxId,
|
|
292
|
+
snapshotId,
|
|
293
|
+
snapshotSandboxId: undefined,
|
|
294
|
+
snapshotSupported: supportsVercelSnapshot(sandbox),
|
|
295
|
+
exposedPorts: undefined,
|
|
296
|
+
},
|
|
297
|
+
});
|
|
298
|
+
try {
|
|
299
|
+
await waitForVercelSandboxRunning(replacementSession);
|
|
300
|
+
await replacementSession.prepareWorkspaceRoot();
|
|
301
|
+
}
|
|
302
|
+
catch (error) {
|
|
303
|
+
try {
|
|
304
|
+
await stopVercelSandbox(sandbox);
|
|
305
|
+
}
|
|
306
|
+
catch (stopError) {
|
|
307
|
+
throw new agents_core_1.UserError(`Failed to restore a Vercel sandbox from snapshot and stop the replacement sandbox. Restore error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
|
|
308
|
+
}
|
|
309
|
+
throw error;
|
|
310
|
+
}
|
|
311
|
+
return sandbox;
|
|
312
|
+
}
|
|
313
|
+
async createSandboxFromSnapshot(snapshotId, credentials) {
|
|
314
|
+
const Sandbox = await loadVercelSandboxClass();
|
|
315
|
+
return await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'restore snapshot', async () => await Sandbox.create({
|
|
316
|
+
...credentials,
|
|
317
|
+
source: {
|
|
318
|
+
type: 'snapshot',
|
|
319
|
+
snapshotId,
|
|
320
|
+
},
|
|
321
|
+
...(this.state.runtime ? { runtime: this.state.runtime } : {}),
|
|
322
|
+
...(this.state.resources ? { resources: this.state.resources } : {}),
|
|
323
|
+
...(this.state.configuredExposedPorts
|
|
324
|
+
? { ports: this.state.configuredExposedPorts }
|
|
325
|
+
: {}),
|
|
326
|
+
...(typeof this.state.interactive === 'boolean'
|
|
327
|
+
? { interactive: this.state.interactive }
|
|
328
|
+
: {}),
|
|
329
|
+
...(this.state.networkPolicy
|
|
330
|
+
? { networkPolicy: this.state.networkPolicy }
|
|
331
|
+
: {}),
|
|
332
|
+
...(typeof this.state.timeoutMs === 'number'
|
|
333
|
+
? { timeout: this.state.timeoutMs }
|
|
334
|
+
: {}),
|
|
335
|
+
env: this.state.environment,
|
|
336
|
+
}), { snapshotId });
|
|
337
|
+
}
|
|
338
|
+
bindRestoredSandbox(sandbox, snapshotId, snapshotFreshAfterRestore) {
|
|
339
|
+
this.sandbox = sandbox;
|
|
340
|
+
this.resetKnownDirs();
|
|
341
|
+
this.knownDirs.add(this.state.manifest.root);
|
|
342
|
+
this.state.sandboxId = sandbox.sandboxId;
|
|
343
|
+
this.state.snapshotId = snapshotId;
|
|
344
|
+
this.state.snapshotSandboxId = snapshotFreshAfterRestore
|
|
345
|
+
? sandbox.sandboxId
|
|
346
|
+
: undefined;
|
|
347
|
+
this.state.snapshotSupported = supportsVercelSnapshot(sandbox);
|
|
348
|
+
this.clearExposedPortCache();
|
|
349
|
+
}
|
|
350
|
+
resetKnownDirs() {
|
|
351
|
+
this.knownDirs.clear();
|
|
352
|
+
this.pendingDirCreates.clear();
|
|
353
|
+
this.knownDirs.add(DEFAULT_VERCEL_WORKSPACE_ROOT);
|
|
354
|
+
}
|
|
355
|
+
markWorkspaceMutated() {
|
|
356
|
+
if (this.state.workspacePersistence === 'snapshot') {
|
|
357
|
+
this.state.snapshotSandboxId = undefined;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
clearExposedPortCache() {
|
|
361
|
+
this.state.exposedPorts = undefined;
|
|
362
|
+
}
|
|
363
|
+
async ensureDir(path) {
|
|
364
|
+
if (path === '/' || path === '.' || this.knownDirs.has(path)) {
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
const pending = this.pendingDirCreates.get(path);
|
|
368
|
+
if (pending) {
|
|
369
|
+
await pending;
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const create = (async () => {
|
|
373
|
+
const parent = (0, shared_1.posixDirname)(path);
|
|
374
|
+
if (parent !== path && parent !== '/' && parent !== '.') {
|
|
375
|
+
await this.ensureDir(parent);
|
|
376
|
+
}
|
|
377
|
+
try {
|
|
378
|
+
await this.sandbox.mkDir(path);
|
|
379
|
+
}
|
|
380
|
+
catch (error) {
|
|
381
|
+
if (!isVercelAlreadyExistsError(error)) {
|
|
382
|
+
throw error;
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
this.knownDirs.add(path);
|
|
386
|
+
})();
|
|
387
|
+
this.pendingDirCreates.set(path, create);
|
|
388
|
+
try {
|
|
389
|
+
await create;
|
|
390
|
+
}
|
|
391
|
+
finally {
|
|
392
|
+
this.pendingDirCreates.delete(path);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
async runRemoteCommand(command, options) {
|
|
396
|
+
const result = await this.execShell(command, options.workdir, undefined);
|
|
397
|
+
return {
|
|
398
|
+
status: result.exitCode,
|
|
399
|
+
stdout: result.output,
|
|
400
|
+
stderr: '',
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
async mkdirRemote(path) {
|
|
404
|
+
await this.ensureDir(path);
|
|
405
|
+
}
|
|
406
|
+
async readRemoteText(path) {
|
|
407
|
+
return new TextDecoder().decode(await this.readRemoteFile(path));
|
|
408
|
+
}
|
|
409
|
+
async readRemoteFile(path) {
|
|
410
|
+
const bytes = await this.sandbox.readFileToBuffer({ path });
|
|
411
|
+
if (!bytes) {
|
|
412
|
+
throw new agents_core_1.UserError(`Sandbox path not found: ${path}`);
|
|
413
|
+
}
|
|
414
|
+
return await (0, shared_1.toUint8Array)(bytes);
|
|
415
|
+
}
|
|
416
|
+
async writeRemoteFile(path, content) {
|
|
417
|
+
await this.sandbox.writeFiles([
|
|
418
|
+
{
|
|
419
|
+
path,
|
|
420
|
+
content,
|
|
421
|
+
},
|
|
422
|
+
]);
|
|
423
|
+
}
|
|
424
|
+
async deleteRemotePath(path) {
|
|
425
|
+
const result = await this.runRemoteCommand(`rm -f -- ${(0, shared_1.shellQuote)(path)}`, {
|
|
426
|
+
kind: 'manifest',
|
|
427
|
+
workdir: this.state.manifest.root,
|
|
428
|
+
});
|
|
429
|
+
if (result.status !== 0) {
|
|
430
|
+
throw new sandbox_1.SandboxProviderError('VercelSandboxClient failed to delete path.', {
|
|
431
|
+
provider: 'vercel',
|
|
432
|
+
operation: 'delete path',
|
|
433
|
+
sandboxId: this.state.sandboxId,
|
|
434
|
+
path,
|
|
435
|
+
exitCode: result.status,
|
|
436
|
+
output: result.stdout ?? '',
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
exports.VercelSandboxSession = VercelSandboxSession;
|
|
442
|
+
/**
|
|
443
|
+
* @see {@link https://vercel.com/docs/vercel-sandbox | Vercel Sandbox overview}.
|
|
444
|
+
* @see {@link https://vercel.com/docs/vercel-sandbox/sdk-reference | Sandbox SDK reference}.
|
|
445
|
+
* @see {@link https://vercel.com/docs/vercel-sandbox/working-with-sandbox | Working with Sandbox examples}.
|
|
446
|
+
*/
|
|
447
|
+
class VercelSandboxClient {
|
|
448
|
+
backendId = 'vercel';
|
|
449
|
+
options;
|
|
450
|
+
constructor(options = {}) {
|
|
451
|
+
this.options = options;
|
|
452
|
+
}
|
|
453
|
+
async create(args, manifestOptions) {
|
|
454
|
+
const createArgs = (0, sandbox_1.normalizeSandboxClientCreateArgs)(args, manifestOptions);
|
|
455
|
+
(0, shared_1.assertCoreSnapshotUnsupported)('VercelSandboxClient', createArgs.snapshot);
|
|
456
|
+
const manifest = createArgs.manifest;
|
|
457
|
+
const resolvedOptions = {
|
|
458
|
+
...this.options,
|
|
459
|
+
...createArgs.options,
|
|
460
|
+
};
|
|
461
|
+
const resolvedManifest = resolveManifestRoot(manifest);
|
|
462
|
+
(0, shared_1.assertSandboxManifestMetadataSupported)('VercelSandboxClient', resolvedManifest);
|
|
463
|
+
return await (0, shared_1.withSandboxSpan)('sandbox.start', {
|
|
464
|
+
backend_id: this.backendId,
|
|
465
|
+
}, async () => {
|
|
466
|
+
const Sandbox = await loadVercelSandboxClass();
|
|
467
|
+
const environment = await (0, shared_1.materializeEnvironment)(resolvedManifest, resolvedOptions.env);
|
|
468
|
+
const credentials = await resolveVercelCredentials(resolvedOptions);
|
|
469
|
+
const sandbox = await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'create sandbox', async () => await Sandbox.create({
|
|
470
|
+
...credentials,
|
|
471
|
+
...(resolvedOptions.runtime
|
|
472
|
+
? { runtime: resolvedOptions.runtime }
|
|
473
|
+
: {}),
|
|
474
|
+
...(resolvedOptions.resources
|
|
475
|
+
? { resources: resolvedOptions.resources }
|
|
476
|
+
: {}),
|
|
477
|
+
...(resolvedOptions.exposedPorts
|
|
478
|
+
? { ports: resolvedOptions.exposedPorts }
|
|
479
|
+
: {}),
|
|
480
|
+
...(typeof resolvedOptions.interactive === 'boolean'
|
|
481
|
+
? { interactive: resolvedOptions.interactive }
|
|
482
|
+
: {}),
|
|
483
|
+
...(resolvedOptions.networkPolicy
|
|
484
|
+
? { networkPolicy: resolvedOptions.networkPolicy }
|
|
485
|
+
: {}),
|
|
486
|
+
...(typeof resolvedOptions.timeoutMs === 'number'
|
|
487
|
+
? { timeout: resolvedOptions.timeoutMs }
|
|
488
|
+
: {}),
|
|
489
|
+
env: environment,
|
|
490
|
+
}), { runtime: resolvedOptions.runtime });
|
|
491
|
+
const session = new VercelSandboxSession({
|
|
492
|
+
sandbox,
|
|
493
|
+
credentials: { ...resolvedOptions, ...credentials },
|
|
494
|
+
concurrencyLimits: createArgs.concurrencyLimits,
|
|
495
|
+
state: {
|
|
496
|
+
manifest: resolvedManifest,
|
|
497
|
+
sandboxId: sandbox.sandboxId,
|
|
498
|
+
projectId: resolvedOptions.projectId ?? credentials.projectId,
|
|
499
|
+
teamId: resolvedOptions.teamId ?? credentials.teamId,
|
|
500
|
+
token: credentials.token,
|
|
501
|
+
runtime: resolvedOptions.runtime,
|
|
502
|
+
resources: resolvedOptions.resources,
|
|
503
|
+
configuredExposedPorts: resolvedOptions.exposedPorts,
|
|
504
|
+
interactive: resolvedOptions.interactive,
|
|
505
|
+
networkPolicy: resolvedOptions.networkPolicy,
|
|
506
|
+
timeoutMs: resolvedOptions.timeoutMs,
|
|
507
|
+
workspacePersistence: resolvedOptions.workspacePersistence ?? 'tar',
|
|
508
|
+
snapshotExpirationMs: resolvedOptions.snapshotExpirationMs,
|
|
509
|
+
environment,
|
|
510
|
+
snapshotSupported: supportsVercelSnapshot(sandbox),
|
|
511
|
+
},
|
|
512
|
+
});
|
|
513
|
+
try {
|
|
514
|
+
await waitForVercelSandboxRunning(session);
|
|
515
|
+
await session.prepareWorkspaceRoot();
|
|
516
|
+
await session.materializeInitialManifest(resolvedManifest);
|
|
517
|
+
}
|
|
518
|
+
catch (error) {
|
|
519
|
+
try {
|
|
520
|
+
await stopVercelSandbox(sandbox);
|
|
521
|
+
}
|
|
522
|
+
catch (stopError) {
|
|
523
|
+
throw new agents_core_1.UserError(`Failed to apply a Vercel sandbox manifest and stop the sandbox. Manifest error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
|
|
524
|
+
}
|
|
525
|
+
throw error;
|
|
526
|
+
}
|
|
527
|
+
return session;
|
|
528
|
+
});
|
|
529
|
+
}
|
|
530
|
+
async serializeSessionState(state, options) {
|
|
531
|
+
if (state.workspacePersistence === 'snapshot' &&
|
|
532
|
+
state.snapshotSupported !== false &&
|
|
533
|
+
state.snapshotSandboxId !== state.sandboxId &&
|
|
534
|
+
(options?.reuseLiveSession === false || options?.willCloseAfterSerialize)) {
|
|
535
|
+
await captureVercelSnapshot(state, {
|
|
536
|
+
options: {
|
|
537
|
+
...this.options,
|
|
538
|
+
projectId: state.projectId ?? this.options.projectId,
|
|
539
|
+
teamId: state.teamId ?? this.options.teamId,
|
|
540
|
+
token: state.token ?? this.options.token,
|
|
541
|
+
},
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
return (0, shared_1.serializeRemoteSandboxSessionState)(state);
|
|
545
|
+
}
|
|
546
|
+
canPersistOwnedSessionState(state) {
|
|
547
|
+
return (state.workspacePersistence === 'snapshot' &&
|
|
548
|
+
state.snapshotSupported !== false);
|
|
549
|
+
}
|
|
550
|
+
canReusePreservedOwnedSession(state) {
|
|
551
|
+
return (state.workspacePersistence !== 'snapshot' ||
|
|
552
|
+
state.snapshotSupported === false);
|
|
553
|
+
}
|
|
554
|
+
async deserializeSessionState(state) {
|
|
555
|
+
const baseState = (0, shared_1.deserializeRemoteSandboxSessionStateValues)(state, this.options.env);
|
|
556
|
+
const manifest = resolveManifestRoot(baseState.manifest);
|
|
557
|
+
(0, shared_1.assertSandboxManifestMetadataSupported)('VercelSandboxClient', manifest);
|
|
558
|
+
return {
|
|
559
|
+
...state,
|
|
560
|
+
...baseState,
|
|
561
|
+
manifest,
|
|
562
|
+
sandboxId: (0, shared_1.readString)(state, 'sandboxId'),
|
|
563
|
+
workspacePersistence: state.workspacePersistence ?? 'tar',
|
|
564
|
+
projectId: (0, shared_1.readOptionalString)(state, 'projectId'),
|
|
565
|
+
teamId: (0, shared_1.readOptionalString)(state, 'teamId'),
|
|
566
|
+
token: (0, shared_1.readOptionalString)(state, 'token'),
|
|
567
|
+
runtime: (0, shared_1.readOptionalString)(state, 'runtime'),
|
|
568
|
+
resources: (0, shared_1.readOptionalRecord)(state.resources),
|
|
569
|
+
configuredExposedPorts: (0, shared_1.readOptionalNumberArray)(state.configuredExposedPorts),
|
|
570
|
+
interactive: (0, shared_1.readOptionalBoolean)(state, 'interactive'),
|
|
571
|
+
networkPolicy: (0, shared_1.readOptionalRecord)(state.networkPolicy),
|
|
572
|
+
timeoutMs: (0, shared_1.readOptionalNumber)(state, 'timeoutMs'),
|
|
573
|
+
snapshotExpirationMs: (0, shared_1.readOptionalNumber)(state, 'snapshotExpirationMs'),
|
|
574
|
+
snapshotId: (0, shared_1.readOptionalString)(state, 'snapshotId'),
|
|
575
|
+
snapshotSandboxId: (0, shared_1.readOptionalString)(state, 'snapshotSandboxId'),
|
|
576
|
+
snapshotSupported: (0, shared_1.readOptionalBoolean)(state, 'snapshotSupported'),
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
async resume(state) {
|
|
580
|
+
const Sandbox = await loadVercelSandboxClass();
|
|
581
|
+
const credentials = await resolveVercelCredentials({
|
|
582
|
+
...this.options,
|
|
583
|
+
projectId: state.projectId ?? this.options.projectId,
|
|
584
|
+
teamId: state.teamId ?? this.options.teamId,
|
|
585
|
+
token: state.token ?? this.options.token,
|
|
586
|
+
});
|
|
587
|
+
applyResolvedVercelCredentials(state, credentials);
|
|
588
|
+
const resumeFromSnapshot = hasFreshVercelSnapshot(state);
|
|
589
|
+
const sandbox = resumeFromSnapshot
|
|
590
|
+
? await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'resume sandbox from snapshot', async () => await Sandbox.create({
|
|
591
|
+
...credentials,
|
|
592
|
+
source: {
|
|
593
|
+
type: 'snapshot',
|
|
594
|
+
snapshotId: state.snapshotId,
|
|
595
|
+
},
|
|
596
|
+
...(state.runtime ? { runtime: state.runtime } : {}),
|
|
597
|
+
...(state.resources ? { resources: state.resources } : {}),
|
|
598
|
+
...(state.configuredExposedPorts
|
|
599
|
+
? { ports: state.configuredExposedPorts }
|
|
600
|
+
: {}),
|
|
601
|
+
...(state.interactive !== undefined
|
|
602
|
+
? { interactive: state.interactive }
|
|
603
|
+
: {}),
|
|
604
|
+
...(state.networkPolicy
|
|
605
|
+
? { networkPolicy: state.networkPolicy }
|
|
606
|
+
: {}),
|
|
607
|
+
...(state.timeoutMs !== undefined
|
|
608
|
+
? { timeout: state.timeoutMs }
|
|
609
|
+
: {}),
|
|
610
|
+
env: state.environment,
|
|
611
|
+
}), { snapshotId: state.snapshotId, sandboxId: state.sandboxId })
|
|
612
|
+
: await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'resume sandbox', async () => await Sandbox.get({
|
|
613
|
+
sandboxId: state.sandboxId,
|
|
614
|
+
...credentials,
|
|
615
|
+
}), { sandboxId: state.sandboxId });
|
|
616
|
+
const session = new VercelSandboxSession({
|
|
617
|
+
credentials,
|
|
618
|
+
state: resumeFromSnapshot
|
|
619
|
+
? {
|
|
620
|
+
...state,
|
|
621
|
+
sandboxId: sandbox.sandboxId,
|
|
622
|
+
snapshotSandboxId: undefined,
|
|
623
|
+
snapshotSupported: supportsVercelSnapshot(sandbox),
|
|
624
|
+
exposedPorts: undefined,
|
|
625
|
+
}
|
|
626
|
+
: {
|
|
627
|
+
...state,
|
|
628
|
+
snapshotSupported: supportsVercelSnapshot(sandbox),
|
|
629
|
+
},
|
|
630
|
+
sandbox,
|
|
631
|
+
});
|
|
632
|
+
try {
|
|
633
|
+
await waitForVercelSandboxRunning(session);
|
|
634
|
+
await session.prepareWorkspaceRoot();
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
if (!resumeFromSnapshot) {
|
|
638
|
+
throw error;
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
await stopVercelSandbox(sandbox);
|
|
642
|
+
}
|
|
643
|
+
catch (stopError) {
|
|
644
|
+
throw new agents_core_1.UserError(`Failed to resume a Vercel sandbox from snapshot and stop the replacement sandbox. Resume error: ${errorMessage(error)} Stop error: ${errorMessage(stopError)}`);
|
|
645
|
+
}
|
|
646
|
+
throw error;
|
|
647
|
+
}
|
|
648
|
+
return session;
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
exports.VercelSandboxClient = VercelSandboxClient;
|
|
652
|
+
async function loadVercelSandboxClass() {
|
|
653
|
+
try {
|
|
654
|
+
const { Sandbox } = await Promise.resolve().then(() => __importStar(require('@vercel/sandbox')));
|
|
655
|
+
if (!Sandbox) {
|
|
656
|
+
throw new Error('Missing Sandbox export from @vercel/sandbox.');
|
|
657
|
+
}
|
|
658
|
+
return adaptVercelSandboxClass(Sandbox);
|
|
659
|
+
}
|
|
660
|
+
catch (error) {
|
|
661
|
+
throw new agents_core_1.UserError(`Vercel sandbox support requires the optional \`@vercel/sandbox\` package. Install it before using Vercel-backed sandbox examples. ${error.message}`);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
function adaptVercelSandboxClass(Sandbox) {
|
|
665
|
+
return {
|
|
666
|
+
create: async (params) => adaptVercelSandbox(await Sandbox.create(params)),
|
|
667
|
+
get: async (params) => adaptVercelSandbox(await Sandbox.get(params)),
|
|
668
|
+
};
|
|
669
|
+
}
|
|
670
|
+
function adaptVercelSandbox(sandbox) {
|
|
671
|
+
const optionalSandbox = sandbox;
|
|
672
|
+
const adapted = {
|
|
673
|
+
sandboxId: sandbox.sandboxId,
|
|
674
|
+
runCommand: async (params) => adaptVercelCommandFinished(await sandbox.runCommand(params)),
|
|
675
|
+
mkDir: async (path) => await sandbox.mkDir(path),
|
|
676
|
+
readFileToBuffer: async (file) => await sandbox.readFileToBuffer(file),
|
|
677
|
+
writeFiles: async (files) => await sandbox.writeFiles(files),
|
|
678
|
+
};
|
|
679
|
+
if (typeof optionalSandbox.domain === 'function') {
|
|
680
|
+
const domain = optionalSandbox.domain.bind(sandbox);
|
|
681
|
+
adapted.domain = (port) => domain(port);
|
|
682
|
+
}
|
|
683
|
+
if (typeof optionalSandbox.stop === 'function') {
|
|
684
|
+
const stop = optionalSandbox.stop.bind(sandbox);
|
|
685
|
+
adapted.stop = async () => await stop();
|
|
686
|
+
}
|
|
687
|
+
if (typeof optionalSandbox.snapshot === 'function') {
|
|
688
|
+
const snapshotFn = optionalSandbox.snapshot.bind(sandbox);
|
|
689
|
+
adapted.snapshot = async (params) => {
|
|
690
|
+
const snapshot = await snapshotFn(params);
|
|
691
|
+
return { snapshotId: snapshot.snapshotId };
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
return adapted;
|
|
695
|
+
}
|
|
696
|
+
function adaptVercelCommandFinished(command) {
|
|
697
|
+
return {
|
|
698
|
+
exitCode: command.exitCode,
|
|
699
|
+
output: async (stream) => await command.output(stream),
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
function resolveManifestRoot(manifest) {
|
|
703
|
+
if (manifest.root === '/workspace') {
|
|
704
|
+
return (0, shared_1.cloneManifestWithRoot)(manifest, DEFAULT_VERCEL_WORKSPACE_ROOT);
|
|
705
|
+
}
|
|
706
|
+
if (manifest.root === DEFAULT_VERCEL_WORKSPACE_ROOT ||
|
|
707
|
+
manifest.root.startsWith(`${DEFAULT_VERCEL_WORKSPACE_ROOT}/`)) {
|
|
708
|
+
return manifest;
|
|
709
|
+
}
|
|
710
|
+
throw new agents_core_1.UserError(`Vercel sandboxes require manifest.root to stay within "${DEFAULT_VERCEL_WORKSPACE_ROOT}".`);
|
|
711
|
+
}
|
|
712
|
+
function pickVercelCredentials(options) {
|
|
713
|
+
const credentials = {};
|
|
714
|
+
if (options.projectId) {
|
|
715
|
+
credentials.projectId = options.projectId;
|
|
716
|
+
}
|
|
717
|
+
if (options.teamId) {
|
|
718
|
+
credentials.teamId = options.teamId;
|
|
719
|
+
}
|
|
720
|
+
if (options.token) {
|
|
721
|
+
credentials.token = options.token;
|
|
722
|
+
}
|
|
723
|
+
return credentials;
|
|
724
|
+
}
|
|
725
|
+
async function resolveVercelCredentials(options) {
|
|
726
|
+
const envOptions = {
|
|
727
|
+
projectId: process.env.VERCEL_PROJECT_ID,
|
|
728
|
+
teamId: process.env.VERCEL_TEAM_ID,
|
|
729
|
+
token: process.env.VERCEL_TOKEN,
|
|
730
|
+
};
|
|
731
|
+
const layeredCredentials = pickVercelCredentials({
|
|
732
|
+
projectId: options.projectId ?? envOptions.projectId,
|
|
733
|
+
teamId: options.teamId ?? envOptions.teamId,
|
|
734
|
+
token: options.token ?? envOptions.token,
|
|
735
|
+
});
|
|
736
|
+
if (layeredCredentials.token) {
|
|
737
|
+
const refreshedCredentials = await refreshLayeredVercelCliCredentials(layeredCredentials);
|
|
738
|
+
if (refreshedCredentials === null) {
|
|
739
|
+
const { token: _token, ...credentialsWithoutToken } = layeredCredentials;
|
|
740
|
+
void _token;
|
|
741
|
+
return credentialsWithoutToken;
|
|
742
|
+
}
|
|
743
|
+
return refreshedCredentials ?? layeredCredentials;
|
|
744
|
+
}
|
|
745
|
+
if (Object.keys(layeredCredentials).length > 0) {
|
|
746
|
+
const cliToken = await resolveVercelCliAuthToken();
|
|
747
|
+
if (cliToken) {
|
|
748
|
+
return {
|
|
749
|
+
...layeredCredentials,
|
|
750
|
+
token: cliToken,
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
return {};
|
|
754
|
+
}
|
|
755
|
+
if (hasAnyVercelCredentialOption(options)) {
|
|
756
|
+
return {};
|
|
757
|
+
}
|
|
758
|
+
return (await resolveVercelCliCredentials()) ?? {};
|
|
759
|
+
}
|
|
760
|
+
function hasAnyVercelCredentialOption(options) {
|
|
761
|
+
return Boolean(options.projectId || options.teamId || options.token);
|
|
762
|
+
}
|
|
763
|
+
async function resolveVercelCliCredentials() {
|
|
764
|
+
const token = await resolveVercelCliAuthToken();
|
|
765
|
+
if (!token) {
|
|
766
|
+
return undefined;
|
|
767
|
+
}
|
|
768
|
+
const linkedProject = findLinkedVercelProject();
|
|
769
|
+
if (!linkedProject) {
|
|
770
|
+
return { token };
|
|
771
|
+
}
|
|
772
|
+
return {
|
|
773
|
+
token,
|
|
774
|
+
projectId: linkedProject.projectId,
|
|
775
|
+
teamId: linkedProject.teamId,
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
async function resolveVercelCliAuthToken() {
|
|
779
|
+
const authModule = await loadVercelAuthModule();
|
|
780
|
+
if (!authModule) {
|
|
781
|
+
return undefined;
|
|
782
|
+
}
|
|
783
|
+
const auth = await resolveVercelCliAuth(authModule);
|
|
784
|
+
return auth?.token;
|
|
785
|
+
}
|
|
786
|
+
async function refreshLayeredVercelCliCredentials(credentials) {
|
|
787
|
+
if (!credentials.token) {
|
|
788
|
+
return undefined;
|
|
789
|
+
}
|
|
790
|
+
const authModule = await loadVercelAuthModule();
|
|
791
|
+
if (!authModule) {
|
|
792
|
+
return undefined;
|
|
793
|
+
}
|
|
794
|
+
const auth = authModule.getAuth();
|
|
795
|
+
if (!auth?.token || auth.token !== credentials.token) {
|
|
796
|
+
return undefined;
|
|
797
|
+
}
|
|
798
|
+
const resolvedAuth = await resolveVercelCliAuth(authModule, auth);
|
|
799
|
+
if (!resolvedAuth?.token) {
|
|
800
|
+
return null;
|
|
801
|
+
}
|
|
802
|
+
return {
|
|
803
|
+
...credentials,
|
|
804
|
+
token: resolvedAuth.token,
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
async function loadVercelAuthModule() {
|
|
808
|
+
if (process.env.NODE_ENV === 'test' && !process.env.VERCEL_AUTH_CONFIG_DIR) {
|
|
809
|
+
return undefined;
|
|
810
|
+
}
|
|
811
|
+
try {
|
|
812
|
+
return await Promise.resolve().then(() => __importStar(require('@vercel/sandbox/dist/auth/index.js')));
|
|
813
|
+
}
|
|
814
|
+
catch {
|
|
815
|
+
return undefined;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
async function resolveVercelCliAuth(authModule, initialAuth = authModule.getAuth()) {
|
|
819
|
+
let auth = initialAuth;
|
|
820
|
+
if (!auth?.token && !auth?.refreshToken) {
|
|
821
|
+
return undefined;
|
|
822
|
+
}
|
|
823
|
+
if (auth?.expiresAt && auth.expiresAt.getTime() <= Date.now()) {
|
|
824
|
+
if (!auth.refreshToken) {
|
|
825
|
+
return undefined;
|
|
826
|
+
}
|
|
827
|
+
const refreshed = await (await authModule.OAuth()).refreshToken(auth.refreshToken);
|
|
828
|
+
auth = {
|
|
829
|
+
expiresAt: new Date(Date.now() + refreshed.expires_in * 1_000),
|
|
830
|
+
token: refreshed.access_token,
|
|
831
|
+
refreshToken: refreshed.refresh_token ?? auth.refreshToken,
|
|
832
|
+
};
|
|
833
|
+
try {
|
|
834
|
+
authModule.updateAuthConfig(auth);
|
|
835
|
+
}
|
|
836
|
+
catch {
|
|
837
|
+
// The refreshed token is still usable for this process.
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
return auth ?? undefined;
|
|
841
|
+
}
|
|
842
|
+
function applyResolvedVercelCredentials(state, credentials) {
|
|
843
|
+
if (credentials.projectId) {
|
|
844
|
+
state.projectId = credentials.projectId;
|
|
845
|
+
}
|
|
846
|
+
if (credentials.teamId) {
|
|
847
|
+
state.teamId = credentials.teamId;
|
|
848
|
+
}
|
|
849
|
+
if (credentials.token) {
|
|
850
|
+
state.token = credentials.token;
|
|
851
|
+
}
|
|
852
|
+
else {
|
|
853
|
+
delete state.token;
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
function findLinkedVercelProject() {
|
|
857
|
+
const candidateCwds = [
|
|
858
|
+
process.env.INIT_CWD,
|
|
859
|
+
process.env.PWD,
|
|
860
|
+
process.cwd(),
|
|
861
|
+
].filter((value) => Boolean(value));
|
|
862
|
+
for (const cwd of candidateCwds) {
|
|
863
|
+
const projectPath = findUpVercelProjectFile(cwd);
|
|
864
|
+
if (!projectPath) {
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
867
|
+
try {
|
|
868
|
+
const data = JSON.parse((0, node_fs_1.readFileSync)(projectPath, 'utf8'));
|
|
869
|
+
if (typeof data.projectId === 'string' &&
|
|
870
|
+
typeof data.orgId === 'string') {
|
|
871
|
+
return {
|
|
872
|
+
projectId: data.projectId,
|
|
873
|
+
teamId: data.orgId,
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
catch {
|
|
878
|
+
continue;
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
return undefined;
|
|
882
|
+
}
|
|
883
|
+
function findUpVercelProjectFile(startDir) {
|
|
884
|
+
let current = (0, node_path_1.resolve)(startDir);
|
|
885
|
+
while (true) {
|
|
886
|
+
const candidate = (0, node_path_1.join)(current, '.vercel', 'project.json');
|
|
887
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
888
|
+
return candidate;
|
|
889
|
+
}
|
|
890
|
+
const parent = (0, node_path_1.dirname)(current);
|
|
891
|
+
if (parent === current) {
|
|
892
|
+
return undefined;
|
|
893
|
+
}
|
|
894
|
+
current = parent;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
async function captureVercelSnapshot(state, args = {}) {
|
|
898
|
+
if (state.workspacePersistence !== 'snapshot') {
|
|
899
|
+
return;
|
|
900
|
+
}
|
|
901
|
+
let sandbox = args.sandbox;
|
|
902
|
+
if (!sandbox) {
|
|
903
|
+
const credentials = await resolveVercelCredentials({
|
|
904
|
+
projectId: state.projectId ?? args.options?.projectId,
|
|
905
|
+
teamId: state.teamId ?? args.options?.teamId,
|
|
906
|
+
token: state.token ?? args.options?.token,
|
|
907
|
+
});
|
|
908
|
+
applyResolvedVercelCredentials(state, credentials);
|
|
909
|
+
sandbox = await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'look up sandbox for snapshot', async () => await (await loadVercelSandboxClass()).get({
|
|
910
|
+
sandboxId: state.sandboxId,
|
|
911
|
+
...credentials,
|
|
912
|
+
}), { sandboxId: state.sandboxId });
|
|
913
|
+
}
|
|
914
|
+
state.snapshotSupported = supportsVercelSnapshot(sandbox);
|
|
915
|
+
if (!state.snapshotSupported) {
|
|
916
|
+
throw new agents_core_1.UserError('Vercel snapshot persistence requires @vercel/sandbox snapshot support.');
|
|
917
|
+
}
|
|
918
|
+
const snapshot = await (0, shared_1.withSandboxSpan)('sandbox.snapshot', {
|
|
919
|
+
backend_id: 'vercel',
|
|
920
|
+
sandbox_id: state.sandboxId,
|
|
921
|
+
}, async () => await (0, shared_1.withProviderError)('VercelSandboxClient', 'vercel', 'capture snapshot', async () => await sandbox.snapshot({
|
|
922
|
+
expiration: state.snapshotExpirationMs,
|
|
923
|
+
}), { sandboxId: state.sandboxId }));
|
|
924
|
+
if (!snapshot.snapshotId) {
|
|
925
|
+
throw new agents_core_1.UserError('Vercel snapshot persistence did not return a snapshotId.');
|
|
926
|
+
}
|
|
927
|
+
state.snapshotId = snapshot.snapshotId;
|
|
928
|
+
state.snapshotSandboxId = sandbox.sandboxId;
|
|
929
|
+
}
|
|
930
|
+
function supportsVercelSnapshot(sandbox) {
|
|
931
|
+
return typeof sandbox.snapshot === 'function';
|
|
932
|
+
}
|
|
933
|
+
function hasFreshVercelSnapshot(state) {
|
|
934
|
+
return Boolean(state.snapshotId && state.snapshotSandboxId === state.sandboxId);
|
|
935
|
+
}
|
|
936
|
+
async function stopVercelSandbox(sandbox) {
|
|
937
|
+
if (!sandbox.stop) {
|
|
938
|
+
return;
|
|
939
|
+
}
|
|
940
|
+
await (0, shared_1.withSandboxSpan)('sandbox.stop', {
|
|
941
|
+
backend_id: 'vercel',
|
|
942
|
+
sandbox_id: sandbox.sandboxId,
|
|
943
|
+
}, async () => {
|
|
944
|
+
await sandbox.stop();
|
|
945
|
+
});
|
|
946
|
+
}
|
|
947
|
+
async function waitForVercelSandboxRunning(session, timeoutMs = 30_000) {
|
|
948
|
+
const deadline = Date.now() + timeoutMs;
|
|
949
|
+
while (Date.now() <= deadline) {
|
|
950
|
+
if (await session.running()) {
|
|
951
|
+
return;
|
|
952
|
+
}
|
|
953
|
+
await new Promise((resolve) => setTimeout(resolve, 250));
|
|
954
|
+
}
|
|
955
|
+
throw new sandbox_1.SandboxLifecycleError(`Vercel sandbox ${session.state.sandboxId} did not become runnable within ${timeoutMs}ms.`, {
|
|
956
|
+
provider: 'vercel',
|
|
957
|
+
sandboxId: session.state.sandboxId,
|
|
958
|
+
timeoutMs,
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
function errorMessage(error) {
|
|
962
|
+
return error instanceof Error ? error.message : String(error);
|
|
963
|
+
}
|
|
964
|
+
function isVercelSandboxAlreadyStoppedError(error) {
|
|
965
|
+
if ((0, shared_1.isProviderSandboxNotFoundError)(error)) {
|
|
966
|
+
return true;
|
|
967
|
+
}
|
|
968
|
+
const message = errorMessage(error);
|
|
969
|
+
return (/\b(sandbox|sandbox instance|instance)\b.*\b(already\s+)?(stopped|terminated|not running)\b/iu.test(message) ||
|
|
970
|
+
/\b(already\s+)?(stopped|terminated|not running)\b.*\b(sandbox|sandbox instance|instance)\b/iu.test(message));
|
|
971
|
+
}
|
|
972
|
+
function assertFilesystemRunAs(runAs) {
|
|
973
|
+
if (runAs && runAs !== 'root') {
|
|
974
|
+
(0, shared_1.assertRunAsUnsupported)('VercelSandboxClient', runAs);
|
|
975
|
+
}
|
|
976
|
+
if (runAs === 'root') {
|
|
977
|
+
throw new sandbox_1.SandboxUnsupportedFeatureError('VercelSandboxClient does not support runAs for filesystem operations.', {
|
|
978
|
+
provider: 'vercel',
|
|
979
|
+
feature: 'runAs',
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function isVercelAlreadyExistsError(error) {
|
|
984
|
+
if (!error || typeof error !== 'object') {
|
|
985
|
+
return false;
|
|
986
|
+
}
|
|
987
|
+
const json = 'json' in error ? error.json : undefined;
|
|
988
|
+
if (!json || typeof json !== 'object') {
|
|
989
|
+
return false;
|
|
990
|
+
}
|
|
991
|
+
const payload = 'error' in json ? json.error : undefined;
|
|
992
|
+
if (!payload || typeof payload !== 'object') {
|
|
993
|
+
return false;
|
|
994
|
+
}
|
|
995
|
+
const code = 'code' in payload ? payload.code : undefined;
|
|
996
|
+
const message = 'message' in payload ? payload.message : undefined;
|
|
997
|
+
return (code === 'file_error' &&
|
|
998
|
+
typeof message === 'string' &&
|
|
999
|
+
message.includes('File exists'));
|
|
1000
|
+
}
|
|
1001
|
+
//# sourceMappingURL=sandbox.js.map
|