@loomcycle/client 1.111.0 → 1.113.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/dist/errors.d.ts CHANGED
@@ -31,6 +31,21 @@ export declare class LoomcycleError extends Error {
31
31
  bodyText?: string;
32
32
  code?: string;
33
33
  });
34
+ /** Whether the same call, sent again unchanged, can succeed once time has
35
+ * passed: true for a refusal that clears on its own (backpressure, a rate
36
+ * limit, a per-user run quota, a paused runtime, a decision-model call
37
+ * that failed or timed out), false for everything else, including a hard
38
+ * token budget, a cap the caller must make room under, a bad request and
39
+ * a missing resource. A retry loop can test this instead of a list of
40
+ * classes.
41
+ *
42
+ * It is a getter rather than a constructor field so that a subclass states
43
+ * its answer by overriding it, without a constructor option any caller
44
+ * could set. False is the default because a wrong `true` turns a refusal
45
+ * that never clears into a loop that never ends, while a wrong `false`
46
+ * only surfaces an error the caller could have waited out. The client
47
+ * itself never retries; bound your own retries even when this is true. */
48
+ get retryable(): boolean;
34
49
  }
35
50
  /** Base class for every HTTP 404 the client surfaces. Lets callers
36
51
  * catch any not-found case with a single `instanceof NotFoundError`
@@ -72,16 +87,45 @@ export declare class AgentIDInUseError extends LoomcycleError {
72
87
  code?: string;
73
88
  });
74
89
  }
75
- /** Every HTTP 429 that is not a per-user quota. A plain BackpressureError is
76
- * the transient case (the server is busy; back off and retry). It has one
77
- * subclass that is NOT transient, TokenLimitExceededError — check for that
78
- * first when deciding whether to retry. */
90
+ /** An HTTP 429 that clears on its own: the server is busy (`backpressure`),
91
+ * a provider's queue is full (`provider_concurrency_exhausted`), or the
92
+ * caller is starting runs too fast (`rate_limited`, raised as the
93
+ * RateLimitedError subclass). Back off and retry; `retryable` is true.
94
+ *
95
+ * One code under this class is the exception: `configured_run_cap` (the user
96
+ * holds as many configured runs as allowed; start or discard one first)
97
+ * needs the caller to act, so its `retryable` is false. It stays a
98
+ * BackpressureError, the class every other 429 lands in.
99
+ *
100
+ * Two 429s are not this class: a per-user run quota
101
+ * (PerUserQuotaExhaustedError, also retryable) and a hard token budget
102
+ * (TokenLimitExceededError, not retryable). */
79
103
  export declare class BackpressureError extends LoomcycleError {
80
104
  constructor(message: string, opts?: {
81
105
  status?: number;
82
106
  bodyText?: string;
83
107
  code?: string;
84
108
  });
109
+ get retryable(): boolean;
110
+ }
111
+ /**
112
+ * RateLimitedError signals that the caller is starting runs faster than its
113
+ * per-caller run-start rate allows: HTTP 429 with body code `rate_limited`.
114
+ * The server says when the next start will be admitted in `Retry-After`,
115
+ * surfaced here as `retryAfterMs`; wait that long rather than backing off on
116
+ * a guess. Retryable, like every BackpressureError.
117
+ */
118
+ export declare class RateLimitedError extends BackpressureError {
119
+ /** Server-suggested retry window in milliseconds, from the Retry-After
120
+ * header. Null when the header is absent or not a whole number of
121
+ * seconds. */
122
+ readonly retryAfterMs: number | null;
123
+ constructor(message: string, opts?: {
124
+ status?: number;
125
+ bodyText?: string;
126
+ code?: string;
127
+ retryAfterMs?: number;
128
+ });
85
129
  }
86
130
  /**
87
131
  * TokenLimitExceededError signals that the caller is at a hard token budget:
@@ -92,20 +136,18 @@ export declare class BackpressureError extends LoomcycleError {
92
136
  * month's tokens for an operator, tenant or user; the same call is refused
93
137
  * until an operator raises the budget or the window rolls over.
94
138
  *
95
- * It extends BackpressureError only so that code written before this class
96
- * existed, which caught this refusal with `instanceof BackpressureError`,
97
- * keeps catching it. Test for this class BEFORE BackpressureError:
98
- *
99
- * if (e instanceof TokenLimitExceededError) {
100
- * // not retryable now: report e.scope / e.used / e.limit
101
- * } else if (e instanceof BackpressureError) {
102
- * // transient: back off and retry
103
- * }
139
+ * It is not a BackpressureError, and `retryable` is false. It used to
140
+ * extend BackpressureError so that an older `instanceof BackpressureError`
141
+ * check kept catching it, but such a check is almost always a retry loop, and
142
+ * that loop then retried a refusal that cannot clear for the rest of the
143
+ * month. The relation was dropped on purpose: a retry loop keyed on
144
+ * BackpressureError or on `retryable` now stops here, and code that wants to
145
+ * report the budget tests for this class.
104
146
  *
105
147
  * The fields come from the response body and are null when the server did
106
148
  * not send them.
107
149
  */
