withruntime 0.8.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/BLAXEL.md +4 -4
- package/COMPATIBILITY.md +145 -0
- package/DAYTONA.md +13 -7
- package/E2B.md +34 -20
- package/README.md +22 -11
- package/README.src.md +22 -11
- package/VERCEL.md +13 -3
- package/compatibility-lock.json +357 -0
- package/dist/ai-harness/index.js +2 -2
- package/dist/api-defaults.d.ts +17 -0
- package/dist/api-defaults.js +22 -0
- package/dist/blaxel/errors.js +1 -1
- package/dist/blaxel/lookup.d.ts +3 -2
- package/dist/blaxel/lookup.js +3 -2
- package/dist/blaxel/pagination.d.ts +2 -2
- package/dist/blaxel/pagination.js +45 -17
- package/dist/blaxel/preview.d.ts +3 -2
- package/dist/blaxel/preview.js +16 -14
- package/dist/blaxel/process.d.ts +1 -1
- package/dist/blaxel/process.js +66 -11
- package/dist/blaxel/sandbox.d.ts +2 -0
- package/dist/blaxel/sandbox.js +2 -0
- package/dist/blaxel/snapshot.js +3 -5
- package/dist/cli-words.d.ts +27 -0
- package/dist/cli-words.js +135 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +351 -85
- package/dist/client.d.ts +33 -4
- package/dist/client.js +47 -12
- package/dist/cloudflare/identity.d.ts +7 -0
- package/dist/cloudflare/identity.js +13 -0
- package/dist/cloudflare/index.d.ts +303 -0
- package/dist/cloudflare/index.js +592 -0
- package/dist/cloudflare/worker.d.ts +419 -0
- package/dist/cloudflare/worker.js +447 -0
- package/dist/codesandbox/guest-service.d.ts +31 -0
- package/dist/codesandbox/guest-service.js +490 -0
- package/dist/codesandbox/index.d.ts +386 -0
- package/dist/codesandbox/index.js +1347 -0
- package/dist/compat/core.d.ts +40 -0
- package/dist/compat/core.js +238 -0
- package/dist/compat/files.d.ts +26 -0
- package/dist/compat/files.js +133 -0
- package/dist/compat/shell.d.ts +4 -0
- package/dist/compat/shell.js +165 -0
- package/dist/credentials.d.ts +6 -1
- package/dist/credentials.js +107 -38
- package/dist/daytona/context.js +2 -1
- package/dist/daytona/daytona.js +11 -4
- package/dist/daytona/filesystem.d.ts +17 -4
- package/dist/daytona/filesystem.js +121 -38
- package/dist/daytona/index.d.ts +1 -1
- package/dist/daytona/process.d.ts +1 -1
- package/dist/daytona/process.js +27 -4
- package/dist/daytona/sandbox.d.ts +1 -1
- package/dist/daytona/sandbox.js +16 -7
- package/dist/e2b/client.js +1 -1
- package/dist/e2b/code-interpreter.d.ts +4 -5
- package/dist/e2b/code-interpreter.js +54 -56
- package/dist/e2b/commands.d.ts +35 -12
- package/dist/e2b/commands.js +169 -73
- package/dist/e2b/errors.js +1 -1
- package/dist/e2b/filesystem.d.ts +8 -6
- package/dist/e2b/filesystem.js +127 -28
- package/dist/e2b/index.d.ts +1 -0
- package/dist/e2b/index.js +1 -0
- package/dist/e2b/pty.d.ts +24 -0
- package/dist/e2b/pty.js +80 -0
- package/dist/e2b/sandbox.d.ts +6 -4
- package/dist/e2b/sandbox.js +59 -25
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +15 -2
- package/dist/file-source.d.ts +16 -0
- package/dist/file-source.js +162 -0
- package/dist/freestyle/index.d.ts +309 -0
- package/dist/freestyle/index.js +343 -0
- package/dist/index.d.ts +3 -1
- package/dist/login.js +16 -10
- package/dist/mcp.js +2 -2
- package/dist/modal/index.d.ts +205 -0
- package/dist/modal/index.js +486 -0
- package/dist/network-cli.js +112 -44
- package/dist/openai-agents/index.js +18 -71
- package/dist/page.d.ts +1 -1
- package/dist/page.js +2 -2
- package/dist/products/audit.d.ts +3 -0
- package/dist/products/index.d.ts +14 -0
- package/dist/products/index.js +12 -0
- package/dist/products/interpreter.d.ts +11 -4
- package/dist/products/interpreter.js +33 -9
- package/dist/products/jobs.js +3 -2
- package/dist/products/limits.d.ts +10 -0
- package/dist/products/observability.d.ts +44 -0
- package/dist/products/observability.js +6 -0
- package/dist/products/previews.d.ts +18 -4
- package/dist/products/previews.js +14 -5
- package/dist/products/tailscale.d.ts +57 -0
- package/dist/products/tailscale.js +17 -0
- package/dist/products/volumes.d.ts +42 -0
- package/dist/products/volumes.js +36 -0
- package/dist/products/watch.d.ts +25 -4
- package/dist/products/watch.js +132 -18
- package/dist/proxy.js +3 -1
- package/dist/runloop/index.d.ts +326 -0
- package/dist/runloop/index.js +535 -0
- package/dist/runloop/pagination.d.ts +46 -0
- package/dist/runloop/pagination.js +82 -0
- package/dist/runloop/snapshots.d.ts +52 -0
- package/dist/runloop/snapshots.js +244 -0
- package/dist/sandbox.d.ts +76 -16
- package/dist/sandbox.js +696 -135
- package/dist/snapshots.d.ts +20 -5
- package/dist/snapshots.js +11 -1
- package/dist/sprites/index.d.ts +251 -0
- package/dist/sprites/index.js +588 -0
- package/dist/tar.d.ts +10 -1
- package/dist/tar.js +311 -35
- package/dist/tools/index.js +2 -1
- package/dist/transport.d.ts +23 -8
- package/dist/transport.js +247 -127
- package/dist/types.d.ts +52 -3
- package/dist/vercel/command.d.ts +1 -1
- package/dist/vercel/command.js +15 -3
- package/dist/vercel/errors.d.ts +2 -2
- package/dist/vercel/errors.js +19 -2
- package/dist/vercel/filesystem.d.ts +21 -18
- package/dist/vercel/filesystem.js +95 -48
- package/dist/vercel/sandbox.d.ts +8 -8
- package/dist/vercel/sandbox.js +159 -64
- package/dist/vercel/snapshot.d.ts +3 -2
- package/dist/vercel/snapshot.js +9 -5
- package/package.json +46 -3
|
@@ -18,6 +18,7 @@
|
|
|
18
18
|
* RUNTIME_API_KEY or this machine's `runtime login`. Plain function tools for
|
|
19
19
|
* an ordinary `Agent` are `runtimeFunctionTools(sandbox)`. */
|
|
20
20
|
import { applyDiff, tool, UserError, } from "@openai/agents-core";
|
|
21
|
+
import { OPENAI_AGENTS_EXEC_TIMEOUT_MS } from "../api-defaults.js";
|
|
21
22
|
import { SandboxProviderError, SandboxUnsupportedFeatureError, normalizeSandboxClientCreateArgs, } from "@openai/agents-core/sandbox";
|
|
22
23
|
import { deserializeManifest, elapsedSeconds, formatExecResponse, imageOutputFromBytes, materializeEnvironment, mergeManifestDelta, mergeManifestEntryDelta, serializeManifestRecord, shellQuote, truncateOutput, } from "@openai/agents-core/sandbox/internal";
|
|
23
24
|
import { Runtime } from "../client.js";
|
|
@@ -477,31 +478,11 @@ export class RuntimeCloudSandboxSession {
|
|
|
477
478
|
await this.#writeBytes(path, await readFile(entry.src));
|
|
478
479
|
return;
|
|
479
480
|
}
|
|
480
|
-
case "local_dir":
|
|
481
|
-
// One
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
const archive = await packDirectory(entry.src);
|
|
485
|
-
try {
|
|
486
|
-
await this.#call((sbx) => sbx.files.write(staging, archive));
|
|
487
|
-
const unpacked = await this.#call((sbx) => sbx.exec([
|
|
488
|
-
"sh",
|
|
489
|
-
"-c",
|
|
490
|
-
'mkdir -p -- "$1" && tar -xzf "$2" -C "$1"',
|
|
491
|
-
"sh",
|
|
492
|
-
path,
|
|
493
|
-
staging,
|
|
494
|
-
]));
|
|
495
|
-
if (unpacked.exitCode !== 0)
|
|
496
|
-
throw new SandboxProviderError(`${PROVIDER} could not place ${entry.src}.`, {
|
|
497
|
-
stderr: unpacked.stderr,
|
|
498
|
-
});
|
|
499
|
-
}
|
|
500
|
-
finally {
|
|
501
|
-
await this.#call((sbx) => sbx.files.remove(staging)).catch(() => undefined);
|
|
502
|
-
}
|
|
481
|
+
case "local_dir":
|
|
482
|
+
// One archive through the API's folder routes, unpacked by the
|
|
483
|
+
// sandbox's own tar as it arrives.
|
|
484
|
+
await this.#call((sbx) => sbx.files.upload(entry.src, path));
|
|
503
485
|
return;
|
|
504
|
-
}
|
|
505
486
|
case "git_repo": {
|
|
506
487
|
const url = /^[a-z]+:\/\//.test(entry.repo)
|
|
507
488
|
? entry.repo
|
|
@@ -550,29 +531,11 @@ export class RuntimeCloudSandboxSession {
|
|
|
550
531
|
// Workspace archives.
|
|
551
532
|
async persistWorkspace() {
|
|
552
533
|
const root = this.state.manifest.root;
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
"-c",
|
|
559
|
-
`mkdir -p -- ${STAGING} && tar ${skip.join(" ")} -C "$1" -cf - . > "$2"`,
|
|
560
|
-
"sh",
|
|
561
|
-
root,
|
|
562
|
-
staging,
|
|
563
|
-
], {
|
|
564
|
-
cwd: "/",
|
|
565
|
-
timeoutMs: this.state.execTimeoutMs,
|
|
566
|
-
}));
|
|
567
|
-
if (packed.exitCode !== 0)
|
|
568
|
-
throw new SandboxProviderError(`${PROVIDER} could not archive the workspace.`, {
|
|
569
|
-
stderr: packed.stderr,
|
|
570
|
-
});
|
|
571
|
-
return await this.#call((sbx) => sbx.files.read(staging));
|
|
572
|
-
}
|
|
573
|
-
finally {
|
|
574
|
-
await this.#call((sbx) => sbx.files.remove(staging)).catch(() => undefined);
|
|
575
|
-
}
|
|
534
|
+
return this.#call((sbx) => sbx.files.archive(root, {
|
|
535
|
+
gzip: false,
|
|
536
|
+
...(root === FILES_HOME ? { exclude: [".openai-agents-staging"] } : {}),
|
|
537
|
+
timeoutMs: this.state.execTimeoutMs,
|
|
538
|
+
}));
|
|
576
539
|
}
|
|
577
540
|
async hydrateWorkspace(data) {
|
|
578
541
|
const bytes = typeof data === "string"
|
|
@@ -580,28 +543,10 @@ export class RuntimeCloudSandboxSession {
|
|
|
580
543
|
: data instanceof Uint8Array
|
|
581
544
|
? data
|
|
582
545
|
: new Uint8Array(data);
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
"sh",
|
|
588
|
-
"-c",
|
|
589
|
-
'mkdir -p -- "$1" && tar -C "$1" -xf "$2"',
|
|
590
|
-
"sh",
|
|
591
|
-
this.state.manifest.root,
|
|
592
|
-
staging,
|
|
593
|
-
], {
|
|
594
|
-
cwd: "/",
|
|
595
|
-
timeoutMs: this.state.execTimeoutMs,
|
|
596
|
-
}));
|
|
597
|
-
if (unpacked.exitCode !== 0)
|
|
598
|
-
throw new SandboxProviderError(`${PROVIDER} could not restore the workspace.`, {
|
|
599
|
-
stderr: unpacked.stderr,
|
|
600
|
-
});
|
|
601
|
-
}
|
|
602
|
-
finally {
|
|
603
|
-
await this.#call((sbx) => sbx.files.remove(staging)).catch(() => undefined);
|
|
604
|
-
}
|
|
546
|
+
await this.#call((sbx) => sbx.files.unarchive(this.state.manifest.root, bytes, {
|
|
547
|
+
gzip: false,
|
|
548
|
+
timeoutMs: this.state.execTimeoutMs,
|
|
549
|
+
}));
|
|
605
550
|
}
|
|
606
551
|
// Lifecycle.
|
|
607
552
|
async running() {
|
|
@@ -674,7 +619,7 @@ export class RuntimeCloudSandboxClient {
|
|
|
674
619
|
...(options.exposedPorts ? { configuredExposedPorts: options.exposedPorts } : {}),
|
|
675
620
|
previewVisibility: options.previewVisibility ?? "private",
|
|
676
621
|
pauseOnExit: options.pauseOnExit ?? false,
|
|
677
|
-
execTimeoutMs: Math.min(MAX_EXEC_MS, options.execTimeoutMs ??
|
|
622
|
+
execTimeoutMs: Math.min(MAX_EXEC_MS, options.execTimeoutMs ?? OPENAI_AGENTS_EXEC_TIMEOUT_MS),
|
|
678
623
|
};
|
|
679
624
|
const session = new RuntimeCloudSandboxSession({ state, runtime: this.runtime });
|
|
680
625
|
await session.sandbox();
|
|
@@ -764,7 +709,9 @@ export class RuntimeCloudSandboxClient {
|
|
|
764
709
|
: {}),
|
|
765
710
|
previewVisibility: record.previewVisibility === "public" ? "public" : "private",
|
|
766
711
|
pauseOnExit: record.pauseOnExit === true,
|
|
767
|
-
execTimeoutMs: typeof record.execTimeoutMs === "number"
|
|
712
|
+
execTimeoutMs: typeof record.execTimeoutMs === "number"
|
|
713
|
+
? record.execTimeoutMs
|
|
714
|
+
: OPENAI_AGENTS_EXEC_TIMEOUT_MS,
|
|
768
715
|
};
|
|
769
716
|
}
|
|
770
717
|
}
|
package/dist/page.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export declare class Page<T> implements AsyncIterable<T> {
|
|
|
5
5
|
private readonly fetchPage;
|
|
6
6
|
constructor(data: T[], nextCursor: string | null, fetchPage: (cursor: string) => Promise<Page<T>>);
|
|
7
7
|
get hasMore(): boolean;
|
|
8
|
-
next(): Promise<Page<T> | null>;
|
|
8
|
+
next(cursor?: string | null): Promise<Page<T> | null>;
|
|
9
9
|
/** Every page, fetched as you go. */
|
|
10
10
|
pages(): AsyncGenerator<Page<T>>;
|
|
11
11
|
[Symbol.asyncIterator](): AsyncGenerator<T>;
|
package/dist/page.js
CHANGED
|
@@ -11,8 +11,8 @@ export class Page {
|
|
|
11
11
|
get hasMore() {
|
|
12
12
|
return this.nextCursor !== null;
|
|
13
13
|
}
|
|
14
|
-
async next() {
|
|
15
|
-
return
|
|
14
|
+
async next(cursor = this.nextCursor) {
|
|
15
|
+
return cursor === null ? null : this.fetchPage(cursor);
|
|
16
16
|
}
|
|
17
17
|
/** Every page, fetched as you go. */
|
|
18
18
|
async *pages() {
|
package/dist/products/audit.d.ts
CHANGED
|
@@ -26,6 +26,9 @@ export type AuditEvent = {
|
|
|
26
26
|
ip: string | null;
|
|
27
27
|
requestId: string | null;
|
|
28
28
|
via: "web" | "api" | "mcp" | "runtime";
|
|
29
|
+
/** The sandbox the request came from, when code in it called the API at
|
|
30
|
+
* http://runtime.internal. */
|
|
31
|
+
sandbox: string | null;
|
|
29
32
|
};
|
|
30
33
|
export type AuditPage = {
|
|
31
34
|
events: AuditEvent[];
|
package/dist/products/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { limits } from "./limits.js";
|
|
|
15
15
|
import { volumes } from "./volumes.js";
|
|
16
16
|
import { jobs } from "./jobs.js";
|
|
17
17
|
import { sandboxMounts } from "./mounts.js";
|
|
18
|
+
import { sandboxTailscale } from "./tailscale.js";
|
|
18
19
|
import { secrets } from "./secrets.js";
|
|
19
20
|
import { mcp, sandboxMcp } from "./mcp.js";
|
|
20
21
|
import { events, otel, sandboxMetrics, webhooks } from "./observability.js";
|
|
@@ -39,17 +40,30 @@ export declare const clientExtensions: {
|
|
|
39
40
|
tunnel: typeof tunnel;
|
|
40
41
|
network: typeof network;
|
|
41
42
|
};
|
|
43
|
+
/** Canonical CLI product names share the existing factory instance. Account
|
|
44
|
+
* commands such as secrets, events and billing retain their current names. */
|
|
45
|
+
export declare const clientProductAliases: {
|
|
46
|
+
readonly image: "images";
|
|
47
|
+
readonly volume: "volumes";
|
|
48
|
+
readonly job: "jobs";
|
|
49
|
+
readonly domain: "domains";
|
|
50
|
+
readonly port: "ports";
|
|
51
|
+
readonly address: "addresses";
|
|
52
|
+
};
|
|
42
53
|
export declare const sandboxExtensions: {
|
|
43
54
|
interpreter: typeof sandboxInterpreter;
|
|
44
55
|
previews: typeof sandboxPreviews;
|
|
45
56
|
network: typeof sandboxNetwork;
|
|
46
57
|
desktop: typeof sandboxDesktop;
|
|
47
58
|
mounts: typeof sandboxMounts;
|
|
59
|
+
tailscale: typeof sandboxTailscale;
|
|
48
60
|
metrics: typeof sandboxMetrics;
|
|
49
61
|
mcp: typeof sandboxMcp;
|
|
50
62
|
};
|
|
51
63
|
export type ClientExtensions = {
|
|
52
64
|
readonly [K in keyof typeof clientExtensions]: ReturnType<(typeof clientExtensions)[K]>;
|
|
65
|
+
} & {
|
|
66
|
+
readonly [K in keyof typeof clientProductAliases]: ReturnType<(typeof clientExtensions)[(typeof clientProductAliases)[K]]>;
|
|
53
67
|
};
|
|
54
68
|
export type SandboxExtensions = {
|
|
55
69
|
readonly [K in keyof typeof sandboxExtensions]: ReturnType<(typeof sandboxExtensions)[K]>;
|
package/dist/products/index.js
CHANGED
|
@@ -13,6 +13,7 @@ import { limits } from "./limits.js";
|
|
|
13
13
|
import { volumes } from "./volumes.js";
|
|
14
14
|
import { jobs } from "./jobs.js";
|
|
15
15
|
import { sandboxMounts } from "./mounts.js";
|
|
16
|
+
import { sandboxTailscale } from "./tailscale.js";
|
|
16
17
|
import { secrets } from "./secrets.js";
|
|
17
18
|
import { mcp, sandboxMcp } from "./mcp.js";
|
|
18
19
|
import { events, otel, sandboxMetrics, webhooks } from "./observability.js";
|
|
@@ -52,12 +53,23 @@ export const clientExtensions = {
|
|
|
52
53
|
tunnel,
|
|
53
54
|
network,
|
|
54
55
|
};
|
|
56
|
+
/** Canonical CLI product names share the existing factory instance. Account
|
|
57
|
+
* commands such as secrets, events and billing retain their current names. */
|
|
58
|
+
export const clientProductAliases = {
|
|
59
|
+
image: "images",
|
|
60
|
+
volume: "volumes",
|
|
61
|
+
job: "jobs",
|
|
62
|
+
domain: "domains",
|
|
63
|
+
port: "ports",
|
|
64
|
+
address: "addresses",
|
|
65
|
+
};
|
|
55
66
|
export const sandboxExtensions = {
|
|
56
67
|
interpreter: sandboxInterpreter,
|
|
57
68
|
previews: sandboxPreviews,
|
|
58
69
|
network: sandboxNetwork,
|
|
59
70
|
desktop: sandboxDesktop,
|
|
60
71
|
mounts: sandboxMounts,
|
|
72
|
+
tailscale: sandboxTailscale,
|
|
61
73
|
metrics: sandboxMetrics,
|
|
62
74
|
mcp: sandboxMcp,
|
|
63
75
|
};
|
|
@@ -50,15 +50,22 @@ export type RunOptions = RequestOptions & {
|
|
|
50
50
|
/** A context id; each language's own name ("python", "typescript", "r"...) is
|
|
51
51
|
* its default context, started on first use. */
|
|
52
52
|
context?: string;
|
|
53
|
+
/** Cell deadline. 0 runs until completion, cancellation or the sandbox's lease ends. */
|
|
53
54
|
timeoutMs?: number;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
/** Separate HTTP deadline, including retries. 0 disables it. */
|
|
56
|
+
requestTimeoutMs?: number;
|
|
57
|
+
/** false lets the cell continue if this reader disconnects. Default true. */
|
|
58
|
+
interruptOnDisconnect?: boolean;
|
|
59
|
+
/** @internal Compatibility protocols with separate header/body deadlines. */
|
|
60
|
+
onResponse?: (response: Response) => void;
|
|
61
|
+
onStdout?: (text: string) => unknown;
|
|
62
|
+
onStderr?: (text: string) => unknown;
|
|
63
|
+
onResult?: (result: ExecutionResult) => unknown;
|
|
57
64
|
onError?: (error: {
|
|
58
65
|
name: string;
|
|
59
66
|
value: string;
|
|
60
67
|
traceback: string;
|
|
61
|
-
}) =>
|
|
68
|
+
}) => unknown;
|
|
62
69
|
};
|
|
63
70
|
/** A stateful interpreter in the sandbox, in Python, JavaScript, TypeScript,
|
|
64
71
|
* R, Java, Bash or Go:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { RuntimeError } from "../errors.js";
|
|
1
2
|
/** A stateful interpreter in the sandbox, in Python, JavaScript, TypeScript,
|
|
2
3
|
* R, Java, Bash or Go:
|
|
3
4
|
* `await sbx.interpreter.run("import pandas as pd; pd.DataFrame({'a': [1]})")`.
|
|
@@ -7,33 +8,56 @@ export function sandboxInterpreter(t, sandbox) {
|
|
|
7
8
|
return {
|
|
8
9
|
/** Run a cell. With any of the on* callbacks, output streams as it happens. */
|
|
9
10
|
async run(code, options = {}) {
|
|
10
|
-
const { language, context, timeoutMs, onStdout, onStderr, onResult, onError, ...request } = options;
|
|
11
|
+
const { language, context, timeoutMs, requestTimeoutMs, interruptOnDisconnect, onStdout, onStderr, onResult, onError, ...request } = options;
|
|
12
|
+
const transportOptions = {
|
|
13
|
+
...request,
|
|
14
|
+
...(requestTimeoutMs !== undefined
|
|
15
|
+
? { timeoutMs: requestTimeoutMs }
|
|
16
|
+
: timeoutMs !== undefined
|
|
17
|
+
? { timeoutMs: timeoutMs === 0 ? 0 : timeoutMs + 60_000 }
|
|
18
|
+
: {}),
|
|
19
|
+
};
|
|
11
20
|
const body = {
|
|
12
21
|
code,
|
|
13
22
|
...(language ? { language } : {}),
|
|
14
23
|
...(context ? { context } : {}),
|
|
15
|
-
...(timeoutMs ? { timeoutMs } : {}),
|
|
24
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
25
|
+
...(interruptOnDisconnect !== undefined ? { interruptOnDisconnect } : {}),
|
|
16
26
|
};
|
|
17
27
|
if (!onStdout && !onStderr && !onResult && !onError)
|
|
18
|
-
return t.json({
|
|
28
|
+
return t.json({
|
|
29
|
+
method: "POST",
|
|
30
|
+
path: `${base()}:run`,
|
|
31
|
+
body,
|
|
32
|
+
...transportOptions,
|
|
33
|
+
});
|
|
19
34
|
for await (const event of t.events({
|
|
20
35
|
method: "POST",
|
|
21
36
|
path: `${base()}:run`,
|
|
22
37
|
body: { ...body, stream: true },
|
|
23
|
-
...
|
|
38
|
+
...transportOptions,
|
|
24
39
|
})) {
|
|
25
40
|
if (event.k === "stdout")
|
|
26
|
-
onStdout?.(event.text);
|
|
41
|
+
await onStdout?.(event.text);
|
|
27
42
|
else if (event.k === "stderr")
|
|
28
|
-
onStderr?.(event.text);
|
|
43
|
+
await onStderr?.(event.text);
|
|
29
44
|
else if (event.k === "result")
|
|
30
|
-
onResult?.({ main: event.main, data: event.data, refs: event.refs });
|
|
45
|
+
await onResult?.({ main: event.main, data: event.data, refs: event.refs });
|
|
31
46
|
else if (event.k === "error")
|
|
32
|
-
onError?.(event);
|
|
47
|
+
await onError?.(event);
|
|
33
48
|
else if (event.k === "execution")
|
|
34
49
|
return event.execution;
|
|
35
50
|
else if (event.k === "failure")
|
|
36
|
-
|
|
51
|
+
// As every other refusal: its code, words, hint and request id,
|
|
52
|
+
// printed by the CLI as it prints the rest (28 September 2026:
|
|
53
|
+
// "Error: forbidden: cloud forbidden", with no hint and no id).
|
|
54
|
+
throw new RuntimeError({
|
|
55
|
+
code: event.code,
|
|
56
|
+
status: event.status ?? 0,
|
|
57
|
+
message: event.message,
|
|
58
|
+
...(event.hint ? { hint: event.hint } : {}),
|
|
59
|
+
...(event.requestId ? { requestId: event.requestId } : {}),
|
|
60
|
+
});
|
|
37
61
|
}
|
|
38
62
|
throw new Error("The interpreter stream ended without a result");
|
|
39
63
|
},
|
package/dist/products/jobs.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { JOB_START_SECONDS, JOB_TIMEOUT_SECONDS } from "../api-defaults.js";
|
|
1
2
|
import { Page } from "../page.js";
|
|
2
3
|
import { RuntimeError, ServiceUnavailableError } from "../errors.js";
|
|
3
4
|
/** The size a run gets when `compute` leaves a field out: the sandbox
|
|
@@ -9,9 +10,9 @@ export const JOB_DEFAULTS = {
|
|
|
9
10
|
cpuFloorMillis: 50,
|
|
10
11
|
memoryMiB: 4096,
|
|
11
12
|
diskMiB: 4096,
|
|
12
|
-
timeoutSeconds:
|
|
13
|
+
timeoutSeconds: JOB_TIMEOUT_SECONDS,
|
|
13
14
|
/** Added to the timeout for the sandbox to start, within the hour. */
|
|
14
|
-
startSeconds:
|
|
15
|
+
startSeconds: JOB_START_SECONDS,
|
|
15
16
|
};
|
|
16
17
|
/** A run is one sandbox: at most 16 vCPU and 64 GiB, a disk no smaller than
|
|
17
18
|
* the system image, and paid for at most an hour. */
|
|
@@ -14,6 +14,16 @@ export type KeyLimits = {
|
|
|
14
14
|
remainingMicros: string | null;
|
|
15
15
|
window: "24h";
|
|
16
16
|
};
|
|
17
|
+
/** The account's free trial time in milliseconds, the same figures as
|
|
18
|
+
* `usage.get()`, or null when the account has no trial. A trial sandbox
|
|
19
|
+
* that has not ended holds its whole lease in `reservedMs`;
|
|
20
|
+
* `availableMs = totalMs - usedMs - reservedMs`. */
|
|
21
|
+
trial: {
|
|
22
|
+
totalMs: number;
|
|
23
|
+
usedMs: number;
|
|
24
|
+
reservedMs: number;
|
|
25
|
+
availableMs: number;
|
|
26
|
+
} | null;
|
|
17
27
|
};
|
|
18
28
|
/** `runtime.limits.get()`: whether this key is read-only, and what its agent
|
|
19
29
|
* may still spend today. An owner sets the limit at
|
|
@@ -10,6 +10,11 @@ export type MetricPoint = {
|
|
|
10
10
|
cpuCores: number | null;
|
|
11
11
|
/** The busiest interval between two readings in the bucket. */
|
|
12
12
|
cpuPeakPercent: number | null;
|
|
13
|
+
/** Measured wall-time percentage ready to run while waiting for CPU; null
|
|
14
|
+
* without two complete readings of the same run. Older servers omit it. */
|
|
15
|
+
cpuWaitPercent?: number | null;
|
|
16
|
+
/** Measured wall-time percentage with a thread waiting for memory. */
|
|
17
|
+
memoryStallPercent?: number | null;
|
|
13
18
|
/** Average resident memory, bytes. */
|
|
14
19
|
memoryBytes: number;
|
|
15
20
|
memoryPeakBytes: number;
|
|
@@ -96,6 +101,45 @@ type List<T> = {
|
|
|
96
101
|
data: T[];
|
|
97
102
|
nextCursor: string | null;
|
|
98
103
|
};
|
|
104
|
+
export type UsageExportQuery = {
|
|
105
|
+
since: string;
|
|
106
|
+
until: string;
|
|
107
|
+
cursor?: string;
|
|
108
|
+
limit?: number;
|
|
109
|
+
};
|
|
110
|
+
export type UsageExportRow = {
|
|
111
|
+
intervalId: string;
|
|
112
|
+
resourceId: string;
|
|
113
|
+
name: string | null;
|
|
114
|
+
kind: string;
|
|
115
|
+
meter: string;
|
|
116
|
+
fundedBy: "credit" | "trial";
|
|
117
|
+
startsAt: string;
|
|
118
|
+
endsAt: string;
|
|
119
|
+
settledAt: string;
|
|
120
|
+
billedMilliseconds: string | null;
|
|
121
|
+
chargedMicros: string;
|
|
122
|
+
quotedRates: Array<{
|
|
123
|
+
component: string;
|
|
124
|
+
unit: string;
|
|
125
|
+
rateMicros: string;
|
|
126
|
+
}>;
|
|
127
|
+
/** Exact JSON text, preserving integers beyond JavaScript's number range. */
|
|
128
|
+
measurementsJson: string | null;
|
|
129
|
+
evidence: "measured" | "partial" | "missing" | null;
|
|
130
|
+
};
|
|
131
|
+
export type UsageExportPage = {
|
|
132
|
+
since: string;
|
|
133
|
+
until: string;
|
|
134
|
+
data: UsageExportRow[];
|
|
135
|
+
nextCursor: string | null;
|
|
136
|
+
/** Concatenate pages in order; only the first page includes the header. */
|
|
137
|
+
csv: string;
|
|
138
|
+
};
|
|
139
|
+
/** Top-level cross-product settled usage, selected by UTC settlement timestamps
|
|
140
|
+
* in [since, until). Pending holds are excluded. Follow nextCursor using the
|
|
141
|
+
* same range; each page checks current permissions. Pages are live reads. */
|
|
142
|
+
export declare function usageExport(t: Transport): (query: UsageExportQuery, options?: RequestOptions) => Promise<UsageExportPage>;
|
|
99
143
|
/** `sbx.metrics()`: this sandbox's measured CPU and memory. */
|
|
100
144
|
export declare function sandboxMetrics(t: Transport, sandbox: Sandbox): (options?: {
|
|
101
145
|
range?: MetricRange;
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/** Top-level cross-product settled usage, selected by UTC settlement timestamps
|
|
2
|
+
* in [since, until). Pending holds are excluded. Follow nextCursor using the
|
|
3
|
+
* same range; each page checks current permissions. Pages are live reads. */
|
|
4
|
+
export function usageExport(t) {
|
|
5
|
+
return (query, options = {}) => t.json({ method: "GET", path: "/v1/usage/export", query, ...options });
|
|
6
|
+
}
|
|
1
7
|
/** `sbx.metrics()`: this sandbox's measured CPU and memory. */
|
|
2
8
|
export function sandboxMetrics(t, sandbox) {
|
|
3
9
|
return (options = {}) => {
|
|
@@ -17,6 +17,8 @@ export type Preview = {
|
|
|
17
17
|
urlWithToken: string | null;
|
|
18
18
|
/** Turned off by Runtime after a report. */
|
|
19
19
|
disabled: boolean;
|
|
20
|
+
/** The sites that may show it in an iframe; null for any site. */
|
|
21
|
+
embedOrigins: string[] | null;
|
|
20
22
|
createdAt: string;
|
|
21
23
|
/** On create only: how to share the address, in one line. */
|
|
22
24
|
hint?: string;
|
|
@@ -27,6 +29,14 @@ export type CreatePreview = {
|
|
|
27
29
|
visibility?: "private" | "public";
|
|
28
30
|
/** How long the returned token lasts, 60 s to 7 days (default 1 day). */
|
|
29
31
|
ttlSeconds?: number;
|
|
32
|
+
/** An absolute ISO private-token deadline, a minute to a week ahead.
|
|
33
|
+
* Used exactly without TTL; with TTL, the earlier expiry wins. */
|
|
34
|
+
expiresAt?: string;
|
|
35
|
+
/** The sites that may show it in an iframe, as origins
|
|
36
|
+
* (`https://app.example.com`, `https://*.example.com`, `http://localhost:3000`),
|
|
37
|
+
* up to 16. Any other site's iframe is refused. Omitted: a shared port keeps
|
|
38
|
+
* its list; `[]` or null: any site, the default. */
|
|
39
|
+
embedOrigins?: string[] | null;
|
|
30
40
|
};
|
|
31
41
|
/** `sbx.previews`: share ports of this sandbox at public HTTPS addresses.
|
|
32
42
|
*
|
|
@@ -35,15 +45,19 @@ export type CreatePreview = {
|
|
|
35
45
|
*
|
|
36
46
|
* WebSockets work. The server must listen on 0.0.0.0 or localhost. */
|
|
37
47
|
export declare function sandboxPreviews(t: Transport, sandbox: Sandbox): {
|
|
38
|
-
/** Shares `port`, or changes its visibility if it is
|
|
48
|
+
/** Shares `port`, or changes its visibility and embedOrigins if it is
|
|
49
|
+
* shared already. */
|
|
39
50
|
create: (port: number, input?: CreatePreview, options?: RequestOptions) => Promise<Preview>;
|
|
40
51
|
/** Every shared port, each private one with a fresh token. */
|
|
41
52
|
list: (options?: RequestOptions) => Promise<Preview[]>;
|
|
42
|
-
/** One preview, with a fresh token
|
|
43
|
-
|
|
53
|
+
/** One preview, with a fresh private token. `expiresAt` bounds its expiry
|
|
54
|
+
* to an absolute ISO deadline; with no TTL, that deadline is used exactly. */
|
|
55
|
+
get: (port: number, ttlSeconds?: number, { expiresAt, ...options }?: RequestOptions & {
|
|
56
|
+
expiresAt?: string;
|
|
57
|
+
}) => Promise<Preview>;
|
|
44
58
|
/** Refuses every token issued for this port so far and returns a new one. */
|
|
45
59
|
rotate: (port: number, options?: RequestOptions) => Promise<Preview>;
|
|
46
|
-
/** Stops sharing `port`.
|
|
60
|
+
/** Stops sharing `port`. Its open connections are closed before this returns. */
|
|
47
61
|
delete: (port: number, options?: RequestOptions) => Promise<{
|
|
48
62
|
id: string;
|
|
49
63
|
sandboxId: string;
|
|
@@ -7,20 +7,29 @@
|
|
|
7
7
|
export function sandboxPreviews(t, sandbox) {
|
|
8
8
|
const base = () => `/v1/sandboxes/${encodeURIComponent(sandbox.id)}/previews`;
|
|
9
9
|
return {
|
|
10
|
-
/** Shares `port`, or changes its visibility if it is
|
|
10
|
+
/** Shares `port`, or changes its visibility and embedOrigins if it is
|
|
11
|
+
* shared already. */
|
|
11
12
|
create: (port, input = {}, options) => t.json({ method: "POST", path: base(), body: { port, ...input }, ...options }),
|
|
12
13
|
/** Every shared port, each private one with a fresh token. */
|
|
13
14
|
list: async (options) => (await t.json({ method: "GET", path: base(), ...options })).data,
|
|
14
|
-
/** One preview, with a fresh token
|
|
15
|
-
|
|
15
|
+
/** One preview, with a fresh private token. `expiresAt` bounds its expiry
|
|
16
|
+
* to an absolute ISO deadline; with no TTL, that deadline is used exactly. */
|
|
17
|
+
get: (port, ttlSeconds, { expiresAt, ...options } = {}) => t.json({
|
|
16
18
|
method: "GET",
|
|
17
19
|
path: `${base()}/${port}`,
|
|
18
|
-
...(ttlSeconds
|
|
20
|
+
...(ttlSeconds !== undefined || expiresAt !== undefined
|
|
21
|
+
? {
|
|
22
|
+
query: {
|
|
23
|
+
...(ttlSeconds === undefined ? {} : { ttlSeconds }),
|
|
24
|
+
...(expiresAt === undefined ? {} : { expiresAt }),
|
|
25
|
+
},
|
|
26
|
+
}
|
|
27
|
+
: {}),
|
|
19
28
|
...options,
|
|
20
29
|
}),
|
|
21
30
|
/** Refuses every token issued for this port so far and returns a new one. */
|
|
22
31
|
rotate: (port, options) => t.json({ method: "POST", path: `${base()}/${port}:rotate`, ...options }),
|
|
23
|
-
/** Stops sharing `port`.
|
|
32
|
+
/** Stops sharing `port`. Its open connections are closed before this returns. */
|
|
24
33
|
delete: (port, options) => t.json({
|
|
25
34
|
method: "DELETE",
|
|
26
35
|
path: `${base()}/${port}`,
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import type { Sandbox } from "../sandbox.js";
|
|
2
|
+
import type { RequestOptions, Transport } from "../transport.js";
|
|
3
|
+
/** Joining a sandbox to your tailnet. */
|
|
4
|
+
export type TailscaleJoin = {
|
|
5
|
+
/** The name of a secret stored for jobs (`runtime secrets set NAME --jobs`)
|
|
6
|
+
* that holds a Tailscale auth key. Use an ephemeral, tagged key. */
|
|
7
|
+
authKeySecret: string;
|
|
8
|
+
/** The machine's name on the tailnet, a DNS label. Default: the sandbox's
|
|
9
|
+
* name, or runtime- and the first part of its id. */
|
|
10
|
+
hostname?: string;
|
|
11
|
+
/** Tags to advertise, such as `tag:agents`; the key must be allowed them. */
|
|
12
|
+
tags?: string[];
|
|
13
|
+
};
|
|
14
|
+
/** A sandbox's machine on your tailnet, as the sandbox reports it. */
|
|
15
|
+
export type TailscaleNode = {
|
|
16
|
+
/** Logged in and running now. */
|
|
17
|
+
running: boolean;
|
|
18
|
+
/** Tailscale's own word: Running, NeedsLogin, Starting, Stopped. */
|
|
19
|
+
state: string | null;
|
|
20
|
+
/** kernel: a tailscale0 interface reaches 100.x directly. userspace: the
|
|
21
|
+
* tailnet reaches the sandbox's ports, and programs in it reach the tailnet
|
|
22
|
+
* through `proxy`. */
|
|
23
|
+
mode: "kernel" | "userspace" | null;
|
|
24
|
+
/** Its MagicDNS name, such as agent-1.tail1234.ts.net. */
|
|
25
|
+
dnsName: string | null;
|
|
26
|
+
/** Its tailnet addresses, 100.x and fd7a:… */
|
|
27
|
+
addresses: string[];
|
|
28
|
+
/** SOCKS5 and HTTP proxy to the tailnet in userspace mode. */
|
|
29
|
+
proxy: string | null;
|
|
30
|
+
};
|
|
31
|
+
/** What a join answers: the node, and what Runtime recorded. */
|
|
32
|
+
export type TailscaleJoined = TailscaleNode & {
|
|
33
|
+
hostname: string;
|
|
34
|
+
tags: string[];
|
|
35
|
+
/** The secret the key was read from; never the key. */
|
|
36
|
+
authKeySecret: string | null;
|
|
37
|
+
joinedAt: number;
|
|
38
|
+
};
|
|
39
|
+
/** What `status()` answers: the node, and the join, or null on none. */
|
|
40
|
+
export type TailscaleStatus = TailscaleNode & {
|
|
41
|
+
tailnet: Pick<TailscaleJoined, "hostname" | "tags" | "authKeySecret" | "joinedAt"> | null;
|
|
42
|
+
};
|
|
43
|
+
/** `sbx.tailscale`: this sandbox on your own Tailscale network. Paid
|
|
44
|
+
* sandboxes only.
|
|
45
|
+
*
|
|
46
|
+
* const node = await sbx.tailscale.up({ authKeySecret: "TS_AUTHKEY", tags: ["tag:agents"] });
|
|
47
|
+
* console.log(node.addresses);
|
|
48
|
+
*
|
|
49
|
+
* The auth key stays in the sandbox's memory. `down()` takes the machine off
|
|
50
|
+
* the tailnet at once; after a stop or a delete, Tailscale removes it. */
|
|
51
|
+
export declare function sandboxTailscale(t: Transport, sandbox: Sandbox): {
|
|
52
|
+
up: (input: TailscaleJoin, options?: RequestOptions) => Promise<TailscaleJoined>;
|
|
53
|
+
status: (options?: RequestOptions) => Promise<TailscaleStatus>;
|
|
54
|
+
down: (options?: RequestOptions) => Promise<{
|
|
55
|
+
left: boolean;
|
|
56
|
+
}>;
|
|
57
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
const enc = encodeURIComponent;
|
|
2
|
+
/** `sbx.tailscale`: this sandbox on your own Tailscale network. Paid
|
|
3
|
+
* sandboxes only.
|
|
4
|
+
*
|
|
5
|
+
* const node = await sbx.tailscale.up({ authKeySecret: "TS_AUTHKEY", tags: ["tag:agents"] });
|
|
6
|
+
* console.log(node.addresses);
|
|
7
|
+
*
|
|
8
|
+
* The auth key stays in the sandbox's memory. `down()` takes the machine off
|
|
9
|
+
* the tailnet at once; after a stop or a delete, Tailscale removes it. */
|
|
10
|
+
export function sandboxTailscale(t, sandbox) {
|
|
11
|
+
const path = () => `/v1/sandboxes/${enc(sandbox.id)}/tailscale`;
|
|
12
|
+
return {
|
|
13
|
+
up: (input, options) => t.json({ method: "POST", path: path(), body: input, ...options }),
|
|
14
|
+
status: (options) => t.json({ method: "GET", path: path(), ...options }),
|
|
15
|
+
down: (options) => t.json({ method: "DELETE", path: path(), ...options }),
|
|
16
|
+
};
|
|
17
|
+
}
|