@blaxel/core 0.2.49-preview.110 → 0.2.49-preview.112

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 (33) hide show
  1. package/dist/cjs/.tsbuildinfo +1 -1
  2. package/dist/cjs/client/sdk.gen.js +143 -3
  3. package/dist/cjs/common/settings.js +2 -2
  4. package/dist/cjs/sandbox/index.js +1 -0
  5. package/dist/cjs/sandbox/interpreter.js +400 -0
  6. package/dist/cjs/tools/mcpTool.js +0 -4
  7. package/dist/cjs/types/client/sdk.gen.d.ts +41 -1
  8. package/dist/cjs/types/client/types.gen.d.ts +599 -16
  9. package/dist/cjs/types/sandbox/index.d.ts +1 -0
  10. package/dist/cjs/types/sandbox/interpreter.d.ts +71 -0
  11. package/dist/cjs-browser/.tsbuildinfo +1 -1
  12. package/dist/cjs-browser/client/sdk.gen.js +143 -3
  13. package/dist/cjs-browser/common/settings.js +2 -2
  14. package/dist/cjs-browser/sandbox/index.js +1 -0
  15. package/dist/cjs-browser/sandbox/interpreter.js +400 -0
  16. package/dist/cjs-browser/tools/mcpTool.js +0 -4
  17. package/dist/cjs-browser/types/client/sdk.gen.d.ts +41 -1
  18. package/dist/cjs-browser/types/client/types.gen.d.ts +599 -16
  19. package/dist/cjs-browser/types/sandbox/index.d.ts +1 -0
  20. package/dist/cjs-browser/types/sandbox/interpreter.d.ts +71 -0
  21. package/dist/esm/.tsbuildinfo +1 -1
  22. package/dist/esm/client/sdk.gen.js +132 -0
  23. package/dist/esm/common/settings.js +2 -2
  24. package/dist/esm/sandbox/index.js +1 -0
  25. package/dist/esm/sandbox/interpreter.js +396 -0
  26. package/dist/esm/tools/mcpTool.js +0 -4
  27. package/dist/esm-browser/.tsbuildinfo +1 -1
  28. package/dist/esm-browser/client/sdk.gen.js +132 -0
  29. package/dist/esm-browser/common/settings.js +2 -2
  30. package/dist/esm-browser/sandbox/index.js +1 -0
  31. package/dist/esm-browser/sandbox/interpreter.js +396 -0
  32. package/dist/esm-browser/tools/mcpTool.js +0 -4
  33. package/package.json +2 -2
@@ -310,6 +310,70 @@ export const listFunctionRevisions = (options) => {
310
310
  ...options
311
311
  });
312
312
  };
