@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.
Files changed (213) hide show
  1. package/dist/metadata.js +2 -2
  2. package/dist/metadata.mjs +2 -2
  3. package/dist/sandbox/blaxel/index.d.ts +2 -0
  4. package/dist/sandbox/blaxel/index.js +19 -0
  5. package/dist/sandbox/blaxel/index.js.map +1 -0
  6. package/dist/sandbox/blaxel/index.mjs +3 -0
  7. package/dist/sandbox/blaxel/index.mjs.map +1 -0
  8. package/dist/sandbox/blaxel/mounts.d.ts +101 -0
  9. package/dist/sandbox/blaxel/mounts.js +542 -0
  10. package/dist/sandbox/blaxel/mounts.js.map +1 -0
  11. package/dist/sandbox/blaxel/mounts.mjs +529 -0
  12. package/dist/sandbox/blaxel/mounts.mjs.map +1 -0
  13. package/dist/sandbox/blaxel/sandbox.d.ts +155 -0
  14. package/dist/sandbox/blaxel/sandbox.js +1110 -0
  15. package/dist/sandbox/blaxel/sandbox.js.map +1 -0
  16. package/dist/sandbox/blaxel/sandbox.mjs +1072 -0
  17. package/dist/sandbox/blaxel/sandbox.mjs.map +1 -0
  18. package/dist/sandbox/cloudflare/index.d.ts +2 -0
  19. package/dist/sandbox/cloudflare/index.js +19 -0
  20. package/dist/sandbox/cloudflare/index.js.map +1 -0
  21. package/dist/sandbox/cloudflare/index.mjs +3 -0
  22. package/dist/sandbox/cloudflare/index.mjs.map +1 -0
  23. package/dist/sandbox/cloudflare/mounts.d.ts +28 -0
  24. package/dist/sandbox/cloudflare/mounts.js +150 -0
  25. package/dist/sandbox/cloudflare/mounts.js.map +1 -0
  26. package/dist/sandbox/cloudflare/mounts.mjs +143 -0
  27. package/dist/sandbox/cloudflare/mounts.mjs.map +1 -0
  28. package/dist/sandbox/cloudflare/sandbox.d.ts +91 -0
  29. package/dist/sandbox/cloudflare/sandbox.js +1163 -0
  30. package/dist/sandbox/cloudflare/sandbox.js.map +1 -0
  31. package/dist/sandbox/cloudflare/sandbox.mjs +1125 -0
  32. package/dist/sandbox/cloudflare/sandbox.mjs.map +1 -0
  33. package/dist/sandbox/daytona/index.d.ts +2 -0
  34. package/dist/sandbox/daytona/index.js +19 -0
  35. package/dist/sandbox/daytona/index.js.map +1 -0
  36. package/dist/sandbox/daytona/index.mjs +3 -0
  37. package/dist/sandbox/daytona/index.mjs.map +1 -0
  38. package/dist/sandbox/daytona/mounts.d.ts +11 -0
  39. package/dist/sandbox/daytona/mounts.js +17 -0
  40. package/dist/sandbox/daytona/mounts.js.map +1 -0
  41. package/dist/sandbox/daytona/mounts.mjs +12 -0
  42. package/dist/sandbox/daytona/mounts.mjs.map +1 -0
  43. package/dist/sandbox/daytona/sandbox.d.ts +160 -0
  44. package/dist/sandbox/daytona/sandbox.js +938 -0
  45. package/dist/sandbox/daytona/sandbox.js.map +1 -0
  46. package/dist/sandbox/daytona/sandbox.mjs +900 -0
  47. package/dist/sandbox/daytona/sandbox.mjs.map +1 -0
  48. package/dist/sandbox/e2b/index.d.ts +2 -0
  49. package/dist/sandbox/e2b/index.js +19 -0
  50. package/dist/sandbox/e2b/index.js.map +1 -0
  51. package/dist/sandbox/e2b/index.mjs +3 -0
  52. package/dist/sandbox/e2b/index.mjs.map +1 -0
  53. package/dist/sandbox/e2b/mounts.d.ts +11 -0
  54. package/dist/sandbox/e2b/mounts.js +17 -0
  55. package/dist/sandbox/e2b/mounts.js.map +1 -0
  56. package/dist/sandbox/e2b/mounts.mjs +12 -0
  57. package/dist/sandbox/e2b/mounts.mjs.map +1 -0
  58. package/dist/sandbox/e2b/sandbox.d.ts +169 -0
  59. package/dist/sandbox/e2b/sandbox.js +829 -0
  60. package/dist/sandbox/e2b/sandbox.js.map +1 -0
  61. package/dist/sandbox/e2b/sandbox.mjs +791 -0
  62. package/dist/sandbox/e2b/sandbox.mjs.map +1 -0
  63. package/dist/sandbox/modal/index.d.ts +2 -0
  64. package/dist/sandbox/modal/index.js +19 -0
  65. package/dist/sandbox/modal/index.js.map +1 -0
  66. package/dist/sandbox/modal/index.mjs +3 -0
  67. package/dist/sandbox/modal/index.mjs.map +1 -0
  68. package/dist/sandbox/modal/mounts.d.ts +24 -0
  69. package/dist/sandbox/modal/mounts.js +194 -0
  70. package/dist/sandbox/modal/mounts.js.map +1 -0
  71. package/dist/sandbox/modal/mounts.mjs +188 -0
  72. package/dist/sandbox/modal/mounts.mjs.map +1 -0
  73. package/dist/sandbox/modal/sandbox.d.ts +220 -0
  74. package/dist/sandbox/modal/sandbox.js +1621 -0
  75. package/dist/sandbox/modal/sandbox.js.map +1 -0
  76. package/dist/sandbox/modal/sandbox.mjs +1581 -0
  77. package/dist/sandbox/modal/sandbox.mjs.map +1 -0
  78. package/dist/sandbox/runloop/index.d.ts +2 -0
  79. package/dist/sandbox/runloop/index.js +19 -0
  80. package/dist/sandbox/runloop/index.js.map +1 -0
  81. package/dist/sandbox/runloop/index.mjs +3 -0
  82. package/dist/sandbox/runloop/index.mjs.map +1 -0
  83. package/dist/sandbox/runloop/mounts.d.ts +11 -0
  84. package/dist/sandbox/runloop/mounts.js +17 -0
  85. package/dist/sandbox/runloop/mounts.js.map +1 -0
  86. package/dist/sandbox/runloop/mounts.mjs +12 -0
  87. package/dist/sandbox/runloop/mounts.mjs.map +1 -0
  88. package/dist/sandbox/runloop/sandbox.d.ts +266 -0
  89. package/dist/sandbox/runloop/sandbox.js +1390 -0
  90. package/dist/sandbox/runloop/sandbox.js.map +1 -0
  91. package/dist/sandbox/runloop/sandbox.mjs +1346 -0
  92. package/dist/sandbox/runloop/sandbox.mjs.map +1 -0
  93. package/dist/sandbox/shared/archive.d.ts +34 -0
  94. package/dist/sandbox/shared/archive.js +397 -0
  95. package/dist/sandbox/shared/archive.js.map +1 -0
  96. package/dist/sandbox/shared/archive.mjs +389 -0
  97. package/dist/sandbox/shared/archive.mjs.map +1 -0
  98. package/dist/sandbox/shared/editor.d.ts +17 -0
  99. package/dist/sandbox/shared/editor.js +65 -0
  100. package/dist/sandbox/shared/editor.js.map +1 -0
  101. package/dist/sandbox/shared/editor.mjs +61 -0
  102. package/dist/sandbox/shared/editor.mjs.map +1 -0
  103. package/dist/sandbox/shared/environment.d.ts +1 -0
  104. package/dist/sandbox/shared/environment.js +13 -0
  105. package/dist/sandbox/shared/environment.js.map +1 -0
  106. package/dist/sandbox/shared/environment.mjs +2 -0
  107. package/dist/sandbox/shared/environment.mjs.map +1 -0
  108. package/dist/sandbox/shared/git.d.ts +4 -0
  109. package/dist/sandbox/shared/git.js +20 -0
  110. package/dist/sandbox/shared/git.js.map +1 -0
  111. package/dist/sandbox/shared/git.mjs +17 -0
  112. package/dist/sandbox/shared/git.mjs.map +1 -0
  113. package/dist/sandbox/shared/inContainerMounts.d.ts +40 -0
  114. package/dist/sandbox/shared/inContainerMounts.js +670 -0
  115. package/dist/sandbox/shared/inContainerMounts.js.map +1 -0
  116. package/dist/sandbox/shared/inContainerMounts.mjs +662 -0
  117. package/dist/sandbox/shared/inContainerMounts.mjs.map +1 -0
  118. package/dist/sandbox/shared/index.d.ts +23 -0
  119. package/dist/sandbox/shared/index.js +112 -0
  120. package/dist/sandbox/shared/index.js.map +1 -0
  121. package/dist/sandbox/shared/index.mjs +18 -0
  122. package/dist/sandbox/shared/index.mjs.map +1 -0
  123. package/dist/sandbox/shared/localSources.d.ts +8 -0
  124. package/dist/sandbox/shared/localSources.js +378 -0
  125. package/dist/sandbox/shared/localSources.js.map +1 -0
  126. package/dist/sandbox/shared/localSources.mjs +372 -0
  127. package/dist/sandbox/shared/localSources.mjs.map +1 -0
  128. package/dist/sandbox/shared/manifest.d.ts +38 -0
  129. package/dist/sandbox/shared/manifest.js +254 -0
  130. package/dist/sandbox/shared/manifest.js.map +1 -0
  131. package/dist/sandbox/shared/manifest.mjs +233 -0
  132. package/dist/sandbox/shared/manifest.mjs.map +1 -0
  133. package/dist/sandbox/shared/media.d.ts +1 -0
  134. package/dist/sandbox/shared/media.js +10 -0
  135. package/dist/sandbox/shared/media.js.map +1 -0
  136. package/dist/sandbox/shared/media.mjs +2 -0
  137. package/dist/sandbox/shared/media.mjs.map +1 -0
  138. package/dist/sandbox/shared/metadata.d.ts +7 -0
  139. package/dist/sandbox/shared/metadata.js +87 -0
  140. package/dist/sandbox/shared/metadata.js.map +1 -0
  141. package/dist/sandbox/shared/metadata.mjs +81 -0
  142. package/dist/sandbox/shared/metadata.mjs.map +1 -0
  143. package/dist/sandbox/shared/output.d.ts +1 -0
  144. package/dist/sandbox/shared/output.js +8 -0
  145. package/dist/sandbox/shared/output.js.map +1 -0
  146. package/dist/sandbox/shared/output.mjs +2 -0
  147. package/dist/sandbox/shared/output.mjs.map +1 -0
  148. package/dist/sandbox/shared/paths.d.ts +27 -0
  149. package/dist/sandbox/shared/paths.js +245 -0
  150. package/dist/sandbox/shared/paths.js.map +1 -0
  151. package/dist/sandbox/shared/paths.mjs +236 -0
  152. package/dist/sandbox/shared/paths.mjs.map +1 -0
  153. package/dist/sandbox/shared/ports.d.ts +14 -0
  154. package/dist/sandbox/shared/ports.js +75 -0
  155. package/dist/sandbox/shared/ports.js.map +1 -0
  156. package/dist/sandbox/shared/ports.mjs +69 -0
  157. package/dist/sandbox/shared/ports.mjs.map +1 -0
  158. package/dist/sandbox/shared/process.d.ts +16 -0
  159. package/dist/sandbox/shared/process.js +90 -0
  160. package/dist/sandbox/shared/process.js.map +1 -0
  161. package/dist/sandbox/shared/process.mjs +86 -0
  162. package/dist/sandbox/shared/process.mjs.map +1 -0
  163. package/dist/sandbox/shared/pty.d.ts +81 -0
  164. package/dist/sandbox/shared/pty.js +382 -0
  165. package/dist/sandbox/shared/pty.js.map +1 -0
  166. package/dist/sandbox/shared/pty.mjs +335 -0
  167. package/dist/sandbox/shared/pty.mjs.map +1 -0
  168. package/dist/sandbox/shared/runAs.d.ts +46 -0
  169. package/dist/sandbox/shared/runAs.js +149 -0
  170. package/dist/sandbox/shared/runAs.js.map +1 -0
  171. package/dist/sandbox/shared/runAs.mjs +141 -0
  172. package/dist/sandbox/shared/runAs.mjs.map +1 -0
  173. package/dist/sandbox/shared/session.d.ts +16 -0
  174. package/dist/sandbox/shared/session.js +138 -0
  175. package/dist/sandbox/shared/session.js.map +1 -0
  176. package/dist/sandbox/shared/session.mjs +128 -0
  177. package/dist/sandbox/shared/session.mjs.map +1 -0
  178. package/dist/sandbox/shared/sessionBase.d.ts +90 -0
  179. package/dist/sandbox/shared/sessionBase.js +446 -0
  180. package/dist/sandbox/shared/sessionBase.js.map +1 -0
  181. package/dist/sandbox/shared/sessionBase.mjs +442 -0
  182. package/dist/sandbox/shared/sessionBase.mjs.map +1 -0
  183. package/dist/sandbox/shared/sessionState.d.ts +7 -0
  184. package/dist/sandbox/shared/sessionState.js +35 -0
  185. package/dist/sandbox/shared/sessionState.js.map +1 -0
  186. package/dist/sandbox/shared/sessionState.mjs +31 -0
  187. package/dist/sandbox/shared/sessionState.mjs.map +1 -0
  188. package/dist/sandbox/shared/snapshots.d.ts +9 -0
  189. package/dist/sandbox/shared/snapshots.js +62 -0
  190. package/dist/sandbox/shared/snapshots.js.map +1 -0
  191. package/dist/sandbox/shared/snapshots.mjs +57 -0
  192. package/dist/sandbox/shared/snapshots.mjs.map +1 -0
  193. package/dist/sandbox/shared/typeGuards.d.ts +10 -0
  194. package/dist/sandbox/shared/typeGuards.js +50 -0
  195. package/dist/sandbox/shared/typeGuards.js.map +1 -0
  196. package/dist/sandbox/shared/typeGuards.mjs +38 -0
  197. package/dist/sandbox/shared/typeGuards.mjs.map +1 -0
  198. package/dist/sandbox/shared/types.d.ts +24 -0
  199. package/dist/sandbox/shared/types.js +3 -0
  200. package/dist/sandbox/shared/types.js.map +1 -0
  201. package/dist/sandbox/shared/types.mjs +2 -0
  202. package/dist/sandbox/shared/types.mjs.map +1 -0
  203. package/dist/sandbox/vercel/index.d.ts +1 -0
  204. package/dist/sandbox/vercel/index.js +18 -0
  205. package/dist/sandbox/vercel/index.js.map +1 -0
  206. package/dist/sandbox/vercel/index.mjs +2 -0
  207. package/dist/sandbox/vercel/index.mjs.map +1 -0
  208. package/dist/sandbox/vercel/sandbox.d.ts +135 -0
  209. package/dist/sandbox/vercel/sandbox.js +1001 -0
  210. package/dist/sandbox/vercel/sandbox.js.map +1 -0
  211. package/dist/sandbox/vercel/sandbox.mjs +963 -0
  212. package/dist/sandbox/vercel/sandbox.mjs.map +1 -0
  213. package/package.json +108 -4
