@cloudflare/sandbox 0.3.1 → 0.3.3
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/CHANGELOG.md +12 -0
- package/Dockerfile +22 -24
- package/README.md +2 -2
- package/container_src/bun.lock +31 -77
- package/container_src/control-process.ts +1 -1
- package/container_src/index.ts +34 -43
- package/container_src/interpreter-service.ts +276 -0
- package/container_src/isolation.ts +1 -1
- package/container_src/mime-processor.ts +1 -1
- package/container_src/package.json +4 -4
- package/container_src/runtime/executors/javascript/node_executor.ts +123 -0
- package/container_src/runtime/executors/python/ipython_executor.py +338 -0
- package/container_src/runtime/executors/typescript/ts_executor.ts +138 -0
- package/container_src/runtime/process-pool.ts +464 -0
- package/container_src/startup.sh +6 -79
- package/dist/{chunk-LALY4SFU.js → chunk-FXYPFGOZ.js} +10 -10
- package/dist/chunk-FXYPFGOZ.js.map +1 -0
- package/dist/{chunk-LFLJGISB.js → chunk-H4PW2LGW.js} +6 -6
- package/dist/chunk-H4PW2LGW.js.map +1 -0
- package/dist/{chunk-FKBV7CZS.js → chunk-JTKON2SH.js} +9 -9
- package/dist/chunk-JTKON2SH.js.map +1 -0
- package/dist/{chunk-EGC5IYXA.js → chunk-W7TVRPBG.js} +2 -2
- package/dist/chunk-W7TVRPBG.js.map +1 -0
- package/dist/{chunk-BEQUGUY4.js → chunk-Z6OZPC6U.js} +9 -6
- package/dist/chunk-Z6OZPC6U.js.map +1 -0
- package/dist/{client-Dny_ro_v.d.ts → client-COGWU6bz.d.ts} +3 -3
- package/dist/client.d.ts +1 -1
- package/dist/errors.d.ts +9 -9
- package/dist/errors.js +5 -5
- package/dist/index.d.ts +2 -2
- package/dist/index.js +13 -11
- package/dist/interpreter-client.d.ts +4 -0
- package/dist/interpreter-client.js +9 -0
- package/dist/interpreter-types.d.ts +5 -5
- package/dist/interpreter-types.js +1 -1
- package/dist/interpreter.d.ts +2 -2
- package/dist/interpreter.js +2 -2
- package/dist/request-handler.d.ts +1 -1
- package/dist/request-handler.js +5 -5
- package/dist/sandbox.d.ts +1 -1
- package/dist/sandbox.js +5 -5
- package/package.json +2 -2
- package/src/errors.ts +15 -14
- package/src/index.ts +16 -5
- package/src/{jupyter-client.ts → interpreter-client.ts} +6 -3
- package/src/interpreter-types.ts +102 -95
- package/src/interpreter.ts +8 -8
- package/src/sandbox.ts +3 -3
- package/container_src/jupyter-server.ts +0 -579
- package/container_src/jupyter-service.ts +0 -461
- package/container_src/jupyter_config.py +0 -48
- package/dist/chunk-BEQUGUY4.js.map +0 -1
- package/dist/chunk-EGC5IYXA.js.map +0 -1
- package/dist/chunk-FKBV7CZS.js.map +0 -1
- package/dist/chunk-LALY4SFU.js.map +0 -1
- package/dist/chunk-LFLJGISB.js.map +0 -1
- package/dist/jupyter-client.d.ts +0 -4
- package/dist/jupyter-client.js +0 -9
- /package/dist/{jupyter-client.js.map → interpreter-client.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cloudflare/sandbox",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/cloudflare/sandbox-sdk"
|
|
7
7
|
},
|
|
8
8
|
"description": "A sandboxed environment for running commands",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@cloudflare/containers": "^0.0.
|
|
10
|
+
"@cloudflare/containers": "^0.0.28"
|
|
11
11
|
},
|
|
12
12
|
"tags": [
|
|
13
13
|
"sandbox",
|
package/src/errors.ts
CHANGED
|
@@ -23,17 +23,17 @@ export class SandboxError extends Error {
|
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
|
-
* Error thrown when
|
|
26
|
+
* Error thrown when interpreter functionality is requested but the service is still initializing.
|
|
27
27
|
*
|
|
28
|
-
* Note: With the current implementation, requests wait for
|
|
28
|
+
* Note: With the current implementation, requests wait for interpreter to be ready.
|
|
29
29
|
* This error is only thrown when:
|
|
30
|
-
* 1. The request times out waiting for
|
|
31
|
-
* 2.
|
|
30
|
+
* 1. The request times out waiting for interpreter (default: 30 seconds)
|
|
31
|
+
* 2. interpreter initialization actually fails
|
|
32
32
|
*
|
|
33
33
|
* Most requests will succeed after a delay, not throw this error.
|
|
34
34
|
*/
|
|
35
|
-
export class
|
|
36
|
-
public readonly code = "
|
|
35
|
+
export class InterpreterNotReadyError extends SandboxError {
|
|
36
|
+
public readonly code = "INTERPRETER_NOT_READY";
|
|
37
37
|
public readonly retryAfter: number;
|
|
38
38
|
public readonly progress?: number;
|
|
39
39
|
|
|
@@ -42,7 +42,8 @@ export class JupyterNotReadyError extends SandboxError {
|
|
|
42
42
|
options?: { retryAfter?: number; progress?: number }
|
|
43
43
|
) {
|
|
44
44
|
super(
|
|
45
|
-
message ||
|
|
45
|
+
message ||
|
|
46
|
+
"Interpreter is still initializing. Please retry in a few seconds."
|
|
46
47
|
);
|
|
47
48
|
this.retryAfter = options?.retryAfter || 5;
|
|
48
49
|
this.progress = options?.progress;
|
|
@@ -123,12 +124,12 @@ export class ServiceUnavailableError extends SandboxError {
|
|
|
123
124
|
}
|
|
124
125
|
|
|
125
126
|
/**
|
|
126
|
-
* Type guard to check if an error is a
|
|
127
|
+
* Type guard to check if an error is a InterpreterNotReadyError
|
|
127
128
|
*/
|
|
128
|
-
export function
|
|
129
|
+
export function isInterpreterNotReadyError(
|
|
129
130
|
error: unknown
|
|
130
|
-
): error is
|
|
131
|
-
return error instanceof
|
|
131
|
+
): error is InterpreterNotReadyError {
|
|
132
|
+
return error instanceof InterpreterNotReadyError;
|
|
132
133
|
}
|
|
133
134
|
|
|
134
135
|
/**
|
|
@@ -143,7 +144,7 @@ export function isSandboxError(error: unknown): error is SandboxError {
|
|
|
143
144
|
*/
|
|
144
145
|
export function isRetryableError(error: unknown): boolean {
|
|
145
146
|
if (
|
|
146
|
-
error instanceof
|
|
147
|
+
error instanceof InterpreterNotReadyError ||
|
|
147
148
|
error instanceof ContainerNotReadyError ||
|
|
148
149
|
error instanceof ServiceUnavailableError
|
|
149
150
|
) {
|
|
@@ -189,9 +190,9 @@ export async function parseErrorResponse(
|
|
|
189
190
|
);
|
|
190
191
|
}
|
|
191
192
|
|
|
192
|
-
//
|
|
193
|
+
// Interpreter initialization error
|
|
193
194
|
if (data.status === "initializing") {
|
|
194
|
-
return new
|
|
195
|
+
return new InterpreterNotReadyError(data.error, {
|
|
195
196
|
retryAfter: parseInt(response.headers.get("Retry-After") || "5"),
|
|
196
197
|
progress: data.progress,
|
|
197
198
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,20 +1,31 @@
|
|
|
1
|
-
//
|
|
1
|
+
// biome-ignore-start assist/source/organizeImports: Need separate exports for deprecation warnings to work properly
|
|
2
|
+
/**
|
|
3
|
+
* @deprecated Use `InterpreterNotReadyError` instead. Will be removed in a future version.
|
|
4
|
+
*/
|
|
5
|
+
export { InterpreterNotReadyError as JupyterNotReadyError } from "./errors";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @deprecated Use `isInterpreterNotReadyError` instead. Will be removed in a future version.
|
|
9
|
+
*/
|
|
10
|
+
export { isInterpreterNotReadyError as isJupyterNotReadyError } from "./errors";
|
|
11
|
+
// biome-ignore-end assist/source/organizeImports: Need separate exports for deprecation warnings to work properly
|
|
2
12
|
|
|
3
|
-
// Export
|
|
13
|
+
// Export API response types
|
|
4
14
|
export {
|
|
5
15
|
CodeExecutionError,
|
|
6
16
|
ContainerNotReadyError,
|
|
7
17
|
ContextNotFoundError,
|
|
8
|
-
|
|
18
|
+
InterpreterNotReadyError,
|
|
19
|
+
isInterpreterNotReadyError,
|
|
9
20
|
isRetryableError,
|
|
10
21
|
isSandboxError,
|
|
11
|
-
JupyterNotReadyError,
|
|
12
22
|
parseErrorResponse,
|
|
13
23
|
SandboxError,
|
|
14
24
|
type SandboxErrorResponse,
|
|
15
25
|
SandboxNetworkError,
|
|
16
26
|
ServiceUnavailableError,
|
|
17
27
|
} from "./errors";
|
|
28
|
+
|
|
18
29
|
// Export code interpreter types
|
|
19
30
|
export type {
|
|
20
31
|
ChartData,
|
|
@@ -60,5 +71,5 @@ export type {
|
|
|
60
71
|
ReadFileResponse,
|
|
61
72
|
RenameFileResponse,
|
|
62
73
|
StreamOptions,
|
|
63
|
-
WriteFileResponse
|
|
74
|
+
WriteFileResponse,
|
|
64
75
|
} from "./types";
|
|
@@ -62,7 +62,7 @@ export interface ExecutionCallbacks {
|
|
|
62
62
|
onError?: (error: ExecutionError) => void | Promise<void>;
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
export class
|
|
65
|
+
export class InterpreterClient extends HttpClient {
|
|
66
66
|
private readonly maxRetries = 3;
|
|
67
67
|
private readonly retryDelayMs = 1000;
|
|
68
68
|
|
|
@@ -239,7 +239,10 @@ export class JupyterClient extends HttpClient {
|
|
|
239
239
|
break;
|
|
240
240
|
}
|
|
241
241
|
} catch (error) {
|
|
242
|
-
console.error(
|
|
242
|
+
console.error(
|
|
243
|
+
"[InterpreterClient] Error parsing execution result:",
|
|
244
|
+
error
|
|
245
|
+
);
|
|
243
246
|
}
|
|
244
247
|
}
|
|
245
248
|
|
|
@@ -295,7 +298,7 @@ export class JupyterClient extends HttpClient {
|
|
|
295
298
|
} catch (error) {
|
|
296
299
|
lastError = error as Error;
|
|
297
300
|
|
|
298
|
-
// Check if it's a retryable error (circuit breaker or
|
|
301
|
+
// Check if it's a retryable error (circuit breaker or interpreter not ready)
|
|
299
302
|
if (this.isRetryableError(error)) {
|
|
300
303
|
// Don't retry on the last attempt
|
|
301
304
|
if (attempt < this.maxRetries - 1) {
|
package/src/interpreter-types.ts
CHANGED
|
@@ -4,19 +4,19 @@ export interface CreateContextOptions {
|
|
|
4
4
|
* Programming language for the context
|
|
5
5
|
* @default 'python'
|
|
6
6
|
*/
|
|
7
|
-
language?:
|
|
8
|
-
|
|
7
|
+
language?: "python" | "javascript" | "typescript";
|
|
8
|
+
|
|
9
9
|
/**
|
|
10
10
|
* Working directory for the context
|
|
11
11
|
* @default '/workspace'
|
|
12
12
|
*/
|
|
13
13
|
cwd?: string;
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
/**
|
|
16
16
|
* Environment variables for the context
|
|
17
17
|
*/
|
|
18
18
|
envVars?: Record<string, string>;
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
/**
|
|
21
21
|
* Request timeout in milliseconds
|
|
22
22
|
* @default 30000
|
|
@@ -29,22 +29,22 @@ export interface CodeContext {
|
|
|
29
29
|
* Unique identifier for the context
|
|
30
30
|
*/
|
|
31
31
|
readonly id: string;
|
|
32
|
-
|
|
32
|
+
|
|
33
33
|
/**
|
|
34
34
|
* Programming language of the context
|
|
35
35
|
*/
|
|
36
36
|
readonly language: string;
|
|
37
|
-
|
|
37
|
+
|
|
38
38
|
/**
|
|
39
39
|
* Current working directory
|
|
40
40
|
*/
|
|
41
41
|
readonly cwd: string;
|
|
42
|
-
|
|
42
|
+
|
|
43
43
|
/**
|
|
44
44
|
* When the context was created
|
|
45
45
|
*/
|
|
46
46
|
readonly createdAt: Date;
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
/**
|
|
49
49
|
* When the context was last used
|
|
50
50
|
*/
|
|
@@ -57,44 +57,44 @@ export interface RunCodeOptions {
|
|
|
57
57
|
* Context to run the code in. If not provided, uses default context for the language
|
|
58
58
|
*/
|
|
59
59
|
context?: CodeContext;
|
|
60
|
-
|
|
60
|
+
|
|
61
61
|
/**
|
|
62
62
|
* Language to use if context is not provided
|
|
63
63
|
* @default 'python'
|
|
64
64
|
*/
|
|
65
|
-
language?:
|
|
66
|
-
|
|
65
|
+
language?: "python" | "javascript" | "typescript";
|
|
66
|
+
|
|
67
67
|
/**
|
|
68
68
|
* Environment variables for this execution
|
|
69
69
|
*/
|
|
70
70
|
envVars?: Record<string, string>;
|
|
71
|
-
|
|
71
|
+
|
|
72
72
|
/**
|
|
73
73
|
* Execution timeout in milliseconds
|
|
74
74
|
* @default 60000
|
|
75
75
|
*/
|
|
76
76
|
timeout?: number;
|
|
77
|
-
|
|
77
|
+
|
|
78
78
|
/**
|
|
79
79
|
* AbortSignal for cancelling execution
|
|
80
80
|
*/
|
|
81
81
|
signal?: AbortSignal;
|
|
82
|
-
|
|
82
|
+
|
|
83
83
|
/**
|
|
84
84
|
* Callback for stdout output
|
|
85
85
|
*/
|
|
86
86
|
onStdout?: (output: OutputMessage) => void | Promise<void>;
|
|
87
|
-
|
|
87
|
+
|
|
88
88
|
/**
|
|
89
89
|
* Callback for stderr output
|
|
90
90
|
*/
|
|
91
91
|
onStderr?: (output: OutputMessage) => void | Promise<void>;
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
/**
|
|
94
94
|
* Callback for execution results (charts, tables, etc)
|
|
95
95
|
*/
|
|
96
96
|
onResult?: (result: Result) => void | Promise<void>;
|
|
97
|
-
|
|
97
|
+
|
|
98
98
|
/**
|
|
99
99
|
* Callback for execution errors
|
|
100
100
|
*/
|
|
@@ -107,7 +107,7 @@ export interface OutputMessage {
|
|
|
107
107
|
* The output text
|
|
108
108
|
*/
|
|
109
109
|
text: string;
|
|
110
|
-
|
|
110
|
+
|
|
111
111
|
/**
|
|
112
112
|
* Timestamp of the output
|
|
113
113
|
*/
|
|
@@ -120,57 +120,57 @@ export interface Result {
|
|
|
120
120
|
* Plain text representation
|
|
121
121
|
*/
|
|
122
122
|
text?: string;
|
|
123
|
-
|
|
123
|
+
|
|
124
124
|
/**
|
|
125
125
|
* HTML representation (tables, formatted output)
|
|
126
126
|
*/
|
|
127
127
|
html?: string;
|
|
128
|
-
|
|
128
|
+
|
|
129
129
|
/**
|
|
130
130
|
* PNG image data (base64 encoded)
|
|
131
131
|
*/
|
|
132
132
|
png?: string;
|
|
133
|
-
|
|
133
|
+
|
|
134
134
|
/**
|
|
135
135
|
* JPEG image data (base64 encoded)
|
|
136
136
|
*/
|
|
137
137
|
jpeg?: string;
|
|
138
|
-
|
|
138
|
+
|
|
139
139
|
/**
|
|
140
140
|
* SVG image data
|
|
141
141
|
*/
|
|
142
142
|
svg?: string;
|
|
143
|
-
|
|
143
|
+
|
|
144
144
|
/**
|
|
145
145
|
* LaTeX representation
|
|
146
146
|
*/
|
|
147
147
|
latex?: string;
|
|
148
|
-
|
|
148
|
+
|
|
149
149
|
/**
|
|
150
150
|
* Markdown representation
|
|
151
151
|
*/
|
|
152
152
|
markdown?: string;
|
|
153
|
-
|
|
153
|
+
|
|
154
154
|
/**
|
|
155
155
|
* JavaScript code to execute
|
|
156
156
|
*/
|
|
157
157
|
javascript?: string;
|
|
158
|
-
|
|
158
|
+
|
|
159
159
|
/**
|
|
160
160
|
* JSON data
|
|
161
161
|
*/
|
|
162
162
|
json?: any;
|
|
163
|
-
|
|
163
|
+
|
|
164
164
|
/**
|
|
165
165
|
* Chart data if the result is a visualization
|
|
166
166
|
*/
|
|
167
167
|
chart?: ChartData;
|
|
168
|
-
|
|
168
|
+
|
|
169
169
|
/**
|
|
170
170
|
* Raw data object
|
|
171
171
|
*/
|
|
172
172
|
data?: any;
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
/**
|
|
175
175
|
* Available output formats
|
|
176
176
|
*/
|
|
@@ -182,33 +182,40 @@ export interface ChartData {
|
|
|
182
182
|
/**
|
|
183
183
|
* Type of chart
|
|
184
184
|
*/
|
|
185
|
-
type:
|
|
186
|
-
|
|
185
|
+
type:
|
|
186
|
+
| "line"
|
|
187
|
+
| "bar"
|
|
188
|
+
| "scatter"
|
|
189
|
+
| "pie"
|
|
190
|
+
| "histogram"
|
|
191
|
+
| "heatmap"
|
|
192
|
+
| "unknown";
|
|
193
|
+
|
|
187
194
|
/**
|
|
188
195
|
* Chart title
|
|
189
196
|
*/
|
|
190
197
|
title?: string;
|
|
191
|
-
|
|
198
|
+
|
|
192
199
|
/**
|
|
193
200
|
* Chart data (format depends on library)
|
|
194
201
|
*/
|
|
195
202
|
data: any;
|
|
196
|
-
|
|
203
|
+
|
|
197
204
|
/**
|
|
198
205
|
* Chart layout/configuration
|
|
199
206
|
*/
|
|
200
207
|
layout?: any;
|
|
201
|
-
|
|
208
|
+
|
|
202
209
|
/**
|
|
203
210
|
* Additional configuration
|
|
204
211
|
*/
|
|
205
212
|
config?: any;
|
|
206
|
-
|
|
213
|
+
|
|
207
214
|
/**
|
|
208
215
|
* Library that generated the chart
|
|
209
216
|
*/
|
|
210
|
-
library?:
|
|
211
|
-
|
|
217
|
+
library?: "matplotlib" | "plotly" | "altair" | "seaborn" | "unknown";
|
|
218
|
+
|
|
212
219
|
/**
|
|
213
220
|
* Base64 encoded image if available
|
|
214
221
|
*/
|
|
@@ -221,17 +228,17 @@ export interface ExecutionError {
|
|
|
221
228
|
* Error name/type (e.g., 'NameError', 'SyntaxError')
|
|
222
229
|
*/
|
|
223
230
|
name: string;
|
|
224
|
-
|
|
231
|
+
|
|
225
232
|
/**
|
|
226
233
|
* Error message
|
|
227
234
|
*/
|
|
228
235
|
value: string;
|
|
229
|
-
|
|
236
|
+
|
|
230
237
|
/**
|
|
231
238
|
* Stack trace
|
|
232
239
|
*/
|
|
233
240
|
traceback: string[];
|
|
234
|
-
|
|
241
|
+
|
|
235
242
|
/**
|
|
236
243
|
* Line number where error occurred
|
|
237
244
|
*/
|
|
@@ -268,30 +275,30 @@ export class Execution {
|
|
|
268
275
|
* All results from the execution
|
|
269
276
|
*/
|
|
270
277
|
public results: Result[] = [];
|
|
271
|
-
|
|
278
|
+
|
|
272
279
|
/**
|
|
273
280
|
* Accumulated stdout and stderr
|
|
274
281
|
*/
|
|
275
282
|
public logs = {
|
|
276
283
|
stdout: [] as string[],
|
|
277
|
-
stderr: [] as string[]
|
|
284
|
+
stderr: [] as string[],
|
|
278
285
|
};
|
|
279
|
-
|
|
286
|
+
|
|
280
287
|
/**
|
|
281
288
|
* Execution error if any
|
|
282
289
|
*/
|
|
283
290
|
public error?: ExecutionError;
|
|
284
|
-
|
|
291
|
+
|
|
285
292
|
/**
|
|
286
|
-
* Execution count (for
|
|
293
|
+
* Execution count (for interpreter)
|
|
287
294
|
*/
|
|
288
295
|
public executionCount?: number;
|
|
289
|
-
|
|
296
|
+
|
|
290
297
|
constructor(
|
|
291
298
|
public readonly code: string,
|
|
292
299
|
public readonly context: CodeContext
|
|
293
300
|
) {}
|
|
294
|
-
|
|
301
|
+
|
|
295
302
|
/**
|
|
296
303
|
* Convert to a plain object for serialization
|
|
297
304
|
*/
|
|
@@ -301,7 +308,7 @@ export class Execution {
|
|
|
301
308
|
logs: this.logs,
|
|
302
309
|
error: this.error,
|
|
303
310
|
executionCount: this.executionCount,
|
|
304
|
-
results: this.results.map(result => ({
|
|
311
|
+
results: this.results.map((result) => ({
|
|
305
312
|
text: result.text,
|
|
306
313
|
html: result.html,
|
|
307
314
|
png: result.png,
|
|
@@ -312,8 +319,8 @@ export class Execution {
|
|
|
312
319
|
javascript: result.javascript,
|
|
313
320
|
json: result.json,
|
|
314
321
|
chart: result.chart,
|
|
315
|
-
data: result.data
|
|
316
|
-
}))
|
|
322
|
+
data: result.data,
|
|
323
|
+
})),
|
|
317
324
|
};
|
|
318
325
|
}
|
|
319
326
|
}
|
|
@@ -321,63 +328,63 @@ export class Execution {
|
|
|
321
328
|
// Implementation of Result
|
|
322
329
|
export class ResultImpl implements Result {
|
|
323
330
|
constructor(private raw: any) {}
|
|
324
|
-
|
|
325
|
-
get text(): string | undefined {
|
|
326
|
-
return this.raw.text || this.raw.data?.[
|
|
331
|
+
|
|
332
|
+
get text(): string | undefined {
|
|
333
|
+
return this.raw.text || this.raw.data?.["text/plain"];
|
|
327
334
|
}
|
|
328
|
-
|
|
329
|
-
get html(): string | undefined {
|
|
330
|
-
return this.raw.html || this.raw.data?.[
|
|
335
|
+
|
|
336
|
+
get html(): string | undefined {
|
|
337
|
+
return this.raw.html || this.raw.data?.["text/html"];
|
|
331
338
|
}
|
|
332
|
-
|
|
333
|
-
get png(): string | undefined {
|
|
334
|
-
return this.raw.png || this.raw.data?.[
|
|
339
|
+
|
|
340
|
+
get png(): string | undefined {
|
|
341
|
+
return this.raw.png || this.raw.data?.["image/png"];
|
|
335
342
|
}
|
|
336
|
-
|
|
337
|
-
get jpeg(): string | undefined {
|
|
338
|
-
return this.raw.jpeg || this.raw.data?.[
|
|
343
|
+
|
|
344
|
+
get jpeg(): string | undefined {
|
|
345
|
+
return this.raw.jpeg || this.raw.data?.["image/jpeg"];
|
|
339
346
|
}
|
|
340
|
-
|
|
341
|
-
get svg(): string | undefined {
|
|
342
|
-
return this.raw.svg || this.raw.data?.[
|
|
347
|
+
|
|
348
|
+
get svg(): string | undefined {
|
|
349
|
+
return this.raw.svg || this.raw.data?.["image/svg+xml"];
|
|
343
350
|
}
|
|
344
|
-
|
|
345
|
-
get latex(): string | undefined {
|
|
346
|
-
return this.raw.latex || this.raw.data?.[
|
|
351
|
+
|
|
352
|
+
get latex(): string | undefined {
|
|
353
|
+
return this.raw.latex || this.raw.data?.["text/latex"];
|
|
347
354
|
}
|
|
348
|
-
|
|
349
|
-
get markdown(): string | undefined {
|
|
350
|
-
return this.raw.markdown || this.raw.data?.[
|
|
355
|
+
|
|
356
|
+
get markdown(): string | undefined {
|
|
357
|
+
return this.raw.markdown || this.raw.data?.["text/markdown"];
|
|
351
358
|
}
|
|
352
|
-
|
|
353
|
-
get javascript(): string | undefined {
|
|
354
|
-
return this.raw.javascript || this.raw.data?.[
|
|
359
|
+
|
|
360
|
+
get javascript(): string | undefined {
|
|
361
|
+
return this.raw.javascript || this.raw.data?.["application/javascript"];
|
|
355
362
|
}
|
|
356
|
-
|
|
357
|
-
get json(): any {
|
|
358
|
-
return this.raw.json || this.raw.data?.[
|
|
363
|
+
|
|
364
|
+
get json(): any {
|
|
365
|
+
return this.raw.json || this.raw.data?.["application/json"];
|
|
359
366
|
}
|
|
360
|
-
|
|
361
|
-
get chart(): ChartData | undefined {
|
|
362
|
-
return this.raw.chart;
|
|
367
|
+
|
|
368
|
+
get chart(): ChartData | undefined {
|
|
369
|
+
return this.raw.chart;
|
|
363
370
|
}
|
|
364
|
-
|
|
365
|
-
get data(): any {
|
|
366
|
-
return this.raw.data;
|
|
371
|
+
|
|
372
|
+
get data(): any {
|
|
373
|
+
return this.raw.data;
|
|
367
374
|
}
|
|
368
|
-
|
|
375
|
+
|
|
369
376
|
formats(): string[] {
|
|
370
377
|
const formats: string[] = [];
|
|
371
|
-
if (this.text) formats.push(
|
|
372
|
-
if (this.html) formats.push(
|
|
373
|
-
if (this.png) formats.push(
|
|
374
|
-
if (this.jpeg) formats.push(
|
|
375
|
-
if (this.svg) formats.push(
|
|
376
|
-
if (this.latex) formats.push(
|
|
377
|
-
if (this.markdown) formats.push(
|
|
378
|
-
if (this.javascript) formats.push(
|
|
379
|
-
if (this.json) formats.push(
|
|
380
|
-
if (this.chart) formats.push(
|
|
378
|
+
if (this.text) formats.push("text");
|
|
379
|
+
if (this.html) formats.push("html");
|
|
380
|
+
if (this.png) formats.push("png");
|
|
381
|
+
if (this.jpeg) formats.push("jpeg");
|
|
382
|
+
if (this.svg) formats.push("svg");
|
|
383
|
+
if (this.latex) formats.push("latex");
|
|
384
|
+
if (this.markdown) formats.push("markdown");
|
|
385
|
+
if (this.javascript) formats.push("javascript");
|
|
386
|
+
if (this.json) formats.push("json");
|
|
387
|
+
if (this.chart) formats.push("chart");
|
|
381
388
|
return formats;
|
|
382
389
|
}
|
|
383
|
-
}
|
|
390
|
+
}
|
package/src/interpreter.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { InterpreterClient } from "./interpreter-client.js";
|
|
1
2
|
import {
|
|
2
3
|
type CodeContext,
|
|
3
4
|
type CreateContextOptions,
|
|
@@ -5,15 +6,14 @@ import {
|
|
|
5
6
|
ResultImpl,
|
|
6
7
|
type RunCodeOptions,
|
|
7
8
|
} from "./interpreter-types.js";
|
|
8
|
-
import type { JupyterClient } from "./jupyter-client.js";
|
|
9
9
|
import type { Sandbox } from "./sandbox.js";
|
|
10
10
|
|
|
11
11
|
export class CodeInterpreter {
|
|
12
|
-
private
|
|
12
|
+
private interpreterClient: InterpreterClient;
|
|
13
13
|
private contexts = new Map<string, CodeContext>();
|
|
14
14
|
|
|
15
15
|
constructor(sandbox: Sandbox) {
|
|
16
|
-
this.
|
|
16
|
+
this.interpreterClient = sandbox.client as InterpreterClient;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
/**
|
|
@@ -22,7 +22,7 @@ export class CodeInterpreter {
|
|
|
22
22
|
async createCodeContext(
|
|
23
23
|
options: CreateContextOptions = {}
|
|
24
24
|
): Promise<CodeContext> {
|
|
25
|
-
const context = await this.
|
|
25
|
+
const context = await this.interpreterClient.createCodeContext(options);
|
|
26
26
|
this.contexts.set(context.id, context);
|
|
27
27
|
return context;
|
|
28
28
|
}
|
|
@@ -46,7 +46,7 @@ export class CodeInterpreter {
|
|
|
46
46
|
const execution = new Execution(code, context);
|
|
47
47
|
|
|
48
48
|
// Stream execution
|
|
49
|
-
await this.
|
|
49
|
+
await this.interpreterClient.runCodeStream(context.id, code, options.language, {
|
|
50
50
|
onStdout: (output) => {
|
|
51
51
|
execution.logs.stdout.push(output.text);
|
|
52
52
|
if (options.onStdout) return options.onStdout(output);
|
|
@@ -83,7 +83,7 @@ export class CodeInterpreter {
|
|
|
83
83
|
}
|
|
84
84
|
|
|
85
85
|
// Create streaming response
|
|
86
|
-
const response = await this.
|
|
86
|
+
const response = await this.interpreterClient.doFetch("/api/execute/code", {
|
|
87
87
|
method: "POST",
|
|
88
88
|
headers: {
|
|
89
89
|
"Content-Type": "application/json",
|
|
@@ -116,7 +116,7 @@ export class CodeInterpreter {
|
|
|
116
116
|
* List all code contexts
|
|
117
117
|
*/
|
|
118
118
|
async listCodeContexts(): Promise<CodeContext[]> {
|
|
119
|
-
const contexts = await this.
|
|
119
|
+
const contexts = await this.interpreterClient.listCodeContexts();
|
|
120
120
|
|
|
121
121
|
// Update local cache
|
|
122
122
|
for (const context of contexts) {
|
|
@@ -130,7 +130,7 @@ export class CodeInterpreter {
|
|
|
130
130
|
* Delete a code context
|
|
131
131
|
*/
|
|
132
132
|
async deleteCodeContext(contextId: string): Promise<void> {
|
|
133
|
-
await this.
|
|
133
|
+
await this.interpreterClient.deleteCodeContext(contextId);
|
|
134
134
|
this.contexts.delete(contextId);
|
|
135
135
|
}
|
|
136
136
|
|
package/src/sandbox.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { Container, getContainer } from "@cloudflare/containers";
|
|
2
2
|
import { CodeInterpreter } from "./interpreter";
|
|
3
|
+
import { InterpreterClient } from "./interpreter-client";
|
|
3
4
|
import type {
|
|
4
5
|
CodeContext,
|
|
5
6
|
CreateContextOptions,
|
|
6
7
|
ExecutionResult,
|
|
7
8
|
RunCodeOptions,
|
|
8
9
|
} from "./interpreter-types";
|
|
9
|
-
import { JupyterClient } from "./jupyter-client";
|
|
10
10
|
import { isLocalhostPattern } from "./request-handler";
|
|
11
11
|
import {
|
|
12
12
|
logSecurityEvent,
|
|
@@ -41,14 +41,14 @@ export function getSandbox(ns: DurableObjectNamespace<Sandbox>, id: string) {
|
|
|
41
41
|
export class Sandbox<Env = unknown> extends Container<Env> implements ISandbox {
|
|
42
42
|
defaultPort = 3000; // Default port for the container's Bun server
|
|
43
43
|
sleepAfter = "20m"; // Keep container warm for 20 minutes to avoid cold starts
|
|
44
|
-
client:
|
|
44
|
+
client: InterpreterClient;
|
|
45
45
|
private sandboxName: string | null = null;
|
|
46
46
|
private codeInterpreter: CodeInterpreter;
|
|
47
47
|
private defaultSession: ExecutionSession | null = null;
|
|
48
48
|
|
|
49
49
|
constructor(ctx: DurableObjectState, env: Env) {
|
|
50
50
|
super(ctx, env);
|
|
51
|
-
this.client = new
|
|
51
|
+
this.client = new InterpreterClient({
|
|
52
52
|
onCommandComplete: (success, exitCode, _stdout, _stderr, command) => {
|
|
53
53
|
console.log(
|
|
54
54
|
`[Container] Command completed: ${command}, Success: ${success}, Exit code: ${exitCode}`
|