@shardflux/sdk 0.10.2 → 0.11.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +58 -26
- package/README.md +73 -51
- package/dist/account.d.ts +2 -2
- package/dist/account.js +1 -1
- package/dist/cell.d.ts +21 -21
- package/dist/cell.js +12 -12
- package/dist/client.d.ts +31 -31
- package/dist/client.js +17 -17
- package/dist/egress.d.ts +3 -3
- package/dist/errors.d.ts +18 -18
- package/dist/errors.js +11 -11
- package/dist/executions.d.ts +2 -2
- package/dist/feedback.d.ts +3 -3
- package/dist/generated/app-api.d.ts +1352 -21
- package/dist/http.d.ts +7 -11
- package/dist/http.js +8 -11
- package/dist/index.d.ts +1 -1
- package/dist/lifecycle.d.ts +2 -2
- package/dist/lifecycle.js +1 -1
- package/dist/progress.d.ts +38 -18
- package/dist/progress.js +17 -11
- package/dist/tar.d.ts +1 -1
- package/dist/tar.js +1 -1
- package/dist/template-file.d.ts +1 -1
- package/dist/template-file.js +1 -1
- package/dist/templates.d.ts +21 -21
- package/dist/templates.js +8 -8
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -4
- package/dist/version-check.d.ts +1 -1
- package/dist/volumes.d.ts +1 -1
- package/dist/workspace.d.ts +30 -21
- package/dist/workspace.js +27 -20
- package/package.json +1 -1
package/dist/http.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { RetryRecord } from './progress.js';
|
|
2
|
-
export declare const SDK_VERSION = "0.
|
|
2
|
+
export declare const SDK_VERSION = "0.11.1";
|
|
3
3
|
export interface RequestOptions {
|
|
4
4
|
query?: Record<string, string | number | boolean | undefined | null>;
|
|
5
5
|
json?: unknown;
|
|
@@ -29,17 +29,13 @@ export interface HttpOptions {
|
|
|
29
29
|
}
|
|
30
30
|
export declare const defaultSleep: (ms: number) => Promise<void>;
|
|
31
31
|
/**
|
|
32
|
-
* The fetch the SDK uses when none is given. On
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
* with 0.2-12 s gaps; Node 22 / undici 6.28 max 351 ms; Node 26 with `Connection: close` max 435 ms; node:http2 on the
|
|
36
|
-
* same load balancer and gaps max 193 ms, and the load balancer's idle timeout is 3600 s, so it is not an idle-timeout
|
|
37
|
-
* interaction). The CLI and MCP server do the same. Other runtimes keep the runtime's keep-alive pooling.
|
|
38
|
-
* `SHARDFLUX_HTTP_KEEPALIVE=1` disables the workaround.
|
|
32
|
+
* The fetch the SDK uses when none is given. On Node 26 every request uses a fresh connection (`Connection: close`),
|
|
33
|
+
* as in the CLI and the MCP server; other runtimes reuse connections. `SHARDFLUX_HTTP_KEEPALIVE=1` reuses connections
|
|
34
|
+
* on Node 26 too.
|
|
39
35
|
*/
|
|
40
36
|
export declare function defaultFetch(env?: Record<string, string | undefined> | undefined, undiciVersion?: string | undefined): typeof fetch;
|
|
41
37
|
export declare function buildUrl(base: string, path: string, query?: RequestOptions['query']): string;
|
|
42
|
-
/** `X-Tree-Revision` (file-first workspaces
|
|
38
|
+
/** `X-Tree-Revision` (file-first workspaces): a non-negative integer, else null. */
|
|
43
39
|
export declare function treeRevisionOf(headers: Headers): number | null;
|
|
44
40
|
/** Turns a non-2xx response into a ShardfluxApiError (or a protocol error for undocumented bodies). */
|
|
45
41
|
export declare function errorFrom(res: Response, source: 'api' | 'cell'): Promise<Error>;
|
|
@@ -61,10 +57,10 @@ export declare class HttpClient {
|
|
|
61
57
|
body: T;
|
|
62
58
|
}>;
|
|
63
59
|
}
|
|
64
|
-
/** Longest server-side wait the SDK asks for (
|
|
60
|
+
/** Longest server-side wait the SDK asks for (servers cap `Prefer: wait` at 20 s). */
|
|
65
61
|
export declare const SERVER_WAIT_MAX_S = 20;
|
|
66
62
|
/**
|
|
67
|
-
* One bounded-wait poll
|
|
63
|
+
* One bounded-wait poll: GET `path` with `Prefer: wait=<s>` when `waitS` >= 1. `applied` is true only
|
|
68
64
|
* when the server says it waited (Preference-Applied); otherwise the caller keeps its own backoff.
|
|
69
65
|
*/
|
|
70
66
|
export declare function pollWithWait<T>(http: HttpClient, path: string, authorization: string, waitS: number, signal?: AbortSignal, onRetry?: RequestOptions['onRetry']): Promise<{
|
package/dist/http.js
CHANGED
|
@@ -8,18 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { ShardfluxApiError, ShardfluxProtocolError, apiError, isErrorBody } from "./errors.js";
|
|
10
10
|
import { describeFailure } from "./progress.js";
|
|
11
|
-
export const SDK_VERSION = '0.
|
|
11
|
+
export const SDK_VERSION = '0.11.1';
|
|
12
12
|
export const defaultSleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
13
13
|
/**
|
|
14
|
-
* The fetch the SDK uses when none is given. On
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
* with 0.2-12 s gaps; Node 22 / undici 6.28 max 351 ms; Node 26 with `Connection: close` max 435 ms; node:http2 on the
|
|
18
|
-
* same load balancer and gaps max 193 ms, and the load balancer's idle timeout is 3600 s, so it is not an idle-timeout
|
|
19
|
-
* interaction). The CLI and MCP server do the same. Other runtimes keep the runtime's keep-alive pooling.
|
|
20
|
-
* `SHARDFLUX_HTTP_KEEPALIVE=1` disables the workaround.
|
|
14
|
+
* The fetch the SDK uses when none is given. On Node 26 every request uses a fresh connection (`Connection: close`),
|
|
15
|
+
* as in the CLI and the MCP server; other runtimes reuse connections. `SHARDFLUX_HTTP_KEEPALIVE=1` reuses connections
|
|
16
|
+
* on Node 26 too.
|
|
21
17
|
*/
|
|
22
18
|
export function defaultFetch(env = globalThis.process?.env, undiciVersion = globalThis.process?.versions?.undici) {
|
|
19
|
+
// Why a fresh connection on Node 26 (its bundled HTTP client, measured): docs/progress/startup-latency.md.
|
|
23
20
|
const base = (input, init) => fetch(input, init);
|
|
24
21
|
const major = Number((undiciVersion ?? '').split('.')[0]);
|
|
25
22
|
if (!(major >= 8) || env?.SHARDFLUX_HTTP_KEEPALIVE === '1')
|
|
@@ -45,7 +42,7 @@ function retryAfterSeconds(res) {
|
|
|
45
42
|
const n = Number(v);
|
|
46
43
|
return Number.isFinite(n) && n >= 0 ? n : undefined;
|
|
47
44
|
}
|
|
48
|
-
/** `X-Tree-Revision` (file-first workspaces
|
|
45
|
+
/** `X-Tree-Revision` (file-first workspaces): a non-negative integer, else null. */
|
|
49
46
|
export function treeRevisionOf(headers) {
|
|
50
47
|
const v = headers.get('x-tree-revision');
|
|
51
48
|
if (v === null || !/^\d{1,19}$/.test(v))
|
|
@@ -171,10 +168,10 @@ export class HttpClient {
|
|
|
171
168
|
}
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
|
-
/** Longest server-side wait the SDK asks for (
|
|
171
|
+
/** Longest server-side wait the SDK asks for (servers cap `Prefer: wait` at 20 s). */
|
|
175
172
|
export const SERVER_WAIT_MAX_S = 20;
|
|
176
173
|
/**
|
|
177
|
-
* One bounded-wait poll
|
|
174
|
+
* One bounded-wait poll: GET `path` with `Prefer: wait=<s>` when `waitS` >= 1. `applied` is true only
|
|
178
175
|
* when the server says it waited (Preference-Applied); otherwise the caller keeps its own backoff.
|
|
179
176
|
*/
|
|
180
177
|
export async function pollWithWait(http, path, authorization, waitS, signal, onRetry) {
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* const workspace = await cloud.workspaces.open({ key: `${customerId}/${projectId}`, template: 'python-node-browser' });
|
|
7
7
|
* await agent.run({ input: userMessage, tools: workspaceTools(workspace) });
|
|
8
8
|
*
|
|
9
|
-
* File-first workspaces (`mode: 'file_first'
|
|
9
|
+
* File-first workspaces (`mode: 'file_first'`) keep a versioned file tree and run each command as an
|
|
10
10
|
* execution: `await workspace.executions.run(['bash', '-lc', 'pytest -q'])`.
|
|
11
11
|
*
|
|
12
12
|
* Types come from the committed OpenAPI documents: application API
|
package/dist/lifecycle.d.ts
CHANGED
|
@@ -34,7 +34,7 @@ export type WaitedLifecycleOptions = LifecycleOptions & {
|
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
36
|
* `resume()` options (0.9.0). With `wait`, the server holds the resume until the workspace runs and returns a tool token
|
|
37
|
-
* with it
|
|
37
|
+
* with it: `agentLabel` and `tools` choose that token (defaults: a workspace handle's own, those given
|
|
38
38
|
* to open(); `workspaces.resume(id)` otherwise the key's tools and label `default`). A handle keeps it for its `cell()`
|
|
39
39
|
* clients of the same label and tools; `workspaces.resume(id)` only attributes it.
|
|
40
40
|
*/
|
|
@@ -50,7 +50,7 @@ export declare const TRACE: unique symbol;
|
|
|
50
50
|
/** Internal: work a workspace handle does after the operation finished, inside the same trace (refreshing its view). */
|
|
51
51
|
export declare const AFTER_WAIT: unique symbol;
|
|
52
52
|
/**
|
|
53
|
-
* Internal: a workspace handle's part in a held resume
|
|
53
|
+
* Internal: a workspace handle's part in a held resume: the tool token to ask for, and how it takes the
|
|
54
54
|
* running workspace and that token from a 200 (instead of reading the view and fetching a token afterwards).
|
|
55
55
|
*/
|
|
56
56
|
export declare const HELD_RESUME: unique symbol;
|
package/dist/lifecycle.js
CHANGED
|
@@ -5,7 +5,7 @@ export const TRACE = Symbol('shardflux.trace');
|
|
|
5
5
|
/** Internal: work a workspace handle does after the operation finished, inside the same trace (refreshing its view). */
|
|
6
6
|
export const AFTER_WAIT = Symbol('shardflux.afterWait');
|
|
7
7
|
/**
|
|
8
|
-
* Internal: a workspace handle's part in a held resume
|
|
8
|
+
* Internal: a workspace handle's part in a held resume: the tool token to ask for, and how it takes the
|
|
9
9
|
* running workspace and that token from a 200 (instead of reading the view and fetching a token afterwards).
|
|
10
10
|
*/
|
|
11
11
|
export const HELD_RESUME = Symbol('shardflux.heldResume');
|
package/dist/progress.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Lifecycle timing and progress.
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Lifecycle timing and progress. Every open, resume and wake says where its time went, without a packet capture: the
|
|
3
|
+
* queue, the cell booting or restoring the VM, the network between the caller and the API, the first tool token, or
|
|
4
|
+
* retries.
|
|
5
5
|
*
|
|
6
6
|
* A Trace follows one SDK call (open, a lifecycle call with `wait`, a wake, a token fetch). It records two clocks and
|
|
7
7
|
* never mixes them:
|
|
@@ -56,8 +56,8 @@ export interface ServerTiming {
|
|
|
56
56
|
kind: Operation['kind'];
|
|
57
57
|
state: Operation['state'];
|
|
58
58
|
/**
|
|
59
|
-
* created_at → started_at: waiting until the cell began running the operation, including any
|
|
60
|
-
*
|
|
59
|
+
* created_at → started_at: waiting until the cell began running the operation, including any time in
|
|
60
|
+
* `capacity_pending` (started_at is set when the operation first enters `running`). Null when the API does not report
|
|
61
61
|
* started_at or the operation has not run yet. An operation that finished without running (e.g. a failed dependency)
|
|
62
62
|
* has started_at = completed_at, so all of its time shows here.
|
|
63
63
|
*/
|
|
@@ -70,8 +70,25 @@ export interface ServerTiming {
|
|
|
70
70
|
startPath: string | null;
|
|
71
71
|
/** `result.warm_fallback`: why a start that could be warm booted instead. */
|
|
72
72
|
warmFallback: string | null;
|
|
73
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* `result.resume_path`: `local_cache`, `prestaged` (copied to this host ahead of the resume),
|
|
75
|
+
* `download` (the checkpoint had to be fetched first), `cold_boot` (0.11.0+: the saved disk was booted after a
|
|
76
|
+
* platform runtime change; processes restarted; see `memoryRestored`) or `reset_blank_layer` (the first start after a
|
|
77
|
+
* reset).
|
|
78
|
+
*/
|
|
74
79
|
resumePath: string | null;
|
|
80
|
+
/**
|
|
81
|
+
* `result.memory_restored` (0.11.0+): `true` when memory and running processes came back from the checkpoint;
|
|
82
|
+
* `false` when the workspace booted instead (`cold_boot`, `reset_blank_layer`): its files are as of the suspend, but
|
|
83
|
+
* every process was restarted, as after a reboot. `null` when the result does not say (an older API, or not a
|
|
84
|
+
* resume). Always set by `serverTiming()`; optional only so timings built by hand still type-check.
|
|
85
|
+
*/
|
|
86
|
+
memoryRestored?: boolean | null;
|
|
87
|
+
/**
|
|
88
|
+
* `result.cold_boot_reason` (0.11.0+), with `resumePath` `cold_boot`: why the memory could not be restored, e.g.
|
|
89
|
+
* `runtime_changed` (the platform's VM runtime changed after the suspend). Null otherwise.
|
|
90
|
+
*/
|
|
91
|
+
coldBootReason?: string | null;
|
|
75
92
|
/** `result.boot_to_ready_ms`: VM start until the guest agent answered. */
|
|
76
93
|
bootToReadyMs: number | null;
|
|
77
94
|
/** `result.host_timings_ms`: the host's own steps (restore: load, after_restore, ready, …). */
|
|
@@ -106,8 +123,8 @@ interface EventBase {
|
|
|
106
123
|
}
|
|
107
124
|
/**
|
|
108
125
|
* - `phase`: a phase began (live progress: "capacity_pending: no_ready_host"). `tool` phases come from tool calls.
|
|
109
|
-
* A `capacity_pending` phase carries `deadlineAt` (0.6.2+, when the API reports it):
|
|
110
|
-
*
|
|
126
|
+
* A `capacity_pending` phase carries `deadlineAt` (0.6.2+, when the API reports it): the start's deadline, past which
|
|
127
|
+
* it fails with `capacity_unavailable` (retryable; nothing was started).
|
|
111
128
|
* - `retry`: a request is retried after a transient failure (also emitted for tool calls, action `tool`).
|
|
112
129
|
* - `done`: the call ended, successfully or not, with its full timing.
|
|
113
130
|
*/
|
|
@@ -129,9 +146,9 @@ export declare function emitTo(listeners: ReadonlyArray<ProgressListener | undef
|
|
|
129
146
|
/** Combines listeners (client-level and per call) into one; undefined when there are none. */
|
|
130
147
|
export declare function combineListeners(...listeners: Array<ProgressListener | undefined>): ProgressListener | undefined;
|
|
131
148
|
/**
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
149
|
+
* The deadline of a start in `capacity_pending`: the operation's `error.details.deadline_at` (RFC 3339). A start still
|
|
150
|
+
* queued then fails with `capacity_unavailable` (retryable; nothing was started). Null in any other state, or from an
|
|
151
|
+
* API that does not report it.
|
|
135
152
|
*/
|
|
136
153
|
export declare function capacityDeadlineOf(op: Operation): string | null;
|
|
137
154
|
/** Server timing from an operation as GET /v1/operations/{id} returns it. */
|
|
@@ -152,7 +169,7 @@ export declare class Trace {
|
|
|
152
169
|
get finished(): LifecycleTiming | null;
|
|
153
170
|
/**
|
|
154
171
|
* Enters a sequential phase (closing the current one). The same phase and reason again is not a new phase.
|
|
155
|
-
* `deadlineAt`:
|
|
172
|
+
* `deadlineAt`: the deadline of a `capacity_pending` start (added to the event only).
|
|
156
173
|
*/
|
|
157
174
|
phase(phase: LifecyclePhase, reason?: string | null, deadlineAt?: string | null): void;
|
|
158
175
|
/** Runs `fn` as a phase that may overlap others (open() reads the view and issues the token together). */
|
|
@@ -168,13 +185,16 @@ export declare class Trace {
|
|
|
168
185
|
/** Runs `fn` under `trace` and ends the trace either way (the error keeps its timing). */
|
|
169
186
|
export declare function traced<T>(trace: Trace, fn: () => Promise<T>): Promise<T>;
|
|
170
187
|
/**
|
|
171
|
-
* A human-readable account of a timing, for logs and bug reports:
|
|
188
|
+
* A human-readable account of a timing, for logs and bug reports. A resume in production:
|
|
189
|
+
*
|
|
190
|
+
* resume 413 ms, succeeded (workspace <id>, operation <id>)
|
|
191
|
+
* client: request 218 ms → queued 195 ms
|
|
192
|
+
* server: queued 51 ms, ran 290 ms, total 341 ms; resume from local_cache, boot to ready 211 ms, host disk 0 ms, load 6 ms, ready 62 ms, total 211 ms, after_restore 36 ms
|
|
193
|
+
* outside the server: 72 ms
|
|
172
194
|
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
* outside the server: 161 ms
|
|
177
|
-
* retries: 1 (POST /v1/workspaces/open, HTTP 503 unavailable, after 200 ms)
|
|
195
|
+
* A call that retried a request adds `retries: <n> (<request>, <cause>, after <delay>)`.
|
|
196
|
+
* A resume that booted the workspace instead of restoring its memory (0.11.0+) says so in the server line:
|
|
197
|
+
* `resume from cold_boot: processes restarted (runtime_changed)`.
|
|
178
198
|
*/
|
|
179
199
|
export declare function formatTiming(t: LifecycleTiming): string;
|
|
180
200
|
export {};
|
package/dist/progress.js
CHANGED
|
@@ -31,9 +31,9 @@ function diffMs(from, to) {
|
|
|
31
31
|
const str = (v) => (typeof v === 'string' && v.length > 0 ? v : null);
|
|
32
32
|
const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : null);
|
|
33
33
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
34
|
+
* The deadline of a start in `capacity_pending`: the operation's `error.details.deadline_at` (RFC 3339). A start still
|
|
35
|
+
* queued then fails with `capacity_unavailable` (retryable; nothing was started). Null in any other state, or from an
|
|
36
|
+
* API that does not report it.
|
|
37
37
|
*/
|
|
38
38
|
export function capacityDeadlineOf(op) {
|
|
39
39
|
if (op.state !== 'capacity_pending')
|
|
@@ -63,6 +63,9 @@ export function serverTiming(op) {
|
|
|
63
63
|
startPath: str(r.start_path),
|
|
64
64
|
warmFallback: str(r.warm_fallback),
|
|
65
65
|
resumePath: str(r.resume_path),
|
|
66
|
+
// Unknown (null) unless the result says so: a result without the field is never read as "not restored".
|
|
67
|
+
memoryRestored: typeof r.memory_restored === 'boolean' ? r.memory_restored : null,
|
|
68
|
+
coldBootReason: str(r.cold_boot_reason),
|
|
66
69
|
bootToReadyMs: num(r.boot_to_ready_ms),
|
|
67
70
|
hostTimingsMs,
|
|
68
71
|
};
|
|
@@ -128,7 +131,7 @@ export class Trace {
|
|
|
128
131
|
}
|
|
129
132
|
/**
|
|
130
133
|
* Enters a sequential phase (closing the current one). The same phase and reason again is not a new phase.
|
|
131
|
-
* `deadlineAt`:
|
|
134
|
+
* `deadlineAt`: the deadline of a `capacity_pending` start (added to the event only).
|
|
132
135
|
*/
|
|
133
136
|
phase(phase, reason = null, deadlineAt = null) {
|
|
134
137
|
if (this.#timing)
|
|
@@ -215,13 +218,16 @@ export async function traced(trace, fn) {
|
|
|
215
218
|
}
|
|
216
219
|
const fmt = (ms) => (ms === null ? '?' : ms < 1000 ? `${Math.round(ms)} ms` : `${(ms / 1000).toFixed(2)} s`);
|
|
217
220
|
/**
|
|
218
|
-
* A human-readable account of a timing, for logs and bug reports:
|
|
221
|
+
* A human-readable account of a timing, for logs and bug reports. A resume in production:
|
|
219
222
|
*
|
|
220
|
-
*
|
|
221
|
-
* client: request
|
|
222
|
-
* server: queued
|
|
223
|
-
* outside the server:
|
|
224
|
-
*
|
|
223
|
+
* resume 413 ms, succeeded (workspace <id>, operation <id>)
|
|
224
|
+
* client: request 218 ms → queued 195 ms
|
|
225
|
+
* server: queued 51 ms, ran 290 ms, total 341 ms; resume from local_cache, boot to ready 211 ms, host disk 0 ms, load 6 ms, ready 62 ms, total 211 ms, after_restore 36 ms
|
|
226
|
+
* outside the server: 72 ms
|
|
227
|
+
*
|
|
228
|
+
* A call that retried a request adds `retries: <n> (<request>, <cause>, after <delay>)`.
|
|
229
|
+
* A resume that booted the workspace instead of restoring its memory (0.11.0+) says so in the server line:
|
|
230
|
+
* `resume from cold_boot: processes restarted (runtime_changed)`.
|
|
225
231
|
*/
|
|
226
232
|
export function formatTiming(t) {
|
|
227
233
|
const ids = [t.workspaceId ? `workspace ${t.workspaceId}` : null, t.operationId ? `operation ${t.operationId}` : null].filter(Boolean).join(', ');
|
|
@@ -242,7 +248,7 @@ export function formatTiming(t) {
|
|
|
242
248
|
const parts = [s.queuedMs !== null ? `queued ${fmt(s.queuedMs)}` : null, s.runMs !== null ? `ran ${fmt(s.runMs)}` : null, s.totalMs !== null ? `total ${fmt(s.totalMs)}` : `still ${s.state}`];
|
|
243
249
|
const how = [
|
|
244
250
|
s.startPath ? `start ${s.startPath}${s.warmFallback ? ` (warm fallback: ${s.warmFallback})` : ''}` : null,
|
|
245
|
-
s.resumePath ? `resume from ${s.resumePath}` : null,
|
|
251
|
+
s.resumePath ? `resume from ${s.resumePath}${s.memoryRestored === false ? `: processes restarted${s.coldBootReason ? ` (${s.coldBootReason})` : ''}` : ''}` : null,
|
|
246
252
|
s.bootToReadyMs !== null ? `boot to ready ${fmt(s.bootToReadyMs)}` : null,
|
|
247
253
|
s.hostTimingsMs ? `host ${Object.entries(s.hostTimingsMs).map(([k, v]) => `${k} ${fmt(v)}`).join(', ')}` : null,
|
|
248
254
|
].filter(Boolean);
|
package/dist/tar.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A small tar writer for build uploads of folders (
|
|
2
|
+
* A small tar writer for build uploads of folders (uncompressed ustar/pax, extracted by the host's
|
|
3
3
|
* static tool). Pure: no Node imports, so the browser bundle can carry it.
|
|
4
4
|
*
|
|
5
5
|
* The bytes equal CPython's `tarfile.open(mode="w", format=tarfile.PAX_FORMAT)` with every member added by hand (the
|
package/dist/tar.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* A small tar writer for build uploads of folders (
|
|
2
|
+
* A small tar writer for build uploads of folders (uncompressed ustar/pax, extracted by the host's
|
|
3
3
|
* static tool). Pure: no Node imports, so the browser bundle can carry it.
|
|
4
4
|
*
|
|
5
5
|
* The bytes equal CPython's `tarfile.open(mode="w", format=tarfile.PAX_FORMAT)` with every member added by hand (the
|
package/dist/template-file.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export declare class TemplateFileError extends Error {
|
|
|
22
22
|
readonly path: string | undefined;
|
|
23
23
|
constructor(message: string, path?: string);
|
|
24
24
|
}
|
|
25
|
-
/** Largest single upload (
|
|
25
|
+
/** Largest single upload (5 GiB, one presigned PUT). */
|
|
26
26
|
export declare const UPLOAD_BYTES_MAX = 5368709120;
|
|
27
27
|
/** Most entries a folder tar may have (the host's extraction limit, §24.2). */
|
|
28
28
|
export declare const TAR_ENTRIES_MAX = 200000;
|
package/dist/template-file.js
CHANGED
|
@@ -33,7 +33,7 @@ export class TemplateFileError extends Error {
|
|
|
33
33
|
this.path = path;
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
/** Largest single upload (
|
|
36
|
+
/** Largest single upload (5 GiB, one presigned PUT). */
|
|
37
37
|
export const UPLOAD_BYTES_MAX = 5_368_709_120;
|
|
38
38
|
/** Most entries a folder tar may have (the host's extraction limit, §24.2). */
|
|
39
39
|
export const TAR_ENTRIES_MAX = 200_000;
|
package/dist/templates.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Template registry, custom template builds (recipe v1 Dockerfiles and recipe v2
|
|
2
|
+
* Template registry, custom template builds (recipe v1 Dockerfiles and recipe v2), build uploads
|
|
3
3
|
* (§24.2), recipe export, version test instances, package search, the version file tree and diff, and template dev
|
|
4
4
|
* mode (drafts and test instances) over the application API (/v1). Registry and build types are written by hand and
|
|
5
5
|
* checked against the generated contract in type-checks.ts; the Templates v2 and template editor types alias the
|
|
@@ -15,7 +15,7 @@ import type { YamlParser } from './template-file.js';
|
|
|
15
15
|
import type { ToolName } from './tokens.js';
|
|
16
16
|
import { Workspace } from './workspace.js';
|
|
17
17
|
type S = components['schemas'];
|
|
18
|
-
/** Recipe v2
|
|
18
|
+
/** Recipe v2: the `recipe` of a build, the export's `recipe` and the document of template.yaml. */
|
|
19
19
|
export type TemplateRecipeV2 = S['TemplateRecipeV2'];
|
|
20
20
|
/** One `build.files[]` entry: an upload (`upload: "sha256:<hex>"`), or in template.yaml a local path (`from`). */
|
|
21
21
|
export type TemplateRecipeV2File = NonNullable<TemplateRecipeV2['build']['files']>[number];
|
|
@@ -40,7 +40,7 @@ export type TemplateVersionRecipe = S['TemplateVersionRecipe'];
|
|
|
40
40
|
export type TemplatePackage = S['TemplatePackage'];
|
|
41
41
|
export type TemplatePackagePage = S['TemplatePackagePage'];
|
|
42
42
|
export type TemplatePackageEcosystem = 'apt' | 'pip' | 'npm';
|
|
43
|
-
/** The languages a base offers a recipe v2 (
|
|
43
|
+
/** The languages a base offers a recipe v2 (`GET …/template-languages`): the language table for its platform base. */
|
|
44
44
|
export type TemplateLanguages = S['TemplateLanguages'];
|
|
45
45
|
export type TemplateLanguage = TemplateLanguages['data'][number];
|
|
46
46
|
export type CreateVersionTestInstanceBody = S['CreateVersionTestInstanceBody'];
|
|
@@ -52,18 +52,18 @@ export type TemplateBuildRecipeV2 = Extract<NonNullable<S['TemplateBuild']['reci
|
|
|
52
52
|
}>;
|
|
53
53
|
/** Start commands and services of a workspace's version (§24.4); null when it has none. */
|
|
54
54
|
export type WorkspaceStartup = S['WorkspaceStartup'];
|
|
55
|
-
/** Manifest v2 `defaults` of a version
|
|
55
|
+
/** Manifest v2 `defaults` of a version. */
|
|
56
56
|
export type TemplateDefaults = S['TemplateDefaults'];
|
|
57
57
|
/** How a version was produced: a recipe build, a saved workspace (or draft publish), or git (reserved). */
|
|
58
58
|
export type TemplateSource = S['TemplateSource'];
|
|
59
59
|
/** The version's file list state (the tree and diff routes read it). */
|
|
60
60
|
export type TemplateFilesSummary = S['TemplateFilesSummary'];
|
|
61
|
-
/** Storage of a template version
|
|
61
|
+
/** Storage of a template version. */
|
|
62
62
|
export type TemplateStorage = S['TemplateStorage'];
|
|
63
63
|
export type TemplateStorageWarning = S['TemplateStorageWarning'];
|
|
64
64
|
/** Template storage of an organization (counts toward retained_state_gib). */
|
|
65
65
|
export type OrgTemplateStorage = S['OrgTemplateStorage'];
|
|
66
|
-
/** One inode path of a template version
|
|
66
|
+
/** One inode path of a template version. */
|
|
67
67
|
export type TemplateFileEntry = S['TemplateFileEntry'];
|
|
68
68
|
/** One directory level of a version's tree (keyset-paginated). */
|
|
69
69
|
export type TemplateFilePage = S['TemplateFilePage'];
|
|
@@ -72,7 +72,7 @@ export type TemplateDiffEntry = S['TemplateDiffEntry'];
|
|
|
72
72
|
export type TemplateDiffChange = TemplateDiffEntry['change'];
|
|
73
73
|
/** One page of a version diff; the first page (no cursor) carries `summary`. */
|
|
74
74
|
export type TemplateDiffPage = S['TemplateDiffPage'];
|
|
75
|
-
/** The live draft of an organization template
|
|
75
|
+
/** The live draft of an organization template. */
|
|
76
76
|
export type TemplateDraft = S['TemplateDraft'];
|
|
77
77
|
/** A disk-only capture of the draft (a test instance or a publish starts from one). */
|
|
78
78
|
export type DraftState = S['DraftState'];
|
|
@@ -164,7 +164,7 @@ export interface TemplateVersion {
|
|
|
164
164
|
rootfs_sha256: string | null;
|
|
165
165
|
} | null;
|
|
166
166
|
defaults: TemplateDefaults;
|
|
167
|
-
/** What a workspace of this version gets when it opens (0.7.0
|
|
167
|
+
/** What a workspace of this version gets when it opens (0.7.0). `defaults` equals `settings.defaults`. */
|
|
168
168
|
settings: TemplateSettings;
|
|
169
169
|
/** The file list the tree and diff read (`loaded` when files() and diff() can answer). */
|
|
170
170
|
files: TemplateFilesSummary;
|
|
@@ -199,7 +199,7 @@ export interface TemplateSummary {
|
|
|
199
199
|
created_at: string;
|
|
200
200
|
archived_at: string | null;
|
|
201
201
|
shadowed_by_organization_template: boolean;
|
|
202
|
-
/** Mutable template-level defaults
|
|
202
|
+
/** Mutable template-level defaults: the size of a start without caps.memory_mib, and the idle policy of a workspace that sets none. */
|
|
203
203
|
defaults: {
|
|
204
204
|
memory_mib: number | null;
|
|
205
205
|
idle_policy: string | null;
|
|
@@ -347,7 +347,7 @@ export interface TemplateBuild {
|
|
|
347
347
|
};
|
|
348
348
|
publishable: boolean;
|
|
349
349
|
builder_availability: BuilderAvailability;
|
|
350
|
-
/** `recipe` (Dockerfile dialect) or `workspace` (save-as-template, draft publish
|
|
350
|
+
/** `recipe` (Dockerfile dialect) or `workspace` (save-as-template, draft publish). */
|
|
351
351
|
source_kind: 'recipe' | 'workspace';
|
|
352
352
|
source_workspace_id: string | null;
|
|
353
353
|
/** The captured checkpoint (null until the capture operation succeeded). */
|
|
@@ -385,7 +385,7 @@ export interface CreateTemplateBuildParams {
|
|
|
385
385
|
displayName?: string;
|
|
386
386
|
/**
|
|
387
387
|
* Recipe v1 (a Dockerfile) or recipe v2 (0.7.0; `schema: "shardflux.template-recipe.v2"`: languages, packages,
|
|
388
|
-
* uploaded files, steps, auto network and settings
|
|
388
|
+
* uploaded files, steps, auto network and settings). Recipe v2 files reference uploads
|
|
389
389
|
* (`templates.uploads.put()`); `buildFromFile()` / `buildFromRecipe()` upload local `from` paths for you.
|
|
390
390
|
*/
|
|
391
391
|
recipe: TemplateRecipe | TemplateRecipeV2;
|
|
@@ -411,7 +411,7 @@ export interface WaitForBuildOptions {
|
|
|
411
411
|
/** Backoff used when the server does not hold the poll (default 1 s doubling to 10 s). */
|
|
412
412
|
pollIntervalMs?: number;
|
|
413
413
|
maxPollIntervalMs?: number;
|
|
414
|
-
/** Ask the server to hold each poll until the build changes (`Prefer: wait
|
|
414
|
+
/** Ask the server to hold each poll until the build changes (`Prefer: wait`; default true). */
|
|
415
415
|
serverWait?: boolean;
|
|
416
416
|
signal?: AbortSignal;
|
|
417
417
|
/** Called with each build view the wait observes whose state or registration changed (0.7.0), the settled one included. */
|
|
@@ -429,7 +429,7 @@ export interface SaveAsTemplateResponse {
|
|
|
429
429
|
operation: Operation | null;
|
|
430
430
|
build: TemplateBuild;
|
|
431
431
|
}
|
|
432
|
-
/** Save-as-template
|
|
432
|
+
/** Save-as-template: everything in the workspace, minus the sf-scrub.v1 list, becomes one new org layer. */
|
|
433
433
|
export interface SaveAsTemplateParams {
|
|
434
434
|
/** Organization template to save into (created when absent; platform slugs are refused with platform_template_slug). */
|
|
435
435
|
templateSlug: string;
|
|
@@ -440,7 +440,7 @@ export interface SaveAsTemplateParams {
|
|
|
440
440
|
/** Defaults of the new version (default: the source version's, else persistent). */
|
|
441
441
|
defaults?: TemplateDefaultsInput;
|
|
442
442
|
/**
|
|
443
|
-
* Settings of the new version (0.7.0
|
|
443
|
+
* Settings of the new version (0.7.0): each field given replaces that field of the source version's
|
|
444
444
|
* settings, each field left out is carried forward. `settings.defaults` together with `defaults` is 422 invalid_settings.
|
|
445
445
|
*/
|
|
446
446
|
settings?: TemplateSettingsInput;
|
|
@@ -536,7 +536,7 @@ export interface DraftOpened {
|
|
|
536
536
|
operation: Operation | null;
|
|
537
537
|
}
|
|
538
538
|
/**
|
|
539
|
-
* Template dev mode for one organization template
|
|
539
|
+
* Template dev mode for one organization template: the single live draft (a layered, persistent
|
|
540
540
|
* workspace on the draft base), its captured states, disposable test instances (session workspaces on a copy of a
|
|
541
541
|
* state) and publishing the draft as the next version. Mutations need build access (owners/admins, API keys with a
|
|
542
542
|
* tool permission); others get 403 forbidden with details.reason template_dev_mode_role.
|
|
@@ -654,7 +654,7 @@ export declare class TemplateUploadError extends Error {
|
|
|
654
654
|
constructor(sha256: string, status: number, code: string | null, detail?: string);
|
|
655
655
|
}
|
|
656
656
|
/**
|
|
657
|
-
* Build uploads
|
|
657
|
+
* Build uploads: files and folders a recipe v2 copies into the template, stored once per
|
|
658
658
|
* organization and content (SHA-256). Needs build access (API keys with a tool permission). Uploads count toward the
|
|
659
659
|
* organization's template storage while they exist; one nothing references is deleted 7 days later.
|
|
660
660
|
*/
|
|
@@ -795,7 +795,7 @@ export interface CreateVersionTestInstanceParams {
|
|
|
795
795
|
idempotencyKey?: string;
|
|
796
796
|
}
|
|
797
797
|
/**
|
|
798
|
-
* Test instances of a version
|
|
798
|
+
* Test instances of a version: a session workspace on a registered version of the organization's
|
|
799
799
|
* template, published or not, so a build can be tried before it is published. Owners, admins and API keys with a
|
|
800
800
|
* tool permission (403 template_dev_mode_role otherwise).
|
|
801
801
|
*/
|
|
@@ -805,7 +805,7 @@ export declare class TemplateVersionTestInstancesApi {
|
|
|
805
805
|
/** Opens one (202; waits until ready unless `wait: false`). It ends with close() or when idle. */
|
|
806
806
|
create(slug: string, version: number, params?: CreateVersionTestInstanceParams): Promise<Workspace>;
|
|
807
807
|
}
|
|
808
|
-
/** Package names for the editor's pickers
|
|
808
|
+
/** Package names for the editor's pickers: apt (a base's index), pip (names only) and npm. */
|
|
809
809
|
export declare class TemplatePackagesApi {
|
|
810
810
|
#private;
|
|
811
811
|
constructor(ctx: () => ClientContext);
|
|
@@ -848,7 +848,7 @@ export declare class TemplatesApi {
|
|
|
848
848
|
organizationId?: string;
|
|
849
849
|
}): Promise<TemplateLanguages>;
|
|
850
850
|
/**
|
|
851
|
-
* Node only: builds a template from template.yaml (or a .json file with the same document
|
|
851
|
+
* Node only: builds a template from template.yaml (or a .json file with the same document). The
|
|
852
852
|
* file is recipe v2; each `build.files[]` entry may name a local `from` path (relative to the file): folders are
|
|
853
853
|
* packed as the reproducible tar, files are sent as they are, both uploaded unless the organization already has
|
|
854
854
|
* them, and the build is created (and awaited with `wait`). YAML needs the optional `yaml` package or `parseYaml`.
|
|
@@ -885,7 +885,7 @@ export declare class TemplatesApi {
|
|
|
885
885
|
owner?: TemplateOwner;
|
|
886
886
|
}): Promise<TemplateDetail | null>;
|
|
887
887
|
/**
|
|
888
|
-
* One directory level of a version's file tree
|
|
888
|
+
* One directory level of a version's file tree, sorted by name bytes. 409 conflict with
|
|
889
889
|
* details.reason file_list_unavailable (no file list) or file_list_indexing (retryable); 404 path_not_found or
|
|
890
890
|
* version_not_found; 422 invalid_path. File contents are not served: open a draft or test instance for that.
|
|
891
891
|
*/
|
|
@@ -901,7 +901,7 @@ export declare class TemplatesApi {
|
|
|
901
901
|
diff(slug: string, params: TemplateDiffParams): Promise<TemplateDiffPage>;
|
|
902
902
|
/** Every diff entry, following next_cursor. */
|
|
903
903
|
diffAll(slug: string, params: Omit<TemplateDiffParams, 'cursor'>): AsyncGenerator<TemplateDiffEntry>;
|
|
904
|
-
/** Dev mode of one organization template: its draft, states, test instances and publish
|
|
904
|
+
/** Dev mode of one organization template: its draft, states, test instances and publish. */
|
|
905
905
|
draft(slug: string, params?: {
|
|
906
906
|
organizationId?: string;
|
|
907
907
|
}): TemplateDraftApi;
|
package/dist/templates.js
CHANGED
|
@@ -53,7 +53,7 @@ async function openedWorkspace(ctx, res, p) {
|
|
|
53
53
|
return { workspace: new Workspace(ctx, view, wrap), operation };
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
|
-
* Template dev mode for one organization template
|
|
56
|
+
* Template dev mode for one organization template: the single live draft (a layered, persistent
|
|
57
57
|
* workspace on the draft base), its captured states, disposable test instances (session workspaces on a copy of a
|
|
58
58
|
* state) and publishing the draft as the next version. Mutations need build access (owners/admins, API keys with a
|
|
59
59
|
* tool permission); others get 403 forbidden with details.reason template_dev_mode_role.
|
|
@@ -369,7 +369,7 @@ async function sendUpload(ctx, meta, body, organizationId, signal) {
|
|
|
369
369
|
return { upload: again.body.upload, ref, uploaded: true };
|
|
370
370
|
}
|
|
371
371
|
/**
|
|
372
|
-
* Build uploads
|
|
372
|
+
* Build uploads: files and folders a recipe v2 copies into the template, stored once per
|
|
373
373
|
* organization and content (SHA-256). Needs build access (API keys with a tool permission). Uploads count toward the
|
|
374
374
|
* organization's template storage while they exist; one nothing references is deleted 7 days later.
|
|
375
375
|
*/
|
|
@@ -458,7 +458,7 @@ function uploadLocal(ctx, src, organizationId, signal) {
|
|
|
458
458
|
return sendUpload(ctx, { sha256: src.sha256, size: src.size, kind: src.kind }, { open: () => fileBody(src.uploadPath), replayable: true }, organizationId, signal);
|
|
459
459
|
}
|
|
460
460
|
const isRecord = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
461
|
-
// ---- recipe export, version test instances, package search
|
|
461
|
+
// ---- recipe export, version test instances, package search --------------------------------------------
|
|
462
462
|
export class TemplateVersionsApi {
|
|
463
463
|
#ctx;
|
|
464
464
|
constructor(ctx) {
|
|
@@ -475,7 +475,7 @@ export class TemplateVersionsApi {
|
|
|
475
475
|
}
|
|
476
476
|
}
|
|
477
477
|
/**
|
|
478
|
-
* Test instances of a version
|
|
478
|
+
* Test instances of a version: a session workspace on a registered version of the organization's
|
|
479
479
|
* template, published or not, so a build can be tried before it is published. Owners, admins and API keys with a
|
|
480
480
|
* tool permission (403 template_dev_mode_role otherwise).
|
|
481
481
|
*/
|
|
@@ -504,7 +504,7 @@ export class TemplateVersionTestInstancesApi {
|
|
|
504
504
|
return (await openedWorkspace(ctx, res, params)).workspace;
|
|
505
505
|
}
|
|
506
506
|
}
|
|
507
|
-
/** Package names for the editor's pickers
|
|
507
|
+
/** Package names for the editor's pickers: apt (a base's index), pip (names only) and npm. */
|
|
508
508
|
export class TemplatePackagesApi {
|
|
509
509
|
#ctx;
|
|
510
510
|
constructor(ctx) {
|
|
@@ -574,7 +574,7 @@ export class TemplatesApi {
|
|
|
574
574
|
return this.#organization;
|
|
575
575
|
}
|
|
576
576
|
/**
|
|
577
|
-
* Node only: builds a template from template.yaml (or a .json file with the same document
|
|
577
|
+
* Node only: builds a template from template.yaml (or a .json file with the same document). The
|
|
578
578
|
* file is recipe v2; each `build.files[]` entry may name a local `from` path (relative to the file): folders are
|
|
579
579
|
* packed as the reproducible tar, files are sent as they are, both uploaded unless the organization already has
|
|
580
580
|
* them, and the build is created (and awaited with `wait`). YAML needs the optional `yaml` package or `parseYaml`.
|
|
@@ -705,7 +705,7 @@ export class TemplatesApi {
|
|
|
705
705
|
}
|
|
706
706
|
}
|
|
707
707
|
/**
|
|
708
|
-
* One directory level of a version's file tree
|
|
708
|
+
* One directory level of a version's file tree, sorted by name bytes. 409 conflict with
|
|
709
709
|
* details.reason file_list_unavailable (no file list) or file_list_indexing (retryable); 404 path_not_found or
|
|
710
710
|
* version_not_found; 422 invalid_path. File contents are not served: open a draft or test instance for that.
|
|
711
711
|
*/
|
|
@@ -741,7 +741,7 @@ export class TemplatesApi {
|
|
|
741
741
|
cursor = page.next_cursor ?? undefined;
|
|
742
742
|
} while (cursor !== undefined);
|
|
743
743
|
}
|
|
744
|
-
/** Dev mode of one organization template: its draft, states, test instances and publish
|
|
744
|
+
/** Dev mode of one organization template: its draft, states, test instances and publish. */
|
|
745
745
|
draft(slug, params = {}) {
|
|
746
746
|
return new TemplateDraftApi(this.#ctx, slug, params.organizationId);
|
|
747
747
|
}
|
package/dist/tools.d.ts
CHANGED
|
@@ -49,7 +49,7 @@ export declare function validateArgs(schema: JsonSchema, value: unknown, path?:
|
|
|
49
49
|
export interface WorkspaceToolsOptions {
|
|
50
50
|
/**
|
|
51
51
|
* Tool permissions to expose (default: the tools of the workspace's last token, else all). A file-first workspace
|
|
52
|
-
* (`workspace.mode
|
|
52
|
+
* (`workspace.mode`) gets only the `exec` and `files` tools: `exec` runs each command as an execution
|
|
53
53
|
* (a fresh VM on the workspace's files; the result adds `execution_id`, `state`, `changed` and `tree_revision`), and
|
|
54
54
|
* the process, terminal, git and browser tools are not offered because nothing runs between executions.
|
|
55
55
|
*/
|
|
@@ -70,7 +70,7 @@ export interface WorkspaceToolsOptions {
|
|
|
70
70
|
* Send `workspace.hint()` when a tool call starts, without waiting for it (default true; 0.9.0+), so a parked
|
|
71
71
|
* workspace is being restored while the call is prepared. Pass false when you call `workspace.hint()` yourself
|
|
72
72
|
* earlier (e.g. when the model starts streaming a tool call). `read_file`, `list_files` and `search_files` never send
|
|
73
|
-
* it: a sleeping workspace serves them from its disk without waking
|
|
73
|
+
* it: a sleeping workspace serves them from its disk without waking, and the hint would wake a
|
|
74
74
|
* suspended workspace (or restore a hibernated one) that the read does not need.
|
|
75
75
|
*/
|
|
76
76
|
hint?: boolean;
|
|
@@ -81,7 +81,7 @@ export interface WorkspaceToolsOptions {
|
|
|
81
81
|
mode?: WorkspaceMode;
|
|
82
82
|
/**
|
|
83
83
|
* File-first workspaces: called with the execution id before the `exec` tool sends its execution (0.9.0+). An
|
|
84
|
-
* execution
|
|
84
|
+
* execution runs to completion, so a caller that stops waiting (an aborted signal) can still fetch its result later
|
|
85
85
|
* with `workspace.executions.get(id)`.
|
|
86
86
|
*/
|
|
87
87
|
onExecution?: (executionId: string) => void;
|