@@ -0,0 +1,1163 @@
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.CloudflareSandboxClient = exports.CloudflareSandboxSession = void 0;
37
+ const agents_core_1 = require("@openai/agents-core");
38
+ const _shims_1 = require("@openai/agents-core/_shims");
39
+ const sandbox_1 = require("@openai/agents-core/sandbox");
40
+ const archive_1 = require("../shared/archive.js");
41
+ const editor_1 = require("../shared/editor.js");
42
+ const environment_1 = require("../shared/environment.js");
43
+ const manifest_1 = require("../shared/manifest.js");
44
+ const media_1 = require("../shared/media.js");
45
+ const metadata_1 = require("../shared/metadata.js");
46
+ const output_1 = require("../shared/output.js");
47
+ const ports_1 = require("../shared/ports.js");
48
+ const pty_1 = require("../shared/pty.js");
49
+ const paths_1 = require("../shared/paths.js");
50
+ const session_1 = require("../shared/session.js");
51
+ const runAs_1 = require("../shared/runAs.js");
52
+ const sessionState_1 = require("../shared/sessionState.js");
53
+ const typeGuards_1 = require("../shared/typeGuards.js");
54
+ const mounts_1 = require("./mounts.js");
55
+ class CloudflareSandboxSession {
56
+ state;
57
+ apiKey;
58
+ ptyProcesses = new pty_1.PtyProcessRegistry();
59
+ concurrencyLimits;
60
+ remotePathResolver = async (path, options) => await this.resolveRemotePath(path, options);
61
+ constructor(args) {
62
+ this.state = {
63
+ ...args.state,
64
+ sandboxId: normalizeCloudflarePersistedSandboxId(args.state.sandboxId),
65
+ };
66
+ this.apiKey = args.apiKey;
67
+ this.concurrencyLimits = args.concurrencyLimits;
68
+ }
69
+ createEditor(runAs) {
70
+ if (runAs) {
71
+ return (0, runAs_1.createRunAsRemoteEditor)({
72
+ providerName: 'CloudflareSandboxClient',
73
+ providerId: 'cloudflare',
74
+ runAs,
75
+ resolvePath: this.remotePathResolver,
76
+ runCommand: this.runAsCommandRunner.bind(this),
77
+ writer: this.writer(),
78
+ });
79
+ }
80
+ return new editor_1.RemoteSandboxEditor({
81
+ resolvePath: this.remotePathResolver,
82
+ pathExists: async (path) => await this.pathExists(path),
83
+ mkdir: async (path) => {
84
+ await this.mkdirPath(path, 'create directory');
85
+ },
86
+ readText: async (path) => new TextDecoder().decode(await this.readFileBytes(path)),
87
+ writeText: async (path, content) => {
88
+ await this.ensureParentDir(path);
89
+ await this.writeFile(path, new TextEncoder().encode(content));
90
+ },
91
+ deletePath: async (path) => {
92
+ const result = await this.execShell(`rm -f -- ${(0, paths_1.shellQuote)(path)}`);
93
+ if (result.exitCode !== 0) {
94
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient failed to delete path.', {
95
+ provider: 'cloudflare',
96
+ operation: 'delete path',
97
+ sandboxId: this.state.sandboxId,
98
+ path,
99
+ exitCode: result.exitCode,
100
+ output: result.output,
101
+ });
102
+ }
103
+ },
104
+ });
105
+ }
106
+ supportsPty() {
107
+ return true;
108
+ }
109
+ async execCommand(args) {
110
+ if (args.tty) {
111
+ return await this.execPtyCommand(args);
112
+ }
113
+ const start = Date.now();
114
+ const wrapped = (0, runAs_1.sandboxUserShellCommand)(buildShellCommand(args.cmd, this.state.environment, (0, paths_1.resolveSandboxWorkdir)(this.state.manifest.root, args.workdir)), args.runAs);
115
+ const result = await this.execShell(wrapped);
116
+ const output = (0, output_1.truncateOutput)(result.output, args.maxOutputTokens);
117
+ return (0, output_1.formatExecResponse)({
118
+ output: output.text,
119
+ wallTimeSeconds: (0, output_1.elapsedSeconds)(start),
120
+ exitCode: result.exitCode,
121
+ originalTokenCount: output.originalTokenCount,
122
+ });
123
+ }
124
+ async writeStdin(args) {
125
+ return await (0, pty_1.writePtyStdin)({
126
+ providerName: 'CloudflareSandboxClient',
127
+ registry: this.ptyProcesses,
128
+ sessionId: args.sessionId,
129
+ chars: args.chars,
130
+ yieldTimeMs: args.yieldTimeMs,
131
+ maxOutputTokens: args.maxOutputTokens,
132
+ });
133
+ }
134
+ async execPtyCommand(args) {
135
+ const start = Date.now();
136
+ const entry = (0, pty_1.createPtyProcessEntry)({ tty: true });
137
+ let readyPromise = Promise.resolve();
138
+ let removeMessageListener = () => { };
139
+ const socket = await (0, pty_1.openPtyWebSocket)({
140
+ url: buildCloudflarePtyWebSocketUrl(this.state),
141
+ providerName: 'CloudflareSandboxClient',
142
+ headers: buildCloudflarePtyWebSocketHeaders(this.apiKey),
143
+ headersUnsupportedUrl: buildCloudflarePtyWebSocketUrl(this.state, this.apiKey),
144
+ configure: (pendingSocket) => {
145
+ removeMessageListener = (0, pty_1.addPtyWebSocketListener)(pendingSocket, 'message', (event) => handleCloudflarePtyMessage(entry, event));
146
+ readyPromise = waitForCloudflarePtyReady(pendingSocket);
147
+ readyPromise.catch(() => { });
148
+ },
149
+ });
150
+ const removeCloseListener = (0, pty_1.addPtyWebSocketListener)(socket, 'close', () => {
151
+ if (!entry.done) {
152
+ (0, pty_1.markPtyDone)(entry);
153
+ }
154
+ });
155
+ const removeErrorListener = (0, pty_1.addPtyWebSocketListener)(socket, 'error', () => {
156
+ if (!entry.done) {
157
+ (0, pty_1.markPtyDone)(entry, 1);
158
+ }
159
+ });
160
+ try {
161
+ await readyPromise;
162
+ }
163
+ catch (error) {
164
+ socket.close();
165
+ throw error;
166
+ }
167
+ entry.sendInput = async (chars) => {
168
+ socket.send(new TextEncoder().encode(chars));
169
+ };
170
+ entry.terminate = async () => {
171
+ removeMessageListener();
172
+ removeCloseListener();
173
+ removeErrorListener();
174
+ socket.close();
175
+ };
176
+ let registered = false;
177
+ let sessionId;
178
+ try {
179
+ const command = (0, pty_1.shellCommandForPty)({
180
+ ...args,
181
+ cmd: (0, runAs_1.sandboxUserShellCommand)(buildShellCommand(args.cmd, this.state.environment, (0, paths_1.resolveSandboxWorkdir)(this.state.manifest.root, args.workdir)), args.runAs),
182
+ });
183
+ await entry.sendInput(`${command}\n`);
184
+ const registeredProcess = this.ptyProcesses.register(entry);
185
+ registered = true;
186
+ sessionId = registeredProcess.sessionId;
187
+ if (registeredProcess.pruned) {
188
+ await registeredProcess.pruned.terminate?.().catch(() => { });
189
+ }
190
+ }
191
+ catch (error) {
192
+ if (!registered) {
193
+ await entry.terminate?.().catch(() => { });
194
+ }
195
+ throw error;
196
+ }
197
+ return await (0, pty_1.formatPtyExecUpdate)({
198
+ registry: this.ptyProcesses,
199
+ sessionId,
200
+ entry,
201
+ startTime: start,
202
+ yieldTimeMs: args.yieldTimeMs,
203
+ maxOutputTokens: args.maxOutputTokens,
204
+ });
205
+ }
206
+ async viewImage(args) {
207
+ const absolutePath = await this.resolveRemotePath(args.path);
208
+ const bytes = args.runAs
209
+ ? await (0, runAs_1.readRunAsRemoteFile)({
210
+ providerName: 'CloudflareSandboxClient',
211
+ providerId: 'cloudflare',
212
+ path: absolutePath,
213
+ runAs: args.runAs,
214
+ runCommand: this.runAsCommandRunner.bind(this),
215
+ })
216
+ : await this.readFileBytes(absolutePath);
217
+ return (0, media_1.imageOutputFromBytes)(args.path, bytes);
218
+ }
219
+ async readFile(args) {
220
+ const absolutePath = await this.resolveRemotePath(args.path);
221
+ const bytes = args.runAs
222
+ ? await (0, runAs_1.readRunAsRemoteFile)({
223
+ providerName: 'CloudflareSandboxClient',
224
+ providerId: 'cloudflare',
225
+ path: absolutePath,
226
+ runAs: args.runAs,
227
+ runCommand: this.runAsCommandRunner.bind(this),
228
+ })
229
+ : await this.readFileBytes(absolutePath);
230
+ if (typeof args.maxBytes === 'number' && bytes.byteLength > args.maxBytes) {
231
+ return bytes.subarray(0, args.maxBytes);
232
+ }
233
+ return bytes;
234
+ }
235
+ async pathExists(path, runAs) {
236
+ const absolutePath = await this.resolveRemotePath(path);
237
+ if (!runAs) {
238
+ const result = await this.execShell(`test -e ${(0, paths_1.shellQuote)(absolutePath)}`);
239
+ return result.exitCode === 0;
240
+ }
241
+ return await (0, runAs_1.runAsRemotePathExists)(absolutePath, runAs, this.runAsCommandRunner.bind(this));
242
+ }
243
+ async running() {
244
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/running`, {
245
+ method: 'GET',
246
+ });
247
+ if (response.status === 404) {
248
+ return false;
249
+ }
250
+ if (!response.ok) {
251
+ throw cloudflareProviderHttpError('check running state', response, {
252
+ sandboxId: this.state.sandboxId,
253
+ });
254
+ }
255
+ const payload = (await response.json().catch(() => ({})));
256
+ return Boolean(payload.running);
257
+ }
258
+ async resolveExposedPort(port) {
259
+ const requestedPort = (0, ports_1.assertConfiguredExposedPort)({
260
+ providerName: 'CloudflareSandboxClient',
261
+ port,
262
+ configuredPorts: this.state.configuredExposedPorts,
263
+ });
264
+ throw new sandbox_1.SandboxUnsupportedFeatureError('CloudflareSandboxClient does not support exposed port resolution until the worker deployment exposes a port-resolution endpoint.', {
265
+ provider: 'cloudflare',
266
+ port: requestedPort,
267
+ });
268
+ }
269
+ async materializeEntry(args) {
270
+ (0, metadata_1.assertSandboxEntryMetadataSupported)('CloudflareSandboxClient', args.path, args.entry, metadata_1.MOUNT_MANIFEST_METADATA_SUPPORT);
271
+ if ((0, manifest_1.entryContainsLocalSource)(args.entry)) {
272
+ const { applyLocalSourceManifestEntryToState } = await Promise.resolve().then(() => __importStar(require("../shared/localSources.js")));
273
+ await applyLocalSourceManifestEntryToState(this.state, args.path, args.entry, 'cloudflare', this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
274
+ return;
275
+ }
276
+ await (0, manifest_1.applyInlineManifestEntryToState)(this.state, args.path, args.entry, 'cloudflare', this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(args.runAs));
277
+ }
278
+ async applyManifest(manifest, runAs) {
279
+ assertCloudflareManifestRoot(manifest);
280
+ (0, metadata_1.assertSandboxManifestMetadataSupported)('CloudflareSandboxClient', manifest, metadata_1.MOUNT_MANIFEST_METADATA_SUPPORT);
281
+ assertCloudflareManifestMountsSupported(manifest);
282
+ if ((0, manifest_1.manifestContainsLocalSource)(manifest)) {
283
+ const { applyLocalSourceManifestToState } = await Promise.resolve().then(() => __importStar(require("../shared/localSources.js")));
284
+ await applyLocalSourceManifestToState(this.state, manifest, 'cloudflare', this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
285
+ return;
286
+ }
287
+ await (0, manifest_1.applyInlineManifestToState)(this.state, manifest, 'cloudflare', this.writer(), this.remotePathResolver, this.manifestMaterializationOptions(runAs));
288
+ }
289
+ async mountBucket(args) {
290
+ const mountPath = await this.resolveRemotePath(args.mountPath, {
291
+ forWrite: true,
292
+ });
293
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/mount`, {
294
+ method: 'POST',
295
+ headers: {
296
+ 'Content-Type': 'application/json',
297
+ },
298
+ body: JSON.stringify({
299
+ bucket: args.bucket,
300
+ mountPath,
301
+ options: args.options,
302
+ }),
303
+ });
304
+ if (!response.ok) {
305
+ throw await cloudflareMountError({
306
+ response,
307
+ message: 'Cloudflare bucket mount failed.',
308
+ mountPath,
309
+ bucket: args.bucket,
310
+ });
311
+ }
312
+ }
313
+ async unmountBucket(mountPath) {
314
+ const resolvedMountPath = await this.resolveRemotePath(mountPath, {
315
+ forWrite: true,
316
+ });
317
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/unmount`, {
318
+ method: 'POST',
319
+ headers: {
320
+ 'Content-Type': 'application/json',
321
+ },
322
+ body: JSON.stringify({
323
+ mountPath: resolvedMountPath,
324
+ }),
325
+ });
326
+ if (!response.ok) {
327
+ throw await cloudflareMountError({
328
+ response,
329
+ message: 'Cloudflare bucket unmount failed.',
330
+ mountPath: resolvedMountPath,
331
+ });
332
+ }
333
+ }
334
+ async persistWorkspace() {
335
+ (0, archive_1.assertTarWorkspacePersistence)('CloudflareSandboxClient', 'tar');
336
+ const excludes = [...this.state.manifest.ephemeralPersistencePaths()]
337
+ .filter((path) => path.length > 0)
338
+ .sort((left, right) => left.localeCompare(right))
339
+ .join(',');
340
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/persist${excludes ? `?excludes=${encodeURIComponent(excludes)}` : ''}`, {
341
+ method: 'POST',
342
+ });
343
+ if (!response.ok) {
344
+ throw new sandbox_1.SandboxArchiveError(`Cloudflare sandbox persist failed with HTTP ${response.status}.`, {
345
+ provider: 'cloudflare',
346
+ sandboxId: this.state.sandboxId,
347
+ status: response.status,
348
+ });
349
+ }
350
+ const archive = decodeStreamedPayload(new Uint8Array(await response.arrayBuffer()), response.headers);
351
+ (0, archive_1.validateWorkspaceTarArchive)(archive);
352
+ return archive;
353
+ }
354
+ async hydrateWorkspace(data) {
355
+ (0, archive_1.assertTarWorkspacePersistence)('CloudflareSandboxClient', 'tar');
356
+ const archive = (0, archive_1.toWorkspaceArchiveBytes)(data);
357
+ (0, archive_1.validateWorkspaceTarArchive)(archive);
358
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/hydrate`, {
359
+ method: 'POST',
360
+ headers: {
361
+ 'Content-Type': 'application/octet-stream',
362
+ },
363
+ body: toArrayBuffer(archive),
364
+ });
365
+ if (!response.ok) {
366
+ throw new sandbox_1.SandboxArchiveError(`Cloudflare sandbox hydrate failed with HTTP ${response.status}.`, {
367
+ provider: 'cloudflare',
368
+ sandboxId: this.state.sandboxId,
369
+ status: response.status,
370
+ });
371
+ }
372
+ }
373
+ async close() {
374
+ await this.ptyProcesses.terminateAll();
375
+ await (0, session_1.withSandboxSpan)('sandbox.stop', {
376
+ backend_id: 'cloudflare',
377
+ sandbox_id: this.state.sandboxId,
378
+ }, async () => {
379
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}`, {
380
+ method: 'DELETE',
381
+ });
382
+ if (!response.ok && response.status !== 404) {
383
+ throw cloudflareProviderHttpError('delete sandbox', response, {
384
+ sandboxId: this.state.sandboxId,
385
+ });
386
+ }
387
+ });
388
+ }
389
+ async shutdown() {
390
+ await this.close();
391
+ }
392
+ async delete() {
393
+ await this.close();
394
+ }
395
+ writer() {
396
+ return {
397
+ mkdir: async (path) => {
398
+ await this.mkdirPath(path, 'create directory');
399
+ },
400
+ writeFile: async (path, content) => {
401
+ await this.ensureParentDir(path);
402
+ await this.writeFile(path, typeof content === 'string'
403
+ ? new TextEncoder().encode(content)
404
+ : content);
405
+ },
406
+ };
407
+ }
408
+ manifestMaterializationOptions(runAs) {
409
+ return (0, runAs_1.manifestMaterializationOptionsWithRunAs)({
410
+ providerName: 'CloudflareSandboxClient',
411
+ providerId: 'cloudflare',
412
+ runAs,
413
+ runCommand: this.runAsCommandRunner.bind(this),
414
+ options: {
415
+ materializeMount: this.materializeMountEntry.bind(this),
416
+ concurrencyLimits: this.concurrencyLimits,
417
+ },
418
+ support: metadata_1.MOUNT_MANIFEST_METADATA_SUPPORT,
419
+ });
420
+ }
421
+ async materializeMountEntry(absolutePath, entry) {
422
+ if (!(0, mounts_1.isCloudflareBucketMountEntry)(entry)) {
423
+ throw new sandbox_1.SandboxUnsupportedFeatureError('CloudflareSandboxClient only supports CloudflareBucketMountStrategy mount entries.', {
424
+ provider: 'cloudflare',
425
+ feature: 'entry.mountStrategy',
426
+ path: absolutePath,
427
+ mountType: entry.type,
428
+ strategyType: entry.mountStrategy?.type,
429
+ });
430
+ }
431
+ const config = (0, mounts_1.buildCloudflareBucketMountConfig)(entry);
432
+ await this.mountBucket({
433
+ bucket: config.bucketName,
434
+ mountPath: entry.mountPath ?? absolutePath,
435
+ options: (0, mounts_1.cloudflareBucketMountRequestOptions)(config),
436
+ });
437
+ }
438
+ async execShell(shellCommand) {
439
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/exec`, {
440
+ method: 'POST',
441
+ headers: {
442
+ 'Content-Type': 'application/json',
443
+ },
444
+ body: JSON.stringify({
445
+ argv: ['/bin/sh', '-lc', shellCommand],
446
+ ...(typeof this.state.timeouts?.execTimeoutMs === 'number' ||
447
+ typeof this.state.timeoutMs === 'number'
448
+ ? {
449
+ timeout_ms: this.state.timeouts?.execTimeoutMs ?? this.state.timeoutMs,
450
+ }
451
+ : {}),
452
+ }),
453
+ });
454
+ if (!response.ok) {
455
+ throw cloudflareProviderHttpError('execute command', response, {
456
+ sandboxId: this.state.sandboxId,
457
+ });
458
+ }
459
+ if (!response.body) {
460
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient failed to execute command.', {
461
+ provider: 'cloudflare',
462
+ operation: 'execute command',
463
+ sandboxId: this.state.sandboxId,
464
+ cause: 'missing response body',
465
+ });
466
+ }
467
+ const decoder = new TextDecoder();
468
+ const reader = response.body.getReader();
469
+ let buffer = '';
470
+ let stdout = '';
471
+ let stderr = '';
472
+ let exitCode;
473
+ const processEvent = (event) => {
474
+ if (event.event === 'stdout') {
475
+ stdout += decodeBase64Text(event.data);
476
+ return;
477
+ }
478
+ if (event.event === 'stderr') {
479
+ stderr += decodeBase64Text(event.data);
480
+ return;
481
+ }
482
+ if (event.event === 'exit') {
483
+ try {
484
+ const payload = JSON.parse(event.data);
485
+ exitCode =
486
+ typeof payload.exit_code === 'number' &&
487
+ Number.isFinite(payload.exit_code)
488
+ ? Math.trunc(payload.exit_code)
489
+ : 1;
490
+ }
491
+ catch {
492
+ exitCode = 1;
493
+ }
494
+ return;
495
+ }
496
+ if (event.event === 'error') {
497
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient failed to execute command.', {
498
+ provider: 'cloudflare',
499
+ operation: 'execute command',
500
+ sandboxId: this.state.sandboxId,
501
+ cause: event.data || 'unknown error',
502
+ });
503
+ }
504
+ };
505
+ while (true) {
506
+ const chunk = await reader.read();
507
+ if (chunk.done) {
508
+ break;
509
+ }
510
+ buffer += decoder.decode(chunk.value, { stream: true });
511
+ const { events, remaining } = splitCompleteSseEvents(buffer);
512
+ buffer = remaining;
513
+ for (const part of events) {
514
+ const event = parseSseEvent(part);
515
+ if (!event) {
516
+ continue;
517
+ }
518
+ processEvent(event);
519
+ }
520
+ }
521
+ buffer += decoder.decode();
522
+ for (const part of collectSseEvents(buffer)) {
523
+ const event = parseSseEvent(part);
524
+ if (event) {
525
+ processEvent(event);
526
+ }
527
+ }
528
+ return {
529
+ exitCode: exitCode ?? 1,
530
+ output: [stdout.trimEnd(), stderr.trimEnd()]
531
+ .filter((value) => value.length > 0)
532
+ .join('\n'),
533
+ };
534
+ }
535
+ async runAsCommandRunner(command, options = {}) {
536
+ const result = await this.execShell((0, runAs_1.sandboxUserShellCommand)(command, options.runAs));
537
+ return {
538
+ status: result.exitCode,
539
+ stdout: result.output,
540
+ stderr: '',
541
+ };
542
+ }
543
+ async readFileBytes(path) {
544
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/file/${encodeSandboxPath(path)}`, {
545
+ method: 'GET',
546
+ });
547
+ if (response.status === 404) {
548
+ throw new sandbox_1.SandboxWorkspaceReadNotFoundError(`Cloudflare sandbox path not found: ${path}.`, {
549
+ provider: 'cloudflare',
550
+ sandboxId: this.state.sandboxId,
551
+ path,
552
+ status: response.status,
553
+ });
554
+ }
555
+ if (!response.ok) {
556
+ throw cloudflareProviderHttpError('read file', response, {
557
+ sandboxId: this.state.sandboxId,
558
+ path,
559
+ });
560
+ }
561
+ const bytes = new Uint8Array(await response.arrayBuffer());
562
+ return decodeStreamedPayload(bytes, response.headers);
563
+ }
564
+ async writeFile(path, content) {
565
+ const response = await this.fetch(`/v1/sandbox/${this.state.sandboxId}/file/${encodeSandboxPath(path)}`, {
566
+ method: 'PUT',
567
+ headers: {
568
+ 'Content-Type': 'application/octet-stream',
569
+ },
570
+ body: toArrayBuffer(content),
571
+ });
572
+ if (!response.ok) {
573
+ throw cloudflareProviderHttpError('write file', response, {
574
+ sandboxId: this.state.sandboxId,
575
+ path,
576
+ });
577
+ }
578
+ }
579
+ async ensureParentDir(path) {
580
+ const parent = (0, paths_1.posixDirname)(path);
581
+ if (parent !== '.' && parent !== '/') {
582
+ await this.mkdirPath(parent, 'create parent directory');
583
+ }
584
+ }
585
+ async mkdirPath(path, operation) {
586
+ const result = await this.execShell(`mkdir -p -- ${(0, paths_1.shellQuote)(path)}`);
587
+ if (result.exitCode !== 0) {
588
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient failed to create directory.', {
589
+ provider: 'cloudflare',
590
+ operation,
591
+ sandboxId: this.state.sandboxId,
592
+ path,
593
+ exitCode: result.exitCode,
594
+ output: result.output,
595
+ });
596
+ }
597
+ }
598
+ async fetch(path, init, timeoutMs) {
599
+ const headers = new Headers(init.headers ?? {});
600
+ const apiKey = this.apiKey ?? (0, _shims_1.loadEnv)().CLOUDFLARE_SANDBOX_API_KEY;
601
+ if (apiKey) {
602
+ headers.set('Authorization', `Bearer ${apiKey}`);
603
+ }
604
+ const requestTimeoutMs = timeoutMs ??
605
+ this.state.timeouts?.requestTimeoutMs ??
606
+ this.state.requestTimeoutMs;
607
+ let timeoutId;
608
+ let controller;
609
+ if (typeof requestTimeoutMs === 'number' && !init.signal) {
610
+ controller = new AbortController();
611
+ timeoutId = setTimeout(() => {
612
+ controller?.abort();
613
+ }, requestTimeoutMs);
614
+ }
615
+ try {
616
+ return await (0, session_1.withProviderError)('CloudflareSandboxClient', 'cloudflare', 'request worker', async () => await fetch(`${this.state.workerUrl}${path}`, {
617
+ ...init,
618
+ headers,
619
+ ...(controller ? { signal: controller.signal } : {}),
620
+ }), {
621
+ sandboxId: this.state.sandboxId,
622
+ path,
623
+ method: init.method ?? 'GET',
624
+ });
625
+ }
626
+ finally {
627
+ if (timeoutId) {
628
+ clearTimeout(timeoutId);
629
+ }
630
+ }
631
+ }
632
+ async resolveRemotePath(path, options = {}) {
633
+ return await (0, paths_1.validateRemoteSandboxPathForManifest)({
634
+ manifest: this.state.manifest,
635
+ path,
636
+ options,
637
+ runCommand: async (command) => {
638
+ const result = await this.execShell(command);
639
+ return {
640
+ status: result.exitCode,
641
+ stdout: result.output,
642
+ stderr: '',
643
+ };
644
+ },
645
+ });
646
+ }
647
+ }
648
+ exports.CloudflareSandboxSession = CloudflareSandboxSession;
649
+ /**
650
+ * @see {@link https://developers.cloudflare.com/sandbox/ | Sandbox SDK overview}.
651
+ * @see {@link https://developers.cloudflare.com/sandbox/get-started/ | Getting started}.
652
+ * @see {@link https://developers.cloudflare.com/sandbox/concepts/architecture/ | Sandbox architecture}.
653
+ */
654
+ class CloudflareSandboxClient {
655
+ backendId = 'cloudflare';
656
+ options;
657
+ constructor(options = {}) {
658
+ this.options = options;
659
+ }
660
+ async create(args, manifestOptions) {
661
+ const createArgs = (0, sandbox_1.normalizeSandboxClientCreateArgs)(args, manifestOptions);
662
+ (0, session_1.assertCoreSnapshotUnsupported)('CloudflareSandboxClient', createArgs.snapshot);
663
+ const manifest = createArgs.manifest;
664
+ const resolvedOptions = {
665
+ ...this.options,
666
+ ...createArgs.options,
667
+ };
668
+ const timeouts = resolveCloudflareTimeouts(resolvedOptions);
669
+ const workerUrl = resolvedOptions.workerUrl;
670
+ if (!workerUrl) {
671
+ throw new agents_core_1.UserError('CloudflareSandboxClient requires options.workerUrl.');
672
+ }
673
+ assertCloudflareManifestRoot(manifest);
674
+ (0, metadata_1.assertSandboxManifestMetadataSupported)('CloudflareSandboxClient', manifest, metadata_1.MOUNT_MANIFEST_METADATA_SUPPORT);
675
+ assertCloudflareManifestMountsSupported(manifest);
676
+ return await (0, session_1.withSandboxSpan)('sandbox.start', {
677
+ backend_id: this.backendId,
678
+ }, async () => {
679
+ const environment = await (0, environment_1.materializeEnvironment)(manifest);
680
+ const headers = new Headers();
681
+ headers.set('Content-Type', 'application/json');
682
+ const apiKey = resolvedOptions.apiKey ?? (0, _shims_1.loadEnv)().CLOUDFLARE_SANDBOX_API_KEY;
683
+ if (apiKey) {
684
+ headers.set('Authorization', `Bearer ${apiKey}`);
685
+ }
686
+ const normalizedWorkerUrl = normalizeCloudflareWorkerUrl(workerUrl, 'options.workerUrl');
687
+ const response = await (0, session_1.withProviderError)('CloudflareSandboxClient', 'cloudflare', 'create sandbox', async () => await fetchWithOptionalTimeout(`${normalizedWorkerUrl}/v1/sandbox`, {
688
+ method: 'POST',
689
+ headers,
690
+ body: JSON.stringify({
691
+ ...(resolvedOptions.exposedPorts
692
+ ? { exposedPorts: resolvedOptions.exposedPorts }
693
+ : {}),
694
+ ...(typeof timeouts.execTimeoutMs === 'number'
695
+ ? { timeoutMs: timeouts.execTimeoutMs }
696
+ : {}),
697
+ ...(typeof timeouts.createTimeoutMs === 'number'
698
+ ? { createTimeoutMs: timeouts.createTimeoutMs }
699
+ : {}),
700
+ ...(resolvedOptions.mounts
701
+ ? { mounts: resolvedOptions.mounts }
702
+ : {}),
703
+ }),
704
+ }, timeouts.createTimeoutMs ?? timeouts.requestTimeoutMs), { workerUrl: normalizedWorkerUrl });
705
+ if (!response.ok) {
706
+ throw cloudflareProviderHttpError('create sandbox', response, {
707
+ workerUrl: normalizedWorkerUrl,
708
+ });
709
+ }
710
+ const payload = await (0, session_1.withProviderError)('CloudflareSandboxClient', 'cloudflare', 'parse create response', async () => (await response.json()), { workerUrl: normalizedWorkerUrl });
711
+ const sandboxId = normalizeCloudflareCreatedSandboxId(payload.id, normalizedWorkerUrl);
712
+ const session = new CloudflareSandboxSession({
713
+ apiKey,
714
+ concurrencyLimits: createArgs.concurrencyLimits,
715
+ state: {
716
+ manifest,
717
+ workerUrl: normalizedWorkerUrl,
718
+ sandboxId,
719
+ configuredExposedPorts: resolvedOptions.exposedPorts,
720
+ timeoutMs: resolvedOptions.timeoutMs,
721
+ createTimeoutMs: timeouts.createTimeoutMs,
722
+ requestTimeoutMs: timeouts.requestTimeoutMs,
723
+ timeouts,
724
+ mounts: resolvedOptions.mounts,
725
+ environment,
726
+ },
727
+ });
728
+ try {
729
+ await session.applyManifest(manifest);
730
+ }
731
+ catch (error) {
732
+ await (0, session_1.closeRemoteSessionOnManifestError)('Cloudflare', session, error);
733
+ }
734
+ return session;
735
+ });
736
+ }
737
+ async serializeSessionState(state) {
738
+ return (0, sessionState_1.serializeRemoteSandboxSessionState)(state);
739
+ }
740
+ canPersistOwnedSessionState() {
741
+ return false;
742
+ }
743
+ async deserializeSessionState(state) {
744
+ const baseState = (0, sessionState_1.deserializeRemoteSandboxSessionStateValues)(state);
745
+ return {
746
+ ...state,
747
+ ...baseState,
748
+ workerUrl: (0, typeGuards_1.readString)(state, 'workerUrl'),
749
+ sandboxId: (0, typeGuards_1.readString)(state, 'sandboxId'),
750
+ configuredExposedPorts: (0, typeGuards_1.readOptionalNumberArray)(state.configuredExposedPorts),
751
+ timeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'timeoutMs'),
752
+ createTimeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'createTimeoutMs'),
753
+ requestTimeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'requestTimeoutMs'),
754
+ timeouts: resolveCloudflareTimeouts({
755
+ timeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'timeoutMs'),
756
+ createTimeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'createTimeoutMs'),
757
+ requestTimeoutMs: (0, typeGuards_1.readOptionalNumber)(state, 'requestTimeoutMs'),
758
+ timeouts: (0, typeGuards_1.isRecord)(state.timeouts)
759
+ ? state.timeouts
760
+ : undefined,
761
+ }),
762
+ mounts: (0, typeGuards_1.readOptionalRecordArray)(state.mounts),
763
+ };
764
+ }
765
+ async resume(state) {
766
+ const sandboxId = normalizeCloudflarePersistedSandboxId(state.sandboxId);
767
+ const workerUrl = normalizeCloudflareWorkerUrl(state.workerUrl, 'persisted workerUrl');
768
+ assertCloudflareManifestRoot(state.manifest);
769
+ (0, metadata_1.assertSandboxManifestMetadataSupported)('CloudflareSandboxClient', state.manifest, metadata_1.MOUNT_MANIFEST_METADATA_SUPPORT);
770
+ assertCloudflareManifestMountsSupported(state.manifest);
771
+ const session = new CloudflareSandboxSession({
772
+ state: {
773
+ ...state,
774
+ sandboxId,
775
+ workerUrl,
776
+ },
777
+ apiKey: this.options.apiKey ?? (0, _shims_1.loadEnv)().CLOUDFLARE_SANDBOX_API_KEY,
778
+ });
779
+ if (!(await session.running())) {
780
+ throw new agents_core_1.UserError(`Cloudflare sandbox ${sandboxId} is no longer running.`);
781
+ }
782
+ return session;
783
+ }
784
+ }
785
+ exports.CloudflareSandboxClient = CloudflareSandboxClient;
786
+ function buildShellCommand(command, environment, cwd) {
787
+ const exports = Object.entries(environment).map(([key, value]) => {
788
+ (0, environment_1.assertShellEnvironmentName)(key);
789
+ return `export ${key}=${(0, paths_1.shellQuote)(value)}`;
790
+ });
791
+ return [`cd ${(0, paths_1.shellQuote)(cwd)}`, ...exports, command].join(' && ');
792
+ }
793
+ function encodeSandboxPath(path) {
794
+ return path.replace(/^\//, '').split('/').map(encodeURIComponent).join('/');
795
+ }
796
+ function resolveCloudflareTimeouts(options) {
797
+ return {
798
+ ...options.timeouts,
799
+ execTimeoutMs: options.timeouts?.execTimeoutMs ?? options.timeoutMs,
800
+ createTimeoutMs: options.timeouts?.createTimeoutMs ?? options.createTimeoutMs,
801
+ requestTimeoutMs: options.timeouts?.requestTimeoutMs ?? options.requestTimeoutMs,
802
+ };
803
+ }
804
+ function normalizeCloudflareWorkerUrl(workerUrl, source) {
805
+ let url;
806
+ try {
807
+ url = new URL(workerUrl);
808
+ }
809
+ catch {
810
+ throw new agents_core_1.UserError(`Cloudflare sandbox ${source} must be an absolute http(s) URL.`);
811
+ }
812
+ if ((url.protocol !== 'https:' && url.protocol !== 'http:') ||
813
+ url.search ||
814
+ url.hash) {
815
+ throw new agents_core_1.UserError(`Cloudflare sandbox ${source} must be an absolute http(s) URL.`);
816
+ }
817
+ return url.href.replace(/\/$/u, '');
818
+ }
819
+ const CLOUDFLARE_SANDBOX_ID_PATTERN = /^[A-Za-z0-9_-]+$/u;
820
+ function normalizeCloudflareCreatedSandboxId(sandboxId, workerUrl) {
821
+ if (isValidCloudflareSandboxId(sandboxId)) {
822
+ return sandboxId;
823
+ }
824
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient failed to create sandbox.', {
825
+ provider: 'cloudflare',
826
+ operation: 'create sandbox',
827
+ workerUrl,
828
+ cause: 'invalid sandbox id',
829
+ });
830
+ }
831
+ function normalizeCloudflarePersistedSandboxId(sandboxId) {
832
+ if (sandboxId === undefined || sandboxId === null || sandboxId === '') {
833
+ throw new agents_core_1.UserError('Cloudflare sandbox resume requires a persisted sandboxId.');
834
+ }
835
+ if (isValidCloudflareSandboxId(sandboxId)) {
836
+ return sandboxId;
837
+ }
838
+ throw new agents_core_1.UserError('Cloudflare sandbox persisted sandboxId must be a safe path segment.');
839
+ }
840
+ function isValidCloudflareSandboxId(sandboxId) {
841
+ return (typeof sandboxId === 'string' &&
842
+ CLOUDFLARE_SANDBOX_ID_PATTERN.test(sandboxId));
843
+ }
844
+ async function fetchWithOptionalTimeout(input, init, timeoutMs) {
845
+ let timeoutId;
846
+ let controller;
847
+ if (typeof timeoutMs === 'number' && !init.signal) {
848
+ controller = new AbortController();
849
+ timeoutId = setTimeout(() => {
850
+ controller?.abort();
851
+ }, timeoutMs);
852
+ }
853
+ try {
854
+ return await fetch(input, {
855
+ ...init,
856
+ ...(controller ? { signal: controller.signal } : {}),
857
+ });
858
+ }
859
+ finally {
860
+ if (timeoutId) {
861
+ clearTimeout(timeoutId);
862
+ }
863
+ }
864
+ }
865
+ function buildCloudflarePtyWebSocketUrl(state, apiKey) {
866
+ const base = state.workerUrl.replace(/\/$/u, '');
867
+ const wsBase = base.replace(/^https:/u, 'wss:').replace(/^http:/u, 'ws:');
868
+ const url = new URL(`${wsBase}/v1/sandbox/${state.sandboxId}/pty`);
869
+ url.searchParams.set('cols', '80');
870
+ url.searchParams.set('rows', '24');
871
+ if (apiKey) {
872
+ url.searchParams.set('authorization', `Bearer ${apiKey}`);
873
+ }
874
+ return url.toString();
875
+ }
876
+ function buildCloudflarePtyWebSocketHeaders(apiKey) {
877
+ if (apiKey) {
878
+ return {
879
+ Authorization: `Bearer ${apiKey}`,
880
+ };
881
+ }
882
+ return undefined;
883
+ }
884
+ function assertCloudflareManifestRoot(manifest) {
885
+ if (manifest.root !== '/workspace') {
886
+ throw new agents_core_1.UserError('Cloudflare sandboxes currently require manifest.root="/workspace".');
887
+ }
888
+ }
889
+ function assertCloudflareManifestMountsSupported(manifest) {
890
+ for (const { entry, mountPath } of manifest.mountTargets()) {
891
+ if (!(0, mounts_1.isCloudflareBucketMountEntry)(entry)) {
892
+ throw new sandbox_1.SandboxUnsupportedFeatureError('CloudflareSandboxClient only supports CloudflareBucketMountStrategy mount entries.', {
893
+ provider: 'cloudflare',
894
+ feature: 'entry.mountStrategy',
895
+ path: mountPath,
896
+ mountType: entry.type,
897
+ strategyType: entry.mountStrategy?.type,
898
+ });
899
+ }
900
+ (0, mounts_1.buildCloudflareBucketMountConfig)(entry);
901
+ }
902
+ }
903
+ async function cloudflareMountError(args) {
904
+ const payload = (await args.response.json().catch(() => ({})));
905
+ return new sandbox_1.SandboxMountError(args.message, {
906
+ provider: 'cloudflare',
907
+ mountPath: args.mountPath,
908
+ ...(args.bucket ? { bucket: args.bucket } : {}),
909
+ status: args.response.status,
910
+ reason: typeof payload.error === 'string'
911
+ ? payload.error
912
+ : `HTTP ${args.response.status}`,
913
+ });
914
+ }
915
+ function cloudflareProviderHttpError(operation, response, context = {}) {
916
+ return new sandbox_1.SandboxProviderError(`CloudflareSandboxClient failed to ${operation}.`, {
917
+ provider: 'cloudflare',
918
+ operation,
919
+ status: response.status,
920
+ ...context,
921
+ });
922
+ }
923
+ function waitForCloudflarePtyReady(socket) {
924
+ return new Promise((resolve, reject) => {
925
+ let removeMessage = () => { };
926
+ let removeClose = () => { };
927
+ let removeError = () => { };
928
+ const timer = setTimeout(() => {
929
+ cleanup();
930
+ reject(new agents_core_1.UserError('CloudflareSandboxClient PTY ready timed out.'));
931
+ }, 30_000);
932
+ const cleanup = () => {
933
+ clearTimeout(timer);
934
+ removeMessage();
935
+ removeClose();
936
+ removeError();
937
+ };
938
+ removeMessage = (0, pty_1.addPtyWebSocketListener)(socket, 'message', (event) => {
939
+ const payload = parseCloudflarePtyControlPayload(event);
940
+ if ((0, typeGuards_1.isRecord)(payload)) {
941
+ if (payload.type === 'ready') {
942
+ cleanup();
943
+ resolve();
944
+ return;
945
+ }
946
+ if (payload.type === 'error') {
947
+ cleanup();
948
+ reject(new agents_core_1.UserError(cloudflarePtyReadyErrorMessage(payload)));
949
+ }
950
+ }
951
+ });
952
+ removeClose = (0, pty_1.addPtyWebSocketListener)(socket, 'close', () => {
953
+ cleanup();
954
+ reject(new agents_core_1.UserError('CloudflareSandboxClient PTY WebSocket closed before ready.'));
955
+ });
956
+ removeError = (0, pty_1.addPtyWebSocketListener)(socket, 'error', () => {
957
+ cleanup();
958
+ reject(new agents_core_1.UserError('CloudflareSandboxClient PTY WebSocket failed.'));
959
+ });
960
+ });
961
+ }
962
+ function cloudflarePtyReadyErrorMessage(payload) {
963
+ const message = payload.message;
964
+ return typeof message === 'string' && message.length > 0
965
+ ? `CloudflareSandboxClient PTY failed before ready: ${message}`
966
+ : 'CloudflareSandboxClient PTY failed before ready.';
967
+ }
968
+ function handleCloudflarePtyMessage(entry, event) {
969
+ const payload = parseCloudflarePtyControlPayload(event);
970
+ if ((0, typeGuards_1.isRecord)(payload)) {
971
+ if (payload.type === 'ready') {
972
+ return;
973
+ }
974
+ if (payload.type === 'exit') {
975
+ (0, pty_1.markPtyDone)(entry, typeof payload.code === 'number' ? payload.code : null);
976
+ return;
977
+ }
978
+ if (payload.type === 'error') {
979
+ const message = payload.message;
980
+ if (typeof message === 'string') {
981
+ (0, pty_1.appendPtyOutput)(entry, message);
982
+ }
983
+ if (!entry.done) {
984
+ (0, pty_1.markPtyDone)(entry, 1);
985
+ }
986
+ return;
987
+ }
988
+ }
989
+ const data = webSocketEventData(event);
990
+ if (typeof data === 'string') {
991
+ (0, pty_1.appendPtyOutput)(entry, data);
992
+ return;
993
+ }
994
+ if (data instanceof ArrayBuffer) {
995
+ (0, pty_1.appendPtyOutput)(entry, data);
996
+ return;
997
+ }
998
+ if (ArrayBuffer.isView(data)) {
999
+ (0, pty_1.appendPtyOutput)(entry, new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
1000
+ }
1001
+ }
1002
+ function parseCloudflarePtyControlPayload(event) {
1003
+ const text = webSocketEventText(event);
1004
+ if (!text) {
1005
+ return undefined;
1006
+ }
1007
+ try {
1008
+ return JSON.parse(text);
1009
+ }
1010
+ catch {
1011
+ return undefined;
1012
+ }
1013
+ }
1014
+ function parseSseEvent(chunk) {
1015
+ const lines = chunk
1016
+ .split(/\r?\n/)
1017
+ .map((line) => line.trimEnd())
1018
+ .filter((line) => line.length > 0);
1019
+ if (lines.length === 0) {
1020
+ return null;
1021
+ }
1022
+ let event = 'message';
1023
+ const data = [];
1024
+ for (const line of lines) {
1025
+ if (line.startsWith('event:')) {
1026
+ event = line.slice('event:'.length).trim();
1027
+ continue;
1028
+ }
1029
+ if (line.startsWith('data:')) {
1030
+ data.push(line.slice('data:'.length).trim());
1031
+ }
1032
+ }
1033
+ return {
1034
+ event,
1035
+ data: data.join('\n'),
1036
+ };
1037
+ }
1038
+ function splitCompleteSseEvents(buffer) {
1039
+ const events = [];
1040
+ const delimiterPattern = /\r\n\r\n|\n\n|\r\r/gu;
1041
+ let start = 0;
1042
+ let match;
1043
+ while ((match = delimiterPattern.exec(buffer))) {
1044
+ events.push(buffer.slice(start, match.index));
1045
+ start = match.index + match[0].length;
1046
+ }
1047
+ return {
1048
+ events,
1049
+ remaining: buffer.slice(start),
1050
+ };
1051
+ }
1052
+ function collectSseEvents(text) {
1053
+ const { events, remaining } = splitCompleteSseEvents(text);
1054
+ if (remaining.trim().length > 0) {
1055
+ events.push(remaining);
1056
+ }
1057
+ return events;
1058
+ }
1059
+ function decodeBase64Text(value) {
1060
+ return new TextDecoder().decode(decodeBase64Bytes(value));
1061
+ }
1062
+ const STREAMED_PAYLOAD_SSE_SNIFF_BYTES = 256;
1063
+ function decodeStreamedPayload(body, headers) {
1064
+ if (!shouldParseStreamedPayloadAsSse(body, headers)) {
1065
+ return body;
1066
+ }
1067
+ const text = new TextDecoder().decode(body);
1068
+ if (!startsWithSseFrame(text)) {
1069
+ return body;
1070
+ }
1071
+ const events = collectSseEvents(text);
1072
+ const chunkData = [];
1073
+ let isBinary = false;
1074
+ for (const rawEvent of events) {
1075
+ const event = parseSseEvent(rawEvent);
1076
+ if (!event) {
1077
+ continue;
1078
+ }
1079
+ if (event.event === 'metadata') {
1080
+ try {
1081
+ const payload = JSON.parse(event.data);
1082
+ isBinary = Boolean(payload.isBinary);
1083
+ }
1084
+ catch {
1085
+ // Ignore malformed metadata and fall back to treating the payload as text.
1086
+ }
1087
+ continue;
1088
+ }
1089
+ if (event.event === 'chunk') {
1090
+ chunkData.push(event.data);
1091
+ }
1092
+ }
1093
+ if (!isBinary || chunkData.length === 0) {
1094
+ return body;
1095
+ }
1096
+ let chunks;
1097
+ try {
1098
+ chunks = chunkData.map((data) => decodeBase64Bytes(data));
1099
+ }
1100
+ catch (error) {
1101
+ throw new sandbox_1.SandboxProviderError('CloudflareSandboxClient received an invalid binary stream payload.', {
1102
+ provider: 'cloudflare',
1103
+ operation: 'decode streamed payload',
1104
+ cause: error instanceof Error ? error.message : String(error),
1105
+ });
1106
+ }
1107
+ const size = chunks.reduce((sum, chunk) => sum + chunk.byteLength, 0);
1108
+ const merged = new Uint8Array(size);
1109
+ let offset = 0;
1110
+ for (const chunk of chunks) {
1111
+ merged.set(chunk, offset);
1112
+ offset += chunk.byteLength;
1113
+ }
1114
+ return merged;
1115
+ }
1116
+ function shouldParseStreamedPayloadAsSse(body, headers) {
1117
+ const contentType = headers?.get('Content-Type')?.toLowerCase() ?? '';
1118
+ if (contentType.split(';', 1)[0]?.trim() === 'text/event-stream') {
1119
+ return true;
1120
+ }
1121
+ const prefix = body.subarray(0, Math.min(body.byteLength, STREAMED_PAYLOAD_SSE_SNIFF_BYTES));
1122
+ return startsWithSseFrame(new TextDecoder().decode(prefix));
1123
+ }
1124
+ function startsWithSseFrame(text) {
1125
+ const trimmed = text.trimStart();
1126
+ return (trimmed.startsWith(':') ||
1127
+ trimmed.startsWith('data:') ||
1128
+ trimmed.startsWith('event:') ||
1129
+ trimmed.startsWith('id:') ||
1130
+ trimmed.startsWith('retry:'));
1131
+ }
1132
+ function decodeBase64Bytes(value) {
1133
+ const binary = atob(value.replace(/\s+/gu, ''));
1134
+ const bytes = new Uint8Array(binary.length);
1135
+ for (let index = 0; index < binary.length; index += 1) {
1136
+ bytes[index] = binary.charCodeAt(index);
1137
+ }
1138
+ return bytes;
1139
+ }
1140
+ function toArrayBuffer(bytes) {
1141
+ const copy = new Uint8Array(bytes.byteLength);
1142
+ copy.set(bytes);
1143
+ return copy.buffer;
1144
+ }
1145
+ function webSocketEventData(event) {
1146
+ return event && typeof event === 'object' && 'data' in event
1147
+ ? event.data
1148
+ : event;
1149
+ }
1150
+ function webSocketEventText(event) {
1151
+ const data = webSocketEventData(event);
1152
+ if (typeof data === 'string') {
1153
+ return data;
1154
+ }
1155
+ if (data instanceof ArrayBuffer) {
1156
+ return new TextDecoder().decode(data);
1157
+ }
1158
+ if (ArrayBuffer.isView(data)) {
1159
+ return new TextDecoder().decode(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
1160
+ }
1161
+ return undefined;
1162
+ }
1163
+ //# sourceMappingURL=sandbox.js.map