313
+ /**
314
+ * List images
315
+ * Returns a list of all images in the workspace grouped by repository with tags.
316
+ */
317
+ export const listImages = (options) => {
318
+ return (options?.client ?? _heyApiClient).get({
319
+ security: [
320
+ {
321
+ scheme: 'bearer',
322
+ type: 'http'
323
+ }
324
+ ],
325
+ url: '/images',
326
+ ...options
327
+ });
328
+ };
329
+ /**
330
+ * Delete image by name
331
+ * Deletes an image by name.
332
+ */
333
+ export const deleteImage = (options) => {
334
+ return (options.client ?? _heyApiClient).delete({
335
+ security: [
336
+ {
337
+ scheme: 'bearer',
338
+ type: 'http'
339
+ }
340
+ ],
341
+ url: '/images/{resourceType}/{imageName}',
342
+ ...options
343
+ });
344
+ };
345
+ /**
346
+ * Get image by name
347
+ * Returns an image by name.
348
+ */
349
+ export const getImage = (options) => {
350
+ return (options.client ?? _heyApiClient).get({
351
+ security: [
352
+ {
353
+ scheme: 'bearer',
354
+ type: 'http'
355
+ }
356
+ ],
357
+ url: '/images/{resourceType}/{imageName}',
358
+ ...options
359
+ });
360
+ };
361
+ /**
362
+ * Delete image tag
363
+ * Deletes a specific tag from an image.
364
+ */
365
+ export const deleteImageTag = (options) => {
366
+ return (options.client ?? _heyApiClient).delete({
367
+ security: [
368
+ {
369
+ scheme: 'bearer',
370
+ type: 'http'
371
+ }
372
+ ],
373
+ url: '/images/{resourceType}/{imageName}/tags/{tagName}',
374
+ ...options
375
+ });
376
+ };
313
377
  /**
314
378
  * List integrations connections
315
379
  * Returns integration information by name.
@@ -550,6 +614,74 @@ export const updateJob = (options) => {
550
614
  }
551
615
  });
552
616
  };
617
+ /**
618
+ * List job executions
619
+ * Returns a list of all executions for a job by name.
620
+ */
621
+ export const listJobExecutions = (options) => {
622
+ return (options.client ?? _heyApiClient).get({
623
+ security: [
624
+ {
625
+ scheme: 'bearer',
626
+ type: 'http'
627
+ }
628
+ ],
629
+ url: '/jobs/{jobId}/executions',
630
+ ...options
631
+ });
632
+ };
633
+ /**
634
+ * Create job execution
635
+ * Creates a new execution for a job by name.
636
+ */
637
+ export const createJobExecution = (options) => {
638
+ return (options.client ?? _heyApiClient).post({
639
+ security: [
640
+ {
641
+ scheme: 'bearer',
642
+ type: 'http'
643
+ }
644
+ ],
645
+ url: '/jobs/{jobId}/executions',
646
+ ...options,
647
+ headers: {
648
+ 'Content-Type': 'application/json',
649
+ ...options?.headers
650
+ }
651
+ });
652
+ };
653
+ /**
654
+ * Delete job execution
655
+ * Stop an execution for a job by name.
656
+ */
657
+ export const deleteJobExecution = (options) => {
658
+ return (options.client ?? _heyApiClient).delete({
659
+ security: [
660
+ {
661
+ scheme: 'bearer',
662
+ type: 'http'
663
+ }
664
+ ],
665
+ url: '/jobs/{jobId}/executions/{executionId}',
666
+ ...options
667
+ });
668
+ };
669
+ /**
670
+ * Get job execution
671
+ * Returns an execution for a job by name.
672
+ */
673
+ export const getJobExecution = (options) => {
674
+ return (options.client ?? _heyApiClient).get({
675
+ security: [
676
+ {
677
+ scheme: 'bearer',
678
+ type: 'http'
679
+ }
680
+ ],
681
+ url: '/jobs/{jobId}/executions/{executionId}',
682
+ ...options
683
+ });
684
+ };
553
685
  /**
554
686
  * List job revisions
555
687
  * Returns revisions for a job by name.
@@ -7,7 +7,7 @@ function getPackageVersion() {
7
7
  if (typeof require !== "undefined") {
8
8
  // Try to require package.json (Node.js only, gracefully fails in browser)
9
9
  // eslint-disable-next-line @typescript-eslint/no-require-imports
10
- const packageJson = {"version":"0.2.49-preview.110","commit":"8ae9567ca2664beae414afa4fd53190d8ccf4250"};
10
+ const packageJson = {"version":"0.2.49-preview.112","commit":"d50dddc5a1963abd22bad3b294e9f6096c3e8287"};
11
11
  return packageJson.version || "unknown";
12
12
  }
13
13
  else {
@@ -59,7 +59,7 @@ function getCommitHash() {
59
59
  if (typeof require !== "undefined") {
60
60
  // Try to require package.json and look for commit field (set during build)
61
61
  // eslint-disable-next-line @typescript-eslint/no-require-imports
62
- const packageJson = {"version":"0.2.49-preview.110","commit":"8ae9567ca2664beae414afa4fd53190d8ccf4250"};
62
+ const packageJson = {"version":"0.2.49-preview.112","commit":"d50dddc5a1963abd22bad3b294e9f6096c3e8287"};
63
63
  // Check for commit in various possible locations
64
64
  const commit = packageJson.commit || packageJson.buildInfo?.commit;
65
65
  if (commit) {
@@ -5,4 +5,5 @@ export * from "./filesystem/index.js";
5
5
  export * from "./codegen/index.js";
6
6
  export * from "./sandbox.js";
7
7
  export * from "./types.js";
8
+ export * from "./interpreter.js";
8
9
  // Re-export everything from client except ClientOptions to avoid conflict
@@ -0,0 +1,396 @@
1
+ import { logger } from "../common/logger.js";
2
+ import { settings } from "../common/settings.js";
3
+ import { SandboxInstance } from "./sandbox.js";
4
+ export class CodeInterpreter extends SandboxInstance {
5
+ static DEFAULT_IMAGE = "blaxel/jupyter-server";
6
+ static DEFAULT_PORTS = [
7
+ { name: "jupyter", target: 8888, protocol: "HTTP" },
8
+ ];
9
+ static DEFAULT_LIFECYCLE = {
10
+ expirationPolicies: [{ type: "ttl-idle", value: "30m", action: "delete" }],
11
+ };
12
+ _sandboxConfig;
13
+ constructor(sandbox) {
14
+ super(sandbox);
15
+ this._sandboxConfig = sandbox;
16
+ }
17
+ static async get(sandboxName) {
18
+ const base = await SandboxInstance.get(sandboxName);
19
+ // Create a minimal config - the base instance already has the sandbox data
20
+ // We'll rely on the process property for URL/headers access
21
+ const config = {
22
+ metadata: base.metadata,
23
+ spec: base.spec,
24
+ status: base.status,
25
+ events: base.events,
26
+ };
27
+ return new CodeInterpreter(config);
28
+ }
29
+ static async create(sandbox, { safe = true } = {}) {
30
+ const payload = {
31
+ image: CodeInterpreter.DEFAULT_IMAGE,
32
+ ports: CodeInterpreter.DEFAULT_PORTS,
33
+ lifecycle: CodeInterpreter.DEFAULT_LIFECYCLE,
34
+ };
35
+ const allowedCopyKeys = new Set(["name", "envs", "memory", "region", "headers"]);
36
+ if (sandbox && typeof sandbox === "object") {
37
+ if (Array.isArray(sandbox)) {
38
+ // Skip arrays
39
+ }
40
+ else if ("metadata" in sandbox || "spec" in sandbox) {
41
+ // It's a Sandbox object
42
+ const sandboxObj = sandbox;
43
+ if (sandboxObj.metadata?.name) {
44
+ payload["name"] = sandboxObj.metadata.name;
45
+ }
46
+ if (sandboxObj.spec?.runtime) {
47
+ if (sandboxObj.spec.runtime.envs) {
48
+ payload["envs"] = sandboxObj.spec.runtime.envs;
49
+ }
50
+ if (sandboxObj.spec.runtime.memory) {
51
+ payload["memory"] = sandboxObj.spec.runtime.memory;
52
+ }
53
+ }
54
+ if (sandboxObj.spec?.region) {
55
+ payload["region"] = sandboxObj.spec.region;
56
+ }
57
+ }
58
+ else if ("name" in sandbox || "image" in sandbox || "memory" in sandbox) {
59
+ // It's a SandboxCreateConfiguration or dict-like object
60
+ const sandboxDict = sandbox;
61
+ for (const k of allowedCopyKeys) {
62
+ const value = sandboxDict[k];
63
+ if (value !== null && value !== undefined) {
64
+ payload[k] = value;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ const baseInstance = await SandboxInstance.create(payload, { safe });
70
+ // Create config from the instance - preserve any forceUrl/headers if provided in input
71
+ const config = {
72
+ metadata: baseInstance.metadata,
73
+ spec: baseInstance.spec,
74
+ status: baseInstance.status,
75
+ events: baseInstance.events,
76
+ };
77
+ // Preserve forceUrl and headers from input if it was a dict-like object
78
+ if (sandbox && typeof sandbox === "object" && !Array.isArray(sandbox)) {
79
+ if ("forceUrl" in sandbox && typeof sandbox.forceUrl === "string") {
80
+ config.forceUrl = sandbox.forceUrl;
81
+ }
82
+ if ("headers" in sandbox && typeof sandbox.headers === "object") {
83
+ config.headers = sandbox.headers;
84
+ }
85
+ if ("params" in sandbox && typeof sandbox.params === "object") {
86
+ config.params = sandbox.params;
87
+ }
88
+ }
89
+ return new CodeInterpreter(config);
90
+ }
91
+ get _jupyterUrl() {
92
+ return this.process.url;
93
+ }
94
+ static OutputMessage = class {
95
+ text;
96
+ timestamp;
97
+ isStderr;
98
+ constructor(text, timestamp, isStderr) {
99
+ this.text = text;
100
+ this.timestamp = timestamp;
101
+ this.isStderr = isStderr;
102
+ }
103
+ };
104
+ static Result = class {
105
+ constructor(kwargs = {}) {
106
+ for (const [k, v] of Object.entries(kwargs)) {
107
+ this[k] = v;
108
+ }
109
+ }
110
+ };
111
+ static ExecutionError = class {
112
+ name;
113
+ value;
114
+ traceback;
115
+ constructor(name, value, traceback) {
116
+ this.name = name;
117
+ this.value = value;
118
+ this.traceback = traceback;
119
+ }
120
+ };
121
+ static Logs = class {
122
+ stdout = [];
123
+ stderr = [];
124
+ };
125
+ static Execution = class {
126
+ results = [];
127
+ logs = new CodeInterpreter.Logs();
128
+ error = null;
129
+ executionCount = null;
130
+ };
131
+ static Context = class {
132
+ id;
133
+ constructor(id) {
134
+ this.id = id;
135
+ }
136
+ static fromJson(data) {
137
+ return new CodeInterpreter.Context(String(data.id || data.context_id || ""));
138
+ }
139
+ };
140
+ _parseOutput(execution, output, onStdout, onStderr, onResult, onError) {
141
+ let data;
142
+ try {
143
+ data = JSON.parse(output);
144
+ }
145
+ catch {
146
+ // Fallback: treat as stdout text-only message
147
+ execution.logs.stdout.push(output);
148
+ if (onStdout) {
149
+ return onStdout(new CodeInterpreter.OutputMessage(output, null, false));
150
+ }
151
+ return null;
152
+ }
153
+ let dataType = "";
154
+ if (typeof data.type === "string") {
155
+ dataType = data.type;
156
+ }
157
+ else if (data.type !== null &&
158
+ data.type !== undefined &&
159
+ typeof data.type !== "object") {
160
+ const typeValue = data.type;
161
+ dataType = String(typeValue);
162
+ }
163
+ const restData = { ...data };
164
+ delete restData.type;
165
+ if (dataType === "result") {
166
+ const result = new CodeInterpreter.Result(restData);
167
+ execution.results.push(result);
168
+ if (onResult) {
169
+ return onResult(result);
170
+ }
171
+ }
172
+ else if (dataType === "stdout") {
173
+ let text = "";
174
+ if (typeof data.text === "string") {
175
+ text = data.text;
176
+ }
177
+ else if (data.text !== null &&
178
+ data.text !== undefined &&
179
+ typeof data.text !== "object") {
180
+ const textValue = data.text;
181
+ text = String(textValue);
182
+ }
183
+ execution.logs.stdout.push(text);
184
+ if (onStdout) {
185
+ return onStdout(new CodeInterpreter.OutputMessage(text, typeof data.timestamp === "number" ? data.timestamp : null, false));
186
+ }
187
+ }
188
+ else if (dataType === "stderr") {
189
+ let text = "";
190
+ if (typeof data.text === "string") {
191
+ text = data.text;
192
+ }
193
+ else if (data.text !== null &&
194
+ data.text !== undefined &&
195
+ typeof data.text !== "object") {
196
+ const textValue = data.text;
197
+ text = String(textValue);
198
+ }
199
+ execution.logs.stderr.push(text);
200
+ if (onStderr) {
201
+ return onStderr(new CodeInterpreter.OutputMessage(text, typeof data.timestamp === "number" ? data.timestamp : null, true));
202
+ }
203
+ }
204
+ else if (dataType === "error") {
205
+ let errorName = "";
206
+ if (typeof data.name === "string") {
207
+ errorName = data.name;
208
+ }
209
+ else if (data.name !== null &&
210
+ data.name !== undefined &&
211
+ typeof data.name !== "object") {
212
+ const nameValue = data.name;
213
+ errorName = String(nameValue);
214
+ }
215
+ execution.error = new CodeInterpreter.ExecutionError(errorName, data.value, data.traceback);
216
+ if (onError) {
217
+ return onError(execution.error);
218
+ }
219
+ }
220
+ else if (dataType === "number_of_executions") {
221
+ execution.executionCount =
222
+ typeof data.execution_count === "number" ? data.execution_count : null;
223
+ }
224
+ return null;
225
+ }
226
+ async runCode(code, options = {}) {
227
+ const { language = null, context = null, onStdout, onStderr, onResult, onError, envs = null, timeout = null, } = options;
228
+ const DEFAULT_TIMEOUT = 60.0;
229
+ if (language && context) {
230
+ throw new Error("You can provide context or language, but not both at the same time.");
231
+ }
232
+ const readTimeout = timeout === 0 ? null : timeout ?? DEFAULT_TIMEOUT;
233
+ const contextId = context?.id ?? null;
234
+ const body = {
235
+ code,
236
+ context_id: contextId,
237
+ language,
238
+ env_vars: envs,
239
+ };
240
+ const execution = new CodeInterpreter.Execution();
241
+ const headers = this._sandboxConfig.forceUrl
242
+ ? this._sandboxConfig.headers
243
+ : settings.headers;
244
+ const controller = new AbortController();
245
+ let timeoutId = null;
246
+ // Set up timeout
247
+ if (readTimeout !== null) {
248
+ timeoutId = setTimeout(() => {
249
+ controller.abort();
250
+ }, readTimeout * 1000);
251
+ }
252
+ try {
253
+ const response = await fetch(`${this._jupyterUrl}/port/8888/execute`, {
254
+ method: "POST",
255
+ headers: {
256
+ ...headers,
257
+ "Content-Type": "application/json",
258
+ },
259
+ body: JSON.stringify(body),
260
+ signal: controller.signal,
261
+ });
262
+ if (response.status >= 400) {
263
+ let bodyText = "<unavailable>";
264
+ try {
265
+ bodyText = await response.text();
266
+ }
267
+ catch {
268
+ // Ignore errors
269
+ }
270
+ const method = "POST";
271
+ const url = `${this._jupyterUrl}/port/8888/execute`;
272
+ const reason = response.statusText;
273
+ const details = "Execution failed\n" +
274
+ `- method: ${method}\n- url: ${url}\n- status: ${response.status} ${reason}\n` +
275
+ `- response-headers: ${JSON.stringify(Object.fromEntries(response.headers.entries()))}\n- body:\n${bodyText}`;
276
+ logger.debug(details);
277
+ throw new Error(details);
278
+ }
279
+ if (!response.body) {
280
+ throw new Error("No response body");
281
+ }
282
+ const reader = response.body.getReader();
283
+ const decoder = new TextDecoder();
284
+ let buffer = "";
285
+ try {
286
+ while (true) {
287
+ const result = await reader.read();
288
+ if (result.done)
289
+ break;
290
+ const value = result.value;
291
+ if (value instanceof Uint8Array) {
292
+ buffer += decoder.decode(value, { stream: true });
293
+ const lines = buffer.split(/\r?\n/);
294
+ buffer = lines.pop() || "";
295
+ for (const line of lines) {
296
+ if (!line)
297
+ continue;
298
+ try {
299
+ this._parseOutput(execution, line, onStdout, onStderr, onResult, onError);
300
+ }
301
+ catch {
302
+ // Fallback: treat as stdout text-only message
303
+ execution.logs.stdout.push(line);
304
+ if (onStdout) {
305
+ onStdout(new CodeInterpreter.OutputMessage(line, null, false));
306
+ }
307
+ }
308
+ }
309
+ }
310
+ }
311
+ }
312
+ finally {
313
+ reader.releaseLock();
314
+ }
315
+ }
316
+ catch (error) {
317
+ if (error &&
318
+ typeof error === "object" &&
319
+ "name" in error &&
320
+ error.name === "AbortError") {
321
+ throw new Error("Request timeout");
322
+ }
323
+ throw error;
324
+ }
325
+ finally {
326
+ if (timeoutId) {
327
+ clearTimeout(timeoutId);
328
+ }
329
+ }
330
+ return execution;
331
+ }
332
+ async createCodeContext(options = {}) {
333
+ const { cwd = null, language = null, requestTimeout = null } = options;
334
+ const data = {};
335
+ if (language) {
336
+ data.language = language;
337
+ }
338
+ if (cwd) {
339
+ data.cwd = cwd;
340
+ }
341
+ const headers = this._sandboxConfig.forceUrl
342
+ ? this._sandboxConfig.headers
343
+ : settings.headers;
344
+ const controller = new AbortController();
345
+ let timeoutId = null;
346
+ if (requestTimeout !== null) {
347
+ timeoutId = setTimeout(() => {
348
+ controller.abort();
349
+ }, requestTimeout * 1000);
350
+ }
351
+ try {
352
+ const response = await fetch(`${this._jupyterUrl}/port/8888/contexts`, {
353
+ method: "POST",
354
+ headers: {
355
+ ...headers,
356
+ "Content-Type": "application/json",
357
+ },
358
+ body: JSON.stringify(data),
359
+ signal: controller.signal,
360
+ });
361
+ if (response.status >= 400) {
362
+ let bodyText = "<unavailable>";
363
+ try {
364
+ bodyText = await response.text();
365
+ }
366
+ catch {
367
+ // Ignore errors
368
+ }
369
+ const method = "POST";
370
+ const url = `${this._jupyterUrl}/port/8888/contexts`;
371
+ const reason = response.statusText;
372
+ const details = "Create context failed\n" +
373
+ `- method: ${method}\n- url: ${url}\n- status: ${response.status} ${reason}\n` +
374
+ `- response-headers: ${JSON.stringify(Object.fromEntries(response.headers.entries()))}\n- body:\n${bodyText}`;
375
+ logger.debug(details);
376
+ throw new Error(details);
377
+ }
378
+ const responseData = (await response.json());
379
+ return CodeInterpreter.Context.fromJson(responseData);
380
+ }
381
+ catch (error) {
382
+ if (error &&
383
+ typeof error === "object" &&
384
+ "name" in error &&
385
+ error.name === "AbortError") {
386
+ throw new Error("Request timeout");
387
+ }
388
+ throw error;
389
+ }
390
+ finally {
391
+ if (timeoutId) {
392
+ clearTimeout(timeoutId);
393
+ }
394
+ }
395
+ }
396
+ }
@@ -39,10 +39,6 @@ export class McpTool {
39
39
  this.client = new ModelContextProtocolClient({
40
40
  name: this.name,
41
41
  version: "1.0.0",
42
- }, {
43
- capabilities: {
44
- tools: {},
45
- },
46
42
  });
47
43
  }
48
44
  get fallbackUrl() {