108
- export declare class TokenLimitExceededError extends BackpressureError {
150
+ export declare class TokenLimitExceededError extends LoomcycleError {
109
151
  /** Whose budget was hit: "operator", "tenant" or "user". */
110
152
  readonly scope: string | null;
111
153
  /** The id of that scope: the tenant id or the user subject. Null for the
@@ -178,6 +220,9 @@ export declare class PerUserQuotaExhaustedError extends LoomcycleError {
178
220
  cap?: number;
179
221
  retryAfterMs?: number;
180
222
  });
223
+ /** The quota counts the caller's own in-flight runs, so it frees up as
224
+ * they finish. */
225
+ get retryable(): boolean;
181
226
  }
182
227
  export declare class AuthError extends LoomcycleError {
183
228
  constructor(message: string, opts?: {
@@ -186,6 +231,37 @@ export declare class AuthError extends LoomcycleError {
186
231
  code?: string;
187
232
  });
188
233
  }
234
+ /** An HTTP 403 because the bearer token lacks a scope the call needs: body code
235
+ * `insufficient_scope`. The token is valid; it was minted without that
236
+ * grant. Ask an operator for a token that carries `requiredScope`; sending
237
+ * the same call again never succeeds, so `retryable` is false.
238
+ *
239
+ * Any other 403 (`restricted_token`, `operator_key_restricted`, …) stays a
240
+ * plain LoomcycleError: those refuse the caller for something a new scope
241
+ * does not fix. */
242
+ export declare class InsufficientScopeError extends LoomcycleError {
243
+ /** The scope the token lacks, e.g. `runs:create` or `substrate:tenant`.
244
+ * Read from the body's `required_scope`, or, from a server that predates
245
+ * that field, from the `WWW-Authenticate: Bearer scope="…"` header. Null
246
+ * when neither names one (a browser does not see that header on a
247
+ * cross-origin response unless the server exposes it). */
248
+ readonly requiredScope: string | null;
249
+ constructor(message: string, opts?: {
250
+ status?: number;
251
+ bodyText?: string;
252
+ code?: string;
253
+ requiredScope?: string;
254
+ });
255
+ }
256
+ /** Every HTTP 503. The status is shared between a condition that clears on
257
+ * its own and features this deployment does not have
258
+ * (`decision_not_configured`, `store_unavailable`, `vector_unsupported`, …),
259
+ * which never will, and many 503 bodies carry no code at all. So
260
+ * `retryable` is true only for `runtime_paused` (new runs are refused while
261
+ * the operator has the runtime paused) and false otherwise. A code-less 503
262
+ * from run creation can also be a model tier with no provider available
263
+ * right now; retry that one on your own judgement, with a bound. (The
264
+ * inherited `retryable` reads `runtime_paused` from TRANSIENT_CODES.) */
189
265
  export declare class UnavailableError extends LoomcycleError {
190
266
  constructor(message: string, opts?: {
191
267
  status?: number;
@@ -209,6 +285,8 @@ export declare class PauseNotConfiguredError extends UnavailableError {
209
285
  bodyText?: string;
210
286
  code?: string;
211
287
  });
288
+ /** The server has no pause manager; asking again does not give it one. */
289
+ get retryable(): boolean;
212
290
  }
213
291
  export declare class AlreadyPausingError extends LoomcycleError {
214
292
  constructor(message: string, opts?: {
package/dist/errors.js CHANGED
@@ -33,7 +33,42 @@ export class LoomcycleError extends Error {
33
33
  this.bodyText = opts?.bodyText;
34
34
  this.code = opts?.code;
35
35
  }
36
+ /** Whether the same call, sent again unchanged, can succeed once time has
37
+ * passed: true for a refusal that clears on its own (backpressure, a rate
38
+ * limit, a per-user run quota, a paused runtime, a decision-model call
39
+ * that failed or timed out), false for everything else, including a hard
40
+ * token budget, a cap the caller must make room under, a bad request and
41
+ * a missing resource. A retry loop can test this instead of a list of
42
+ * classes.
43
+ *
44
+ * It is a getter rather than a constructor field so that a subclass states
45
+ * its answer by overriding it, without a constructor option any caller
46
+ * could set. False is the default because a wrong `true` turns a refusal
47
+ * that never clears into a loop that never ends, while a wrong `false`
48
+ * only surfaces an error the caller could have waited out. The client
49
+ * itself never retries; bound your own retries even when this is true. */
50
+ get retryable() {
51
+ return this.code !== undefined && TRANSIENT_CODES.has(this.code);
52
+ }
36
53
  }
54
+ /** Codes that clear on their own although the class their status maps to
55
+ * does not: a 503 is mostly a feature the deployment lacks, and a 502 / 504
56
+ * is any upstream failure, so the class alone says false. The server
57
+ * classifies each of these as transient:
58
+ * - `runtime_paused` (503): new runs are refused until the operator resumes.
59
+ * - `call_failed` (502): a decision-model call did not complete.
60
+ * - `timeout` (504): a decision-model call did not answer in time. */
61
+ const TRANSIENT_CODES = new Set([
62
+ "runtime_paused",
63
+ "call_failed",
64
+ "timeout",
65
+ ]);
66
+ /** 429 codes that do NOT clear by waiting: the caller has to act first, so
67
+ * a retry loop on them never ends. `configured_run_cap`: the user already
68
+ * holds as many configured (not yet started) runs as the operator allows,
69
+ * and only starting or discarding one makes room. (A hard token budget,
70
+ * `token_limit_exceeded`, has a class of its own outside BackpressureError.) */
71
+ const CALLER_ACTION_429_CODES = new Set(["configured_run_cap"]);
37
72
  /** Base class for every HTTP 404 the client surfaces. Lets callers
38
73
  * catch any not-found case with a single `instanceof NotFoundError`
39
74
  * check, regardless of which specific resource was missing
@@ -69,15 +104,45 @@ export class AgentIDInUseError extends LoomcycleError {
69
104
  this.name = "AgentIDInUseError";
70
105
  }
71
106
  }
72
- /** Every HTTP 429 that is not a per-user quota. A plain BackpressureError is
73
- * the transient case (the server is busy; back off and retry). It has one
74
- * subclass that is NOT transient, TokenLimitExceededError — check for that
75
- * first when deciding whether to retry. */
107
+ /** An HTTP 429 that clears on its own: the server is busy (`backpressure`),
108
+ * a provider's queue is full (`provider_concurrency_exhausted`), or the
109
+ * caller is starting runs too fast (`rate_limited`, raised as the
110
+ * RateLimitedError subclass). Back off and retry; `retryable` is true.
111
+ *
112
+ * One code under this class is the exception: `configured_run_cap` (the user
113
+ * holds as many configured runs as allowed; start or discard one first)
114
+ * needs the caller to act, so its `retryable` is false. It stays a
115
+ * BackpressureError, the class every other 429 lands in.
116
+ *
117
+ * Two 429s are not this class: a per-user run quota
118
+ * (PerUserQuotaExhaustedError, also retryable) and a hard token budget
119
+ * (TokenLimitExceededError, not retryable). */
76
120
  export class BackpressureError extends LoomcycleError {
77
121
  constructor(message, opts) {
78
122
  super(message, opts);
79
123
  this.name = "BackpressureError";
80
124
  }
125
+ get retryable() {
126
+ return this.code === undefined || !CALLER_ACTION_429_CODES.has(this.code);
127
+ }
128
+ }
129
+ /**
130
+ * RateLimitedError signals that the caller is starting runs faster than its
131
+ * per-caller run-start rate allows: HTTP 429 with body code `rate_limited`.
132
+ * The server says when the next start will be admitted in `Retry-After`,
133
+ * surfaced here as `retryAfterMs`; wait that long rather than backing off on
134
+ * a guess. Retryable, like every BackpressureError.
135
+ */
136
+ export class RateLimitedError extends BackpressureError {
137
+ /** Server-suggested retry window in milliseconds, from the Retry-After
138
+ * header. Null when the header is absent or not a whole number of
139
+ * seconds. */
140
+ retryAfterMs;
141
+ constructor(message, opts) {
142
+ super(message, opts);
143
+ this.name = "RateLimitedError";
144
+ this.retryAfterMs = opts?.retryAfterMs ?? null;
145
+ }
81
146
  }
82
147
  /**
83
148
  * TokenLimitExceededError signals that the caller is at a hard token budget:
@@ -88,20 +153,18 @@ export class BackpressureError extends LoomcycleError {
88
153
  * month's tokens for an operator, tenant or user; the same call is refused
89
154
  * until an operator raises the budget or the window rolls over.
90
155
  *
91
- * It extends BackpressureError only so that code written before this class
92
- * existed, which caught this refusal with `instanceof BackpressureError`,
93
- * keeps catching it. Test for this class BEFORE BackpressureError:
94
- *
95
- * if (e instanceof TokenLimitExceededError) {
96
- * // not retryable now: report e.scope / e.used / e.limit
97
- * } else if (e instanceof BackpressureError) {
98
- * // transient: back off and retry
99
- * }
156
+ * It is not a BackpressureError, and `retryable` is false. It used to
157
+ * extend BackpressureError so that an older `instanceof BackpressureError`
158
+ * check kept catching it, but such a check is almost always a retry loop, and
159
+ * that loop then retried a refusal that cannot clear for the rest of the
160
+ * month. The relation was dropped on purpose: a retry loop keyed on
161
+ * BackpressureError or on `retryable` now stops here, and code that wants to
162
+ * report the budget tests for this class.
100
163
  *
101
164
  * The fields come from the response body and are null when the server did
102
165
  * not send them.
103
166
  */
104
- export class TokenLimitExceededError extends BackpressureError {
167
+ export class TokenLimitExceededError extends LoomcycleError {
105
168
  /** Whose budget was hit: "operator", "tenant" or "user". */
106
169
  scope;
107
170
  /** The id of that scope: the tenant id or the user subject. Null for the
@@ -172,6 +235,11 @@ export class PerUserQuotaExhaustedError extends LoomcycleError {
172
235
  this.cap = opts?.cap ?? null;
173
236
  this.retryAfterMs = opts?.retryAfterMs ?? null;
174
237
  }
238
+ /** The quota counts the caller's own in-flight runs, so it frees up as
239
+ * they finish. */
240
+ get retryable() {
241
+ return true;
242
+ }
175
243
  }
176
244
  export class AuthError extends LoomcycleError {
177
245
  constructor(message, opts) {
@@ -179,6 +247,36 @@ export class AuthError extends LoomcycleError {
179
247
  this.name = "AuthError";
180
248
  }
181
249
  }
250
+ /** An HTTP 403 because the bearer token lacks a scope the call needs: body code
251
+ * `insufficient_scope`. The token is valid; it was minted without that
252
+ * grant. Ask an operator for a token that carries `requiredScope`; sending
253
+ * the same call again never succeeds, so `retryable` is false.
254
+ *
255
+ * Any other 403 (`restricted_token`, `operator_key_restricted`, …) stays a
256
+ * plain LoomcycleError: those refuse the caller for something a new scope
257
+ * does not fix. */
258
+ export class InsufficientScopeError extends LoomcycleError {
259
+ /** The scope the token lacks, e.g. `runs:create` or `substrate:tenant`.
260
+ * Read from the body's `required_scope`, or, from a server that predates
261
+ * that field, from the `WWW-Authenticate: Bearer scope="…"` header. Null
262
+ * when neither names one (a browser does not see that header on a
263
+ * cross-origin response unless the server exposes it). */
264
+ requiredScope;
265
+ constructor(message, opts) {
266
+ super(message, opts);
267
+ this.name = "InsufficientScopeError";
268
+ this.requiredScope = opts?.requiredScope ?? null;
269
+ }
270
+ }
271
+ /** Every HTTP 503. The status is shared between a condition that clears on
272
+ * its own and features this deployment does not have
273
+ * (`decision_not_configured`, `store_unavailable`, `vector_unsupported`, …),
274
+ * which never will, and many 503 bodies carry no code at all. So
275
+ * `retryable` is true only for `runtime_paused` (new runs are refused while
276
+ * the operator has the runtime paused) and false otherwise. A code-less 503
277
+ * from run creation can also be a model tier with no provider available
278
+ * right now; retry that one on your own judgement, with a bound. (The
279
+ * inherited `retryable` reads `runtime_paused` from TRANSIENT_CODES.) */
182
280
  export class UnavailableError extends LoomcycleError {
183
281
  constructor(message, opts) {
184
282
  super(message, opts);
@@ -200,6 +298,10 @@ export class PauseNotConfiguredError extends UnavailableError {
200
298
  super(message, opts);
201
299
  this.name = "PauseNotConfiguredError";
202
300
  }
301
+ /** The server has no pause manager; asking again does not give it one. */
302
+ get retryable() {
303
+ return false;
304
+ }
203
305
  }
204
306
  export class AlreadyPausingError extends LoomcycleError {
205
307
  constructor(message, opts) {
@@ -77,6 +77,9 @@ export declare function deleteJSON<T>(ctx: _FetchContext, path: string, opts?: {
77
77
  *
78
78
  * 400 → InvalidArgumentError
79
79
  * 401 → AuthError
80
+ * 403 + code "insufficient_scope" (or an older server's
81
+ * WWW-Authenticate scope hint) → InsufficientScopeError
82
+ * 403 (other) → LoomcycleError (base)
80
83
  * 404 + "snapshot" → SnapshotNotFoundError ────────┐
81
84
  * 404 + "session" → SessionNotFoundError │ All extend
82
85
  * 404 + "agent" → AgentNotFoundError │ callers can
@@ -9,7 +9,7 @@
9
9
  * Method-level code in client.ts stays focused on URL + body shape;
10
10
  * the boring fetch + error-translation machinery lives here.
11
11
  */
12
- import { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, ChannelCursorRegressionError, InvalidArgumentError, LoomcycleError, NotFoundError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
12
+ import { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, ChannelCursorRegressionError, InsufficientScopeError, InvalidArgumentError, LoomcycleError, NotFoundError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RateLimitedError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
13
13
  /** authHeaders builds the standard request header set: JSON Accept
14
14
  * + Bearer token when the client was constructed with one. The
15
15
  * caller adds Content-Type when posting a body. */
@@ -157,6 +157,9 @@ export async function deleteJSON(ctx, path, opts) {
157
157
  *
158
158
  * 400 → InvalidArgumentError
159
159
  * 401 → AuthError
160
+ * 403 + code "insufficient_scope" (or an older server's
161
+ * WWW-Authenticate scope hint) → InsufficientScopeError
162
+ * 403 (other) → LoomcycleError (base)
160
163
  * 404 + "snapshot" → SnapshotNotFoundError ────────┐
161
164
  * 404 + "session" → SessionNotFoundError │ All extend
162
165
  * 404 + "agent" → AgentNotFoundError │ callers can
@@ -216,6 +219,19 @@ export async function raiseFromResponse(resp) {
216
219
  throw new InvalidArgumentError(msg, opts);
217
220
  case 401:
218
221
  throw new AuthError(msg, opts);
222
+ case 403: {
223
+ // A missing scope says so in its code. A server from before the JSON
224
+ // body sent "insufficient scope" as plain text; the scope hint in
225
+ // WWW-Authenticate, which no other 403 carries, still identifies it.
226
+ const hinted = scopeFromWWWAuthenticate(resp);
227
+ if (opts.code === "insufficient_scope" || (opts.code === undefined && hinted !== undefined)) {
228
+ throw new InsufficientScopeError(msg, {
229
+ ...opts,
230
+ requiredScope: stringField(bodyObject(bodyText)?.required_scope) ?? hinted,
231
+ });
232
+ }
233
+ throw new LoomcycleError(msg, opts);
234
+ }
219
235
  case 404:
220
236
  // Priority: most-specific keyword wins.
221
237
  // - "snapshot" → SnapshotNotFoundError
@@ -275,8 +291,8 @@ export async function raiseFromResponse(resp) {
275
291
  }
276
292
  case 429: {
277
293
  // A hard token budget is not transient the way backpressure is, so
278
- // it gets its own class (a BackpressureError subclass, for callers
279
- // that already catch that).
294
+ // it gets its own class, deliberately outside BackpressureError: a
295
+ // retry loop keyed on that class must not spin on it all month.
280
296
  if (opts.code === "token_limit_exceeded") {
281
297
  const body = bodyObject(bodyText) ?? {};
282
298
  throw new TokenLimitExceededError(msg, {
@@ -288,6 +304,9 @@ export async function raiseFromResponse(resp) {
288
304
  window: stringField(body.window),
289
305
  });
290
306
  }
307
+ if (opts.code === "rate_limited") {
308
+ throw new RateLimitedError(msg, { ...opts, retryAfterMs: retryAfterMs(resp) });
309
+ }
291
310
  // v0.10.1: distinguish per-user quota exhaustion from
292
311
  // operator-wide backpressure. The shapes share the 429 status
293
312
  // but the JSON body's `code` field discriminates. Consumers
@@ -295,18 +314,13 @@ export async function raiseFromResponse(resp) {
295
314
  try {
296
315
  const parsed = JSON.parse(bodyText);
297
316
  if (parsed.code === "per_user_quota_exhausted") {
298
- // Retry-After is `<seconds>` per RFC; convert to ms.
299
- const retryAfterRaw = resp.headers.get("retry-after");
300
- const retryAfterMs = retryAfterRaw
301
- ? Number.parseInt(retryAfterRaw, 10) * 1000
302
- : undefined;
303
317
  throw new PerUserQuotaExhaustedError(parsed.error ?? msg, {
304
318
  status,
305
319
  bodyText,
306
320
  code: parsed.code,
307
321
  userId: parsed.user_id,
308
322
  cap: parsed.cap,
309
- retryAfterMs: Number.isFinite(retryAfterMs) ? retryAfterMs : undefined,
323
+ retryAfterMs: retryAfterMs(resp),
310
324
  });
311
325
  }
312
326
  }
@@ -325,6 +339,23 @@ export async function raiseFromResponse(resp) {
325
339
  throw new LoomcycleError(msg, opts);
326
340
  }
327
341
  }
342
+ /** retryAfterMs reads a `Retry-After` header given in seconds, as the server
343
+ * always sends it, and returns milliseconds; undefined when the header is
344
+ * absent or not a number (an HTTP-date form is not parsed). */
345
+ function retryAfterMs(resp) {
346
+ const raw = resp.headers.get("retry-after");
347
+ if (!raw)
348
+ return undefined;
349
+ const ms = Number.parseInt(raw, 10) * 1000;
350
+ return Number.isFinite(ms) ? ms : undefined;
351
+ }
352
+ /** scopeFromWWWAuthenticate reads the scope from the RFC 6750 hint the server
353
+ * sends with a scope refusal (`Bearer scope="runs:create"`); undefined when
354
+ * the header is absent or names no scope. */
355
+ function scopeFromWWWAuthenticate(resp) {
356
+ const m = /\bscope="([^"]*)"/.exec(resp.headers.get("www-authenticate") ?? "");
357
+ return stringField(m?.[1]);
358
+ }
328
359
  /** bodyCode returns the string `code` of a JSON error body, or undefined when
329
360
  * the body is not a JSON object or has none. Statuses are shared between
330
361
  * unrelated conditions (a 400 is any bad request; a 429 is backpressure, a
package/dist/index.d.ts CHANGED
@@ -14,8 +14,10 @@
14
14
  * getAgent(agentId): Promise<Agent>
15
15
  * getRun(runId): Promise<Agent>
16
16
  * cancelAgent(agentId, opts?): Promise<CancelAgentResult>
17
- * listUserAgents(userId, opts?): Promise<Agent[]>
17
+ * listUserAgents(userId, opts?): Promise<AgentList>
18
18
  * listWalkRuns(walkId, opts?): Promise<WalkRunsPage>
19
+ * deleteRunTree(runId, opts?): Promise<RunTreeDeletion> // needs runs:delete
20
+ * deleteSession(sessionId, {cascade: "children"}): Promise<RunTreeDeletion>
19
21
  * getTranscript(sessionId): Promise<TranscriptResponse>
20
22
  * health(): Promise<HealthResponse>
21
23
  * listUsers(opts?): Promise<ListUsersResponse> // tenant-scoped (RFC L)
@@ -33,6 +35,9 @@
33
35
  * resumeRuntime(): Promise<ResumeResult>
34
36
  * getRuntimeState(): Promise<RuntimeStateResponse>
35
37
  * resolveProbe(opts?): Promise<ResolverMatrix>
38
+ * listModels(): Promise<ModelAliasesResponse> // configured model aliases
39
+ * getRouting(): Promise<RoutingResponse> // per user_tier × tier cascade
40
+ * listProviderModels(providerId): Promise<ProviderModelsResponse> // admin token only
36
41
  *
37
42
  * // Snapshot lifecycle (v0.8.17/8.18)
38
43
  * createSnapshot(opts?): Promise<SnapshotCreateResponse>
@@ -55,6 +60,10 @@
55
60
  * backfillEmbeddings(scope, scopeId, opts?): Promise<MemoryBackfillResponse> // embeds rows that have none
56
61
  * purgeStaleEmbeddings(scope, scopeId, opts?): Promise<MemoryPurgeResponse> // DELETES; dry_run defaults true
57
62
  *
63
+ * // Memory / document change feeds (RFC CD Part C; SSE; substrate:tenant)
64
+ * streamMemoryChanges(opts?): AsyncIterable<ChangeFeedFrame> // feed | change | error (non-fatal); resume with opts.since = last seq
65
+ * streamDocumentChanges(opts?): AsyncIterable<ChangeFeedFrame>
66
+ *
58
67
  * // Interruption (v0.8.16; decline RFC BH)
59
68
  * listUserInterrupts(userId, opts?): Promise<InterruptListResponse>
60
69
  * listRunInterrupts(runId, opts?): Promise<InterruptListResponse>
@@ -70,7 +79,27 @@
70
79
  * mcpServerDef(input): Promise<SubstrateToolResponse>
71
80
  * mcpServerDefVerify(name, sha): Promise<MCPServerDefVerifyResult> // v0.18.0
72
81
  * ensureMcpServer(opts): Promise<EnsureMcpServerResult> // v0.18.0 — idempotent register-if-changed
73
- * scheduleDef(input): Promise<SubstrateToolResponse>
82
+ * scheduleDef(input): Promise<SubstrateToolResponse> // input: ScheduleDefInput | SubstrateToolInput
83
+ * webhookDef(input): Promise<SubstrateToolResponse> // input: WebhookDefInput | SubstrateToolInput
84
+ * hookDef(input): Promise<SubstrateToolResponse> // input: HookDefInput | SubstrateToolInput
85
+ * ensureHookDef(name, overlay, opts?): Promise<EnsureHookDefResult> // idempotent register-if-changed
86
+ * createHookDef / forkHookDef(name, overlay, opts?) // overlay strictly typed, no loose fallback
87
+ * createScheduleDef / forkScheduleDef(name, overlay, opts?) // ditto (overlay open: types of known keys checked)
88
+ * createWebhookDef / forkWebhookDef(name, overlay, opts?) // ditto
89
+ *
90
+ * // Def name enumeration (tenant-scoped; opts.tenant = admin focus)
91
+ * listAgentDefNames / listSkillDefNames / listHookDefNames / listMcpServerDefNames /
92
+ * listScheduleDefNames / listA2AServerCardDefNames / listA2AAgentDefNames /
93
+ * listWebhookDefNames / listMemoryBackendDefNames / listDocumentSourceDefNames
94
+ * (opts?): Promise<DefNamesResponse>
95
+ * listOperatorTokenDefNames(opts?): Promise<OperatorTokenDefNamesResponse> // admin token only
96
+ *
97
+ * // Schedules admin
98
+ * listAllSchedules(opts?): Promise<ScheduleListResponse> // static yaml + ScheduleDefs, merged
99
+ * getScheduleState(defId): Promise<ScheduleStateView>
100
+ * runScheduleNow(defId): Promise<ScheduleRunNowResult> // fires on the next tick
101
+ * pauseSchedule(defId): Promise<SchedulePauseResult> // indefinite
102
+ * resumeSchedule(defId): Promise<SchedulePauseResult>
74
103
  *
75
104
  * // Dynamic filesystem volumes (v0.35.0 — RFC AH; tenant-confined)
76
105
  * volumeDef(input): Promise<SubstrateToolResponse> // create/get/list/delete/purge
@@ -81,8 +110,8 @@
81
110
  * listTeams(): Promise<ListTeamsResponse>
82
111
  * renderTeamDiagram(name, opts?): Promise<TeamDiagram>
83
112
  * getTeamDef(defId): Promise<TeamDefDetail>
84
- * createTeam(name, overlay): Promise<CreatedTeam>
85
- * forkTeam(name, overlay): Promise<CreatedTeam>
113
+ * createTeam(name, overlay, opts?): Promise<CreatedTeam> // opts: promote (default true) / description
114
+ * forkTeam(name, overlay, opts?): Promise<CreatedTeam> // opts: promote / parentDefId / description
86
115
  * deleteTeam(name): Promise<{name, deleted}>
87
116
  * runTeam({name|defId, input}): Promise<TeamRunResult>
88
117
  * runTeam({..., mode:"detach"}): Promise<TeamRunDetached> // the handle, now — the walk runs on
@@ -96,6 +125,14 @@
96
125
  * // History — browse/search/annotate past chats (RFC BE; tenant-confined)
97
126
  * history(input): Promise<HistoryToolResponse> // list/get/search/rename/annotate/pin/archive/recap/resume
98
127
  *
128
+ * // Evaluation — score runs and read the scores back, outside a run
129
+ * evaluation(input): Promise<…> // submit/get/list_for_run/list_for_def/aggregate
130
+ * submitEvaluation(runId, score, opts?): Promise<EvaluationSubmitResult>
131
+ * getEvaluation(evalId): Promise<EvaluationRecord>
132
+ * listEvaluationsForRun(runId, opts?): Promise<EvaluationListForRunResult>
133
+ * listEvaluationsForDef(defId, opts?): Promise<EvaluationListForDefResult>
134
+ * aggregateEvaluations(defId, opts?): Promise<EvaluationAggregate>
135
+ *
99
136
  * // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
100
137
  * listLibraryAgents(): Promise<LibraryListResponse<LibraryAgentDefinition>>
101
138
  * listLibrarySkills(): Promise<LibraryListResponse<LibrarySkillDefinition>>
@@ -112,13 +149,18 @@
112
149
  * full HTTP-status → typed-error mapping table):
113
150
  * LoomcycleError, AgentNotFoundError, SessionNotFoundError,
114
151
  * SessionBusyError, AgentIDInUseError, BackpressureError,
115
- * AuthError, UnavailableError, InvalidArgumentError,
152
+ * RateLimitedError (subclass of BackpressureError),
153
+ * PerUserQuotaExhaustedError, AuthError, InsufficientScopeError (a 403
154
+ * naming the scope the token lacks), UnavailableError,
155
+ * InvalidArgumentError,
116
156
  * PauseNotConfiguredError (subclass of UnavailableError),
117
157
  * AlreadyPausingError, NotPausedError, SnapshotNotFoundError,
118
158
  * SnapshotTooLargeError, RequestTooLargeError + PromptTooLargeError
119
159
  * (both subclasses of SnapshotTooLargeError), TokenLimitExceededError
120
- * (subclass of BackpressureError), SnapshotVersionError,
121
- * SubstrateToolRefusedError (v0.8.22)
160
+ * (NOT a BackpressureError: a hard budget, not retryable),
161
+ * SnapshotVersionError, SubstrateToolRefusedError (v0.8.22).
162
+ * Every one carries `retryable` (true only for a refusal that clears
163
+ * on its own).
122
164
  *
123
165
  * Transport: HTTP+SSE. Auth: Bearer token via the Authorization
124
166
  * header. Designed for Node ≥18 (engines pinned); Bun/Deno likely
@@ -130,7 +172,9 @@
130
172
  export { LoomcycleClient } from "./client.js";
131
173
  export { InteractiveSession } from "./interactive.js";
132
174
  export type { InteractiveSessionOps } from "./interactive.js";
175
+ export { verifyLoomcycleSignature, verifyLoomcycleDelivery } from "./signature.js";
176
+ export type { VerifySignatureOptions, VerifiedDelivery } from "./signature.js";
133
177
  export { ClientToolHost, clientToolsURL, CLIENT_TOOL_SUBPROTOCOL } from "./client-tools.js";
134
178
  export type { ClientToolSchema, ClientToolInvocation, ConnectClientToolsOptions, WebSocketLike, WebSocketCtor, } from "./client-tools.js";
135
- export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, ImageMediaType, ParentContext, PromptContent, PromptSegment, RetryInfo, RunOptions, SamplingOptions, CompactionOptions, ContextOptions, ToolUse, Usage, CallTiming, Agent, AgentStatus, AwaitedState, AgentUsage, RunResult, RunSpec, RunSpecTeam, ConfiguredRun, ConfiguredRunPatch, ToolChoiceOptions, OutputFormatOptions, CancelAgentResult, ListAgentsResponse, WalkRunsPage, RunBatchOptions, RunBatchResult, SpawnRunResult, CompactRunResult, DirectoryBudget, DirectoryInspection, DirectoryTenant, DirectoryUser, ErasureReport, ErasureResidue, ErasureResult, ErasureTier, CancelTurnResult, ReviewRunResult, TranscriptEvent, TranscriptResponse, HealthResponse, ListUsersResponse, UserSummary, UserRecord, CreateUserBody, UpdateUserBody, MintedUserToken, UserTokenMeta, ListUserTokensResponse, RunnableAgent, RunnableAgentsResponse, WhoamiResponse, PauseResult, ResumeResult, RuntimeStateResponse, RuntimeStateStatus, ResolverMatrix, ResolverModelStatus, ResolverProviderAvailability, CreateSnapshotOptions, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotListResponse, SnapshotRestoreResponse, MemoryEntriesResponse, MemoryEntry, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopeIDSummary, MemoryScopeKind, MemoryScopesResponse, MemorySearchInput, MemorySource, MemoryWhen, MemoryTimeFilter, MemorySearchEntry, MemorySearchResponse, MemoryEmbedModelStats, MemoryEmbedStatsResponse, MemoryReembedConfigured, MemoryReembedResponse, MemoryBackfillResponse, MemoryPurgeResponse, InterruptListResponse, InterruptRow, InterruptStatus, ResolveInterruptOptions, ChannelHookCall, ChannelHookResult, HookFailMode, HookPhase, HookToolCall, HookToolResult, PostHookCall, PostHookResult, PreHookCall, PreHookResult, SubstrateToolInput, SubstrateToolResponse, TeamNameSummary, ListTeamsResponse, TeamDiagram, CreatedTeam, PromotedTeam, RetiredTeam, TeamDefDetail, TeamVerification, TeamDraft, TeamDraftVerification, TeamIssue, TeamIssueKind, TeamVersion, TeamVersionList, TeamBreakpoints, TeamRunDetached, TeamRunResult, TeamRunTarget, PathToolInput, PathToolResponse, DocumentToolInput, DocumentToolResponse, HistoryToolInput, HistoryToolResponse, VolumeMode, PersistentVolumeEntry, PersistentVolumesResponse, EphemeralVolumeEntry, EphemeralVolumesResponse, SystemPromptPayload, UserInputPayload, ChannelDescriptor, ListChannelsResponse, RunStateEvent, RunStateStreamClose, RunStateStreamItem, RunStateStreamOpen, StreamUserRunStatesOptions, AckChannelOptions, ChannelAckResult, ChannelMessageItem, ChannelPeekResult, ListTeamChannelsOptions, PeekTeamChannelOptions, ReleaseTeamChannelOptions, TeamChannelReleaseResult, TeamChannelDeclaredIn, TeamChannelDescriptor, TeamChannelPeekResult, TeamChannelsResult, ChannelPublishResult, ChannelPurgeResult, ChannelReleaseResult, ChannelScope, ChannelSubscribeResult, PeekChannelOptions, PublishChannelOptions, SubscribeChannelOptions, AwaitChannelsOptions, BroadcastChannelsOptions, ChannelAwaitEntry, ChannelAwaitMode, ChannelAwaitResult, ChannelBroadcastEntry, ChannelBroadcastResult, CreateChannelOptions, ReleaseChannelOptions, UpdateChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, EnsureMcpServerOptions, EnsureMcpServerResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, AgentDefOverlay, HookEvent, InlineWebhook, HookEntry, EventHooks, ToolEntry, ToolHooksByTool, EnsureCodeAgentOptions, EnsureCodeAgentResult, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, UsageDimension, UsageAggregate, UsageReportResponse, CapabilityInertInfo, LimitInfo, ErrorInfo, CallFormat, CallRef, HookDecisionInfo, TeamDecisionInfo, EffectiveConfigResponse, EffectiveConfigSource, EffectiveValue, RetuneRunResponse, RunConfigRecord, SubagentHoldInfo, RunConfigResponse, RunPromptResponse, RunPromptSnapshot, PromptBlock, TokenLimit, TokenLimitsResponse, ConfigResponse, ConfigProvider, ConfigModel, ConfigSearch, ConfigInstance, SetTokenLimitRequest, CredentialScope, CredentialMeta, CredentialListResponse, DecideRequest, DecideResponse, DecisionQuestion, DecisionChoiceQuestion, DecisionNoulQuestion, DecisionScoreQuestion, DecisionAnswer, DecisionChoiceAnswer, DecisionNoulAnswer, DecisionScoreAnswer, DecisionModel, DecisionModelsResponse, } from "./types.js";
136
- export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";
179
+ export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, ImageMediaType, ParentContext, PromptContent, PromptSegment, RetryInfo, RunOptions, RunOverrideOptions, SamplingOptions, CompactionOptions, ContextOptions, ToolUse, Usage, CallTiming, Agent, AgentStatus, AwaitedState, AgentUsage, RunResult, RunSpec, RunSpecTeam, ConfiguredRun, ConfiguredRunPatch, ToolChoiceOptions, OutputFormatOptions, CancelAgentResult, ListAgentsResponse, ListUserAgentsOptions, AgentList, WalkRunsPage, RunBatchOptions, RunBatchResult, SpawnRunResult, CompactRunResult, RunTreeDeletion, RunTreeNotReached, DirectoryBudget, DirectoryInspection, DirectoryTenant, DirectoryUser, ErasureReport, ErasureResidue, ErasureResult, ErasureTier, CancelTurnResult, ReviewRunResult, ReplaySessionResult, TranscriptEvent, TranscriptResponse, HealthResponse, ListUsersResponse, UserSummary, UserRecord, CreateUserBody, UpdateUserBody, MintedUserToken, TokenRestrictions, UserTokenMeta, ListUserTokensResponse, RunnableAgent, RunnableAgentsResponse, WhoamiResponse, PauseResult, RetentionOverride, ResumeResult, RuntimeStateResponse, RuntimeStateStatus, ResolverMatrix, ResolverModelStatus, ResolverProviderAvailability, CreateSnapshotOptions, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotListResponse, SnapshotRestoreResponse, MemoryEntriesResponse, MemoryEntry, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopeIDSummary, MemoryScopeKind, MemoryScopesResponse, MemorySearchInput, MemorySource, MemoryWhen, MemoryTimeFilter, MemorySearchEntry, MemorySearchResponse, MemoryEmbedModelStats, MemoryEmbedStatsResponse, MemoryReembedConfigured, MemoryReembedResponse, MemoryBackfillResponse, MemoryPurgeResponse, InterruptListResponse, InterruptRow, InterruptStatus, ResolveInterruptOptions, ChannelHookCall, ChannelHookResult, HookFailMode, HookPhase, HookToolCall, HookToolResult, PostHookCall, PostHookResult, PreHookCall, PreHookResult, SubstrateToolInput, SubstrateToolResponse, TeamNameSummary, ListTeamsResponse, TeamDiagram, CreatedTeam, PromotedTeam, RetiredTeam, TeamDefDetail, TeamVerification, TeamDraft, TeamDraftVerification, TeamIssue, TeamIssueKind, TeamVersion, TeamVersionList, TeamBreakpoints, TeamRunDetached, TeamRunResult, TeamRunTarget, CreateTeamOptions, ForkTeamOptions, DefNameSummary, DefNamesResponse, OperatorTokenDefNameSummary, OperatorTokenDefNamesResponse, ScheduleListEntry, ScheduleListResponse, ScheduleActiveRun, ScheduleStateView, ScheduleRunNowResult, SchedulePauseResult, ModelAlias, ModelAliasesResponse, RoutingResponse, RoutingUserTier, RoutingTier, RoutingCandidate, RoutingThroughput, RoutingProvider, SearchRoutingProvider, ProviderModelsResponse, TeamRunStep, TeamDecisionHandler, TeamDecisionQuestion, TeamDecisionAnswer, PathToolInput, PathToolResponse, DocumentToolInput, DocumentToolResponse, HistoryToolInput, HistoryToolResponse, EvaluationEmitterRole, EvaluationSubmitInput, EvaluationGetInput, EvaluationListForRunInput, EvaluationListForDefInput, EvaluationAggregateInput, EvaluationInput, EvaluationSubmitResult, EvaluationRecord, EvaluationListForRunResult, EvaluationListForDefResult, EvaluationScoreStats, EvaluationAggregate, VolumeMode, PersistentVolumeEntry, PersistentVolumesResponse, EphemeralVolumeEntry, EphemeralVolumesResponse, SystemPromptPayload, UserInputPayload, ChannelDescriptor, ListChannelsResponse, RunStateEvent, RunStateStreamClose, RunStateStreamItem, RunStateStreamOpen, StreamUserRunStatesOptions, ChangeFeedError, ChangeFeedFrame, ChangeFeedStatus, EmbedderHealth, MemoryChange, MemoryChangeScope, MemoryChangeType, StreamChangesOptions, AckChannelOptions, ChannelAckResult, ChannelMessageItem, ChannelPeekResult, ListTeamChannelsOptions, PeekTeamChannelOptions, ReleaseTeamChannelOptions, TeamChannelReleaseResult, TeamChannelDeclaredIn, TeamChannelDescriptor, TeamChannelPeekResult, TeamChannelsResult, ChannelPublishResult, ChannelPurgeResult, ChannelReleaseResult, ChannelScope, ChannelSubscribeResult, PeekChannelOptions, PublishChannelOptions, SubscribeChannelOptions, AwaitChannelsOptions, BroadcastChannelsOptions, ChannelAwaitEntry, ChannelAwaitMode, ChannelAwaitResult, ChannelBroadcastEntry, ChannelBroadcastResult, CreateChannelOptions, ReleaseChannelOptions, UpdateChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, EnsureMcpServerOptions, EnsureMcpServerResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, AgentDefOverlay, AgentChannelACL, AgentInterruptionACL, AgentDecision, MemoryRerank, AgentSampling, AgentCompaction, AgentContext, TierCandidate, CoreBlock, HookEvent, InlineWebhook, HookEntry, EventHooks, ToolEntry, ToolHooksByTool, EnsureCodeAgentOptions, EnsureCodeAgentResult, CreateDefOptions, ForkDefOptions, EnsureHookDefOptions, EnsureHookDefResult, HookDefBody, HookDefForkOverlay, HookDefInput, HookDefMatch, HookDefOverlay, HookDefRowResponse, HookDefVerifyResult, ScheduleDefInput, ScheduleDefOverlay, ScheduleDefRowResponse, ScheduledRunHook, ScheduledRunPromptContent, ScheduledRunPromptSegment, WebhookDefAuth, WebhookDefInput, WebhookDefOverlay, WebhookDefRateLimit, WebhookDefRowResponse, WebhookDefSyncResponse, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, UsageDimension, UsageAggregate, UsageReportResponse, CapabilityInertInfo, LimitInfo, AdmissionInfo, ErrorInfo, CallFormat, CallRef, HookDecisionInfo, TeamDecisionInfo, OverrideInfo, FallbackInfo, InterruptionEventInfo, SpawnChildInfo, TurnCancelledInfo, ChannelEventInfo, ContextCompactionInfo, ContextRecapInfo, ContextStateInfo, ContextExhaustedInfo, ContextTierVerdict, ContextDistillDeclinedInfo, EffectiveConfigResponse, EffectiveConfigSource, EffectiveValue, InertContextSetting, AgentOverridableResponse, OverridableField, OverrideLockReason, RetuneRunResponse, RunConfigRecord, SubagentHoldInfo, RunConfigResponse, RunPromptResponse, RunPromptSnapshot, PromptBlock, TokenLimit, TokenLimitsResponse, ConfigResponse, ConfigProvider, ConfigModel, ConfigSearch, ConfigInstance, SetTokenLimitRequest, CredentialScope, CredentialMeta, CredentialListResponse, DecideRequest, DecideResponse, DecisionQuestion, DecisionChoiceQuestion, DecisionNoulQuestion, DecisionScoreQuestion, DecisionAnswer, DecisionChoiceAnswer, DecisionNoulAnswer, DecisionScoreAnswer, DecisionModel, DecisionModelsResponse, } from "./types.js";
180
+ export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, NotFoundError, InsufficientScopeError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, PromptTooLargeError, RateLimitedError, RequestTooLargeError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, TokenLimitExceededError, UnavailableError, } from "./errors.js";