@loomcycle/client 1.105.0 → 1.107.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/README.md +104 -2
- package/dist/cjs/client.js +34 -0
- package/dist/cjs/errors.js +91 -1
- package/dist/cjs/fetch-helpers.js +65 -5
- package/dist/cjs/index.js +7 -2
- package/dist/client.d.ts +25 -1
- package/dist/client.js +34 -0
- package/dist/errors.d.ts +108 -0
- package/dist/errors.js +87 -0
- package/dist/fetch-helpers.d.ts +10 -2
- package/dist/fetch-helpers.js +66 -6
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -2
- package/dist/types.d.ts +157 -0
- package/package.json +1 -1
package/dist/errors.d.ts
CHANGED
|
@@ -20,9 +20,16 @@
|
|
|
20
20
|
export declare class LoomcycleError extends Error {
|
|
21
21
|
readonly status?: number;
|
|
22
22
|
readonly bodyText?: string;
|
|
23
|
+
/** The machine-readable `code` of a JSON error body (`model_not_allowed`,
|
|
24
|
+
* `token_limit_exceeded`, `per_user_quota_exhausted`, …), on whichever
|
|
25
|
+
* class the status maps to. Undefined when the body is not JSON or carries
|
|
26
|
+
* no string `code`. Read from the whole body, so it survives where
|
|
27
|
+
* `bodyText` is cut at 1 KiB. Branch on this, not on the message. */
|
|
28
|
+
readonly code?: string;
|
|
23
29
|
constructor(message: string, opts?: {
|
|
24
30
|
status?: number;
|
|
25
31
|
bodyText?: string;
|
|
32
|
+
code?: string;
|
|
26
33
|
});
|
|
27
34
|
}
|
|
28
35
|
/** Base class for every HTTP 404 the client surfaces. Lets callers
|
|
@@ -34,36 +41,91 @@ export declare class NotFoundError extends LoomcycleError {
|
|
|
34
41
|
constructor(message: string, opts?: {
|
|
35
42
|
status?: number;
|
|
36
43
|
bodyText?: string;
|
|
44
|
+
code?: string;
|
|
37
45
|
});
|
|
38
46
|
}
|
|
39
47
|
export declare class AgentNotFoundError extends NotFoundError {
|
|
40
48
|
constructor(message: string, opts?: {
|
|
41
49
|
status?: number;
|
|
42
50
|
bodyText?: string;
|
|
51
|
+
code?: string;
|
|
43
52
|
});
|
|
44
53
|
}
|
|
45
54
|
export declare class SessionNotFoundError extends NotFoundError {
|
|
46
55
|
constructor(message: string, opts?: {
|
|
47
56
|
status?: number;
|
|
48
57
|
bodyText?: string;
|
|
58
|
+
code?: string;
|
|
49
59
|
});
|
|
50
60
|
}
|
|
51
61
|
export declare class SessionBusyError extends LoomcycleError {
|
|
52
62
|
constructor(message: string, opts?: {
|
|
53
63
|
status?: number;
|
|
54
64
|
bodyText?: string;
|
|
65
|
+
code?: string;
|
|
55
66
|
});
|
|
56
67
|
}
|
|
57
68
|
export declare class AgentIDInUseError extends LoomcycleError {
|
|
58
69
|
constructor(message: string, opts?: {
|
|
59
70
|
status?: number;
|
|
60
71
|
bodyText?: string;
|
|
72
|
+
code?: string;
|
|
61
73
|
});
|
|
62
74
|
}
|
|
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. */
|
|
63
79
|
export declare class BackpressureError extends LoomcycleError {
|
|
64
80
|
constructor(message: string, opts?: {
|
|
65
81
|
status?: number;
|
|
66
82
|
bodyText?: string;
|
|
83
|
+
code?: string;
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* TokenLimitExceededError signals that the caller is at a hard token budget:
|
|
88
|
+
* HTTP 429 with body code `token_limit_exceeded`, from run creation and from
|
|
89
|
+
* `decide()`.
|
|
90
|
+
*
|
|
91
|
+
* Do not retry it the way you retry backpressure. The budget is a calendar
|
|
92
|
+
* month's tokens for an operator, tenant or user; the same call is refused
|
|
93
|
+
* until an operator raises the budget or the window rolls over.
|
|
94
|
+
*
|
|
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
|
+
* }
|
|
104
|
+
*
|
|
105
|
+
* The fields come from the response body and are null when the server did
|
|
106
|
+
* not send them.
|
|
107
|
+
*/
|
|
108
|
+
export declare class TokenLimitExceededError extends BackpressureError {
|
|
109
|
+
/** Whose budget was hit: "operator", "tenant" or "user". */
|
|
110
|
+
readonly scope: string | null;
|
|
111
|
+
/** The id of that scope: the tenant id or the user subject. Null for the
|
|
112
|
+
* operator-wide budget, and where the server withholds it. */
|
|
113
|
+
readonly scopeId: string | null;
|
|
114
|
+
/** Tokens the scope has used in the current window. */
|
|
115
|
+
readonly used: number | null;
|
|
116
|
+
/** The hard ceiling that was reached, in tokens. */
|
|
117
|
+
readonly limit: number | null;
|
|
118
|
+
/** The budget window, e.g. "month" (a calendar month, UTC). */
|
|
119
|
+
readonly window: string | null;
|
|
120
|
+
constructor(message: string, opts?: {
|
|
121
|
+
status?: number;
|
|
122
|
+
bodyText?: string;
|
|
123
|
+
code?: string;
|
|
124
|
+
scope?: string;
|
|
125
|
+
scopeId?: string;
|
|
126
|
+
used?: number;
|
|
127
|
+
limit?: number;
|
|
128
|
+
window?: string;
|
|
67
129
|
});
|
|
68
130
|
}
|
|
69
131
|
/**
|
|
@@ -111,6 +173,7 @@ export declare class PerUserQuotaExhaustedError extends LoomcycleError {
|
|
|
111
173
|
constructor(message: string, opts?: {
|
|
112
174
|
status?: number;
|
|
113
175
|
bodyText?: string;
|
|
176
|
+
code?: string;
|
|
114
177
|
userId?: string;
|
|
115
178
|
cap?: number;
|
|
116
179
|
retryAfterMs?: number;
|
|
@@ -120,18 +183,21 @@ export declare class AuthError extends LoomcycleError {
|
|
|
120
183
|
constructor(message: string, opts?: {
|
|
121
184
|
status?: number;
|
|
122
185
|
bodyText?: string;
|
|
186
|
+
code?: string;
|
|
123
187
|
});
|
|
124
188
|
}
|
|
125
189
|
export declare class UnavailableError extends LoomcycleError {
|
|
126
190
|
constructor(message: string, opts?: {
|
|
127
191
|
status?: number;
|
|
128
192
|
bodyText?: string;
|
|
193
|
+
code?: string;
|
|
129
194
|
});
|
|
130
195
|
}
|
|
131
196
|
export declare class InvalidArgumentError extends LoomcycleError {
|
|
132
197
|
constructor(message: string, opts?: {
|
|
133
198
|
status?: number;
|
|
134
199
|
bodyText?: string;
|
|
200
|
+
code?: string;
|
|
135
201
|
});
|
|
136
202
|
}
|
|
137
203
|
/** Subclasses UnavailableError for back-compat: code that broadly
|
|
@@ -141,36 +207,76 @@ export declare class PauseNotConfiguredError extends UnavailableError {
|
|
|
141
207
|
constructor(message: string, opts?: {
|
|
142
208
|
status?: number;
|
|
143
209
|
bodyText?: string;
|
|
210
|
+
code?: string;
|
|
144
211
|
});
|
|
145
212
|
}
|
|
146
213
|
export declare class AlreadyPausingError extends LoomcycleError {
|
|
147
214
|
constructor(message: string, opts?: {
|
|
148
215
|
status?: number;
|
|
149
216
|
bodyText?: string;
|
|
217
|
+
code?: string;
|
|
150
218
|
});
|
|
151
219
|
}
|
|
152
220
|
export declare class NotPausedError extends LoomcycleError {
|
|
153
221
|
constructor(message: string, opts?: {
|
|
154
222
|
status?: number;
|
|
155
223
|
bodyText?: string;
|
|
224
|
+
code?: string;
|
|
156
225
|
});
|
|
157
226
|
}
|
|
158
227
|
export declare class SnapshotNotFoundError extends NotFoundError {
|
|
159
228
|
constructor(message: string, opts?: {
|
|
160
229
|
status?: number;
|
|
161
230
|
bodyText?: string;
|
|
231
|
+
code?: string;
|
|
162
232
|
});
|
|
163
233
|
}
|
|
234
|
+
/** A snapshot envelope over the size cap (HTTP 413, body code
|
|
235
|
+
* `snapshot_too_large`).
|
|
236
|
+
*
|
|
237
|
+
* For compatibility it is ALSO the base class of every other 413: until
|
|
238
|
+
* RequestTooLargeError and PromptTooLargeError existed, the client raised
|
|
239
|
+
* this class for any 413, so `instanceof SnapshotTooLargeError` is true for
|
|
240
|
+
* all of them and stays true. To single out a snapshot that is too large,
|
|
241
|
+
* test `e.code === "snapshot_too_large"`. */
|
|
164
242
|
export declare class SnapshotTooLargeError extends LoomcycleError {
|
|
165
243
|
constructor(message: string, opts?: {
|
|
166
244
|
status?: number;
|
|
167
245
|
bodyText?: string;
|
|
246
|
+
code?: string;
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
/** An HTTP 413 that is not about a snapshot: a request body over the server's
|
|
250
|
+
* size limit (`request_too_large`, or a plain-text 413 with no code), a
|
|
251
|
+
* memory value or quota (`memory_value_too_large`, `memory_quota_exceeded`),
|
|
252
|
+
* a channel payload (`payload_too_large`). `e.code` says which.
|
|
253
|
+
*
|
|
254
|
+
* It extends SnapshotTooLargeError only because that is the class these
|
|
255
|
+
* responses were raised as before this one existed; the relation keeps an
|
|
256
|
+
* existing `instanceof SnapshotTooLargeError` matching and says nothing about
|
|
257
|
+
* snapshots. */
|
|
258
|
+
export declare class RequestTooLargeError extends SnapshotTooLargeError {
|
|
259
|
+
constructor(message: string, opts?: {
|
|
260
|
+
status?: number;
|
|
261
|
+
bodyText?: string;
|
|
262
|
+
code?: string;
|
|
263
|
+
});
|
|
264
|
+
}
|
|
265
|
+
/** A `decide()` request that does not fit the decision model's context (HTTP
|
|
266
|
+
* 413, body code `prompt_too_large`). The server never shortens it for you:
|
|
267
|
+
* shorten `state` or ask fewer questions, then send it again. */
|
|
268
|
+
export declare class PromptTooLargeError extends RequestTooLargeError {
|
|
269
|
+
constructor(message: string, opts?: {
|
|
270
|
+
status?: number;
|
|
271
|
+
bodyText?: string;
|
|
272
|
+
code?: string;
|
|
168
273
|
});
|
|
169
274
|
}
|
|
170
275
|
export declare class SnapshotVersionError extends LoomcycleError {
|
|
171
276
|
constructor(message: string, opts?: {
|
|
172
277
|
status?: number;
|
|
173
278
|
bodyText?: string;
|
|
279
|
+
code?: string;
|
|
174
280
|
});
|
|
175
281
|
}
|
|
176
282
|
/** ChannelCursorRegressionError — raised by `client.ackChannel()`
|
|
@@ -187,6 +293,7 @@ export declare class ChannelCursorRegressionError extends LoomcycleError {
|
|
|
187
293
|
constructor(message: string, opts?: {
|
|
188
294
|
status?: number;
|
|
189
295
|
bodyText?: string;
|
|
296
|
+
code?: string;
|
|
190
297
|
});
|
|
191
298
|
}
|
|
192
299
|
/** SubstrateToolRefusedError — raised by `client.agentDef()` /
|
|
@@ -205,6 +312,7 @@ export declare class SubstrateToolRefusedError extends LoomcycleError {
|
|
|
205
312
|
constructor(message: string, opts?: {
|
|
206
313
|
status?: number;
|
|
207
314
|
bodyText?: string;
|
|
315
|
+
code?: string;
|
|
208
316
|
tool?: string;
|
|
209
317
|
});
|
|
210
318
|
}
|
package/dist/errors.js
CHANGED
|
@@ -20,11 +20,18 @@
|
|
|
20
20
|
export class LoomcycleError extends Error {
|
|
21
21
|
status;
|
|
22
22
|
bodyText;
|
|
23
|
+
/** The machine-readable `code` of a JSON error body (`model_not_allowed`,
|
|
24
|
+
* `token_limit_exceeded`, `per_user_quota_exhausted`, …), on whichever
|
|
25
|
+
* class the status maps to. Undefined when the body is not JSON or carries
|
|
26
|
+
* no string `code`. Read from the whole body, so it survives where
|
|
27
|
+
* `bodyText` is cut at 1 KiB. Branch on this, not on the message. */
|
|
28
|
+
code;
|
|
23
29
|
constructor(message, opts) {
|
|
24
30
|
super(message);
|
|
25
31
|
this.name = "LoomcycleError";
|
|
26
32
|
this.status = opts?.status;
|
|
27
33
|
this.bodyText = opts?.bodyText;
|
|
34
|
+
this.code = opts?.code;
|
|
28
35
|
}
|
|
29
36
|
}
|
|
30
37
|
/** Base class for every HTTP 404 the client surfaces. Lets callers
|
|
@@ -62,12 +69,60 @@ export class AgentIDInUseError extends LoomcycleError {
|
|
|
62
69
|
this.name = "AgentIDInUseError";
|
|
63
70
|
}
|
|
64
71
|
}
|
|
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. */
|
|
65
76
|
export class BackpressureError extends LoomcycleError {
|
|
66
77
|
constructor(message, opts) {
|
|
67
78
|
super(message, opts);
|
|
68
79
|
this.name = "BackpressureError";
|
|
69
80
|
}
|
|
70
81
|
}
|
|
82
|
+
/**
|
|
83
|
+
* TokenLimitExceededError signals that the caller is at a hard token budget:
|
|
84
|
+
* HTTP 429 with body code `token_limit_exceeded`, from run creation and from
|
|
85
|
+
* `decide()`.
|
|
86
|
+
*
|
|
87
|
+
* Do not retry it the way you retry backpressure. The budget is a calendar
|
|
88
|
+
* month's tokens for an operator, tenant or user; the same call is refused
|
|
89
|
+
* until an operator raises the budget or the window rolls over.
|
|
90
|
+
*
|
|
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
|
+
* }
|
|
100
|
+
*
|
|
101
|
+
* The fields come from the response body and are null when the server did
|
|
102
|
+
* not send them.
|
|
103
|
+
*/
|
|
104
|
+
export class TokenLimitExceededError extends BackpressureError {
|
|
105
|
+
/** Whose budget was hit: "operator", "tenant" or "user". */
|
|
106
|
+
scope;
|
|
107
|
+
/** The id of that scope: the tenant id or the user subject. Null for the
|
|
108
|
+
* operator-wide budget, and where the server withholds it. */
|
|
109
|
+
scopeId;
|
|
110
|
+
/** Tokens the scope has used in the current window. */
|
|
111
|
+
used;
|
|
112
|
+
/** The hard ceiling that was reached, in tokens. */
|
|
113
|
+
limit;
|
|
114
|
+
/** The budget window, e.g. "month" (a calendar month, UTC). */
|
|
115
|
+
window;
|
|
116
|
+
constructor(message, opts) {
|
|
117
|
+
super(message, opts);
|
|
118
|
+
this.name = "TokenLimitExceededError";
|
|
119
|
+
this.scope = opts?.scope ?? null;
|
|
120
|
+
this.scopeId = opts?.scopeId ?? null;
|
|
121
|
+
this.used = opts?.used ?? null;
|
|
122
|
+
this.limit = opts?.limit ?? null;
|
|
123
|
+
this.window = opts?.window ?? null;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
71
126
|
/**
|
|
72
127
|
* PerUserQuotaExhaustedError signals that the caller has hit their
|
|
73
128
|
* per-user cap on in-flight (active+queued) runs. Distinct from
|
|
@@ -164,12 +219,44 @@ export class SnapshotNotFoundError extends NotFoundError {
|
|
|
164
219
|
this.name = "SnapshotNotFoundError";
|
|
165
220
|
}
|
|
166
221
|
}
|
|
222
|
+
/** A snapshot envelope over the size cap (HTTP 413, body code
|
|
223
|
+
* `snapshot_too_large`).
|
|
224
|
+
*
|
|
225
|
+
* For compatibility it is ALSO the base class of every other 413: until
|
|
226
|
+
* RequestTooLargeError and PromptTooLargeError existed, the client raised
|
|
227
|
+
* this class for any 413, so `instanceof SnapshotTooLargeError` is true for
|
|
228
|
+
* all of them and stays true. To single out a snapshot that is too large,
|
|
229
|
+
* test `e.code === "snapshot_too_large"`. */
|
|
167
230
|
export class SnapshotTooLargeError extends LoomcycleError {
|
|
168
231
|
constructor(message, opts) {
|
|
169
232
|
super(message, opts);
|
|
170
233
|
this.name = "SnapshotTooLargeError";
|
|
171
234
|
}
|
|
172
235
|
}
|
|
236
|
+
/** An HTTP 413 that is not about a snapshot: a request body over the server's
|
|
237
|
+
* size limit (`request_too_large`, or a plain-text 413 with no code), a
|
|
238
|
+
* memory value or quota (`memory_value_too_large`, `memory_quota_exceeded`),
|
|
239
|
+
* a channel payload (`payload_too_large`). `e.code` says which.
|
|
240
|
+
*
|
|
241
|
+
* It extends SnapshotTooLargeError only because that is the class these
|
|
242
|
+
* responses were raised as before this one existed; the relation keeps an
|
|
243
|
+
* existing `instanceof SnapshotTooLargeError` matching and says nothing about
|
|
244
|
+
* snapshots. */
|
|
245
|
+
export class RequestTooLargeError extends SnapshotTooLargeError {
|
|
246
|
+
constructor(message, opts) {
|
|
247
|
+
super(message, opts);
|
|
248
|
+
this.name = "RequestTooLargeError";
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
/** A `decide()` request that does not fit the decision model's context (HTTP
|
|
252
|
+
* 413, body code `prompt_too_large`). The server never shortens it for you:
|
|
253
|
+
* shorten `state` or ask fewer questions, then send it again. */
|
|
254
|
+
export class PromptTooLargeError extends RequestTooLargeError {
|
|
255
|
+
constructor(message, opts) {
|
|
256
|
+
super(message, opts);
|
|
257
|
+
this.name = "PromptTooLargeError";
|
|
258
|
+
}
|
|
259
|
+
}
|
|
173
260
|
export class SnapshotVersionError extends LoomcycleError {
|
|
174
261
|
constructor(message, opts) {
|
|
175
262
|
super(message, opts);
|
package/dist/fetch-helpers.d.ts
CHANGED
|
@@ -88,15 +88,23 @@ export declare function deleteJSON<T>(ctx: _FetchContext, path: string, opts?: {
|
|
|
88
88
|
* 409 + "session" → SessionBusyError
|
|
89
89
|
* 409 + "agent_id" → AgentIDInUseError
|
|
90
90
|
* 409 + (other) → LoomcycleError (base)
|
|
91
|
-
* 413
|
|
91
|
+
* 413 + code "snapshot_too_large" → SnapshotTooLargeError ──┐ all are
|
|
92
|
+
* 413 + code "prompt_too_large" → PromptTooLargeError │ instanceof
|
|
93
|
+
* 413 (other) → RequestTooLargeError ───┘ SnapshotTooLargeError
|
|
92
94
|
* 422 → SnapshotVersionError (snapshot-version-too-new/unknown)
|
|
93
|
-
* 429
|
|
95
|
+
* 429 + code "per_user_quota_exhausted" → PerUserQuotaExhaustedError
|
|
96
|
+
* 429 + code "token_limit_exceeded" → TokenLimitExceededError
|
|
97
|
+
* (subclass of BackpressureError)
|
|
98
|
+
* 429 (other) → BackpressureError
|
|
94
99
|
* 503 + "pause manager not configured" → PauseNotConfiguredError
|
|
95
100
|
* (subclass of UnavailableError)
|
|
96
101
|
* 503 + (other) → UnavailableError
|
|
97
102
|
* 500-599 (other) → LoomcycleError (base)
|
|
98
103
|
* default → LoomcycleError (base)
|
|
99
104
|
*
|
|
105
|
+
* Whatever class the status maps to, a JSON body's string `code` is on the
|
|
106
|
+
* error as `code` (see bodyCode).
|
|
107
|
+
*
|
|
100
108
|
* Priority within a status group is most-specific-first; an unknown
|
|
101
109
|
* 409 falls through to base LoomcycleError so callers see a
|
|
102
110
|
* meaningful message + status. For 404, the catch-all is NotFoundError
|
package/dist/fetch-helpers.js
CHANGED
|
@@ -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, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
|
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";
|
|
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. */
|
|
@@ -168,15 +168,23 @@ export async function deleteJSON(ctx, path, opts) {
|
|
|
168
168
|
* 409 + "session" → SessionBusyError
|
|
169
169
|
* 409 + "agent_id" → AgentIDInUseError
|
|
170
170
|
* 409 + (other) → LoomcycleError (base)
|
|
171
|
-
* 413
|
|
171
|
+
* 413 + code "snapshot_too_large" → SnapshotTooLargeError ──┐ all are
|
|
172
|
+
* 413 + code "prompt_too_large" → PromptTooLargeError │ instanceof
|
|
173
|
+
* 413 (other) → RequestTooLargeError ───┘ SnapshotTooLargeError
|
|
172
174
|
* 422 → SnapshotVersionError (snapshot-version-too-new/unknown)
|
|
173
|
-
* 429
|
|
175
|
+
* 429 + code "per_user_quota_exhausted" → PerUserQuotaExhaustedError
|
|
176
|
+
* 429 + code "token_limit_exceeded" → TokenLimitExceededError
|
|
177
|
+
* (subclass of BackpressureError)
|
|
178
|
+
* 429 (other) → BackpressureError
|
|
174
179
|
* 503 + "pause manager not configured" → PauseNotConfiguredError
|
|
175
180
|
* (subclass of UnavailableError)
|
|
176
181
|
* 503 + (other) → UnavailableError
|
|
177
182
|
* 500-599 (other) → LoomcycleError (base)
|
|
178
183
|
* default → LoomcycleError (base)
|
|
179
184
|
*
|
|
185
|
+
* Whatever class the status maps to, a JSON body's string `code` is on the
|
|
186
|
+
* error as `code` (see bodyCode).
|
|
187
|
+
*
|
|
180
188
|
* Priority within a status group is most-specific-first; an unknown
|
|
181
189
|
* 409 falls through to base LoomcycleError so callers see a
|
|
182
190
|
* meaningful message + status. For 404, the catch-all is NotFoundError
|
|
@@ -202,7 +210,7 @@ export async function raiseFromResponse(resp) {
|
|
|
202
210
|
// ("401 Unauthorized" not "401 " with a trailing space).
|
|
203
211
|
const statusPhrase = resp.statusText || stockStatusPhrase(status);
|
|
204
212
|
const msg = bodyText.trim() ? bodyText.slice(0, 1024) : `${status} ${statusPhrase}`;
|
|
205
|
-
const opts = { status, bodyText: bodyText.slice(0, 1024) };
|
|
213
|
+
const opts = { status, bodyText: bodyText.slice(0, 1024), code: bodyCode(bodyText) };
|
|
206
214
|
switch (status) {
|
|
207
215
|
case 400:
|
|
208
216
|
throw new InvalidArgumentError(msg, opts);
|
|
@@ -238,7 +246,14 @@ export async function raiseFromResponse(resp) {
|
|
|
238
246
|
throw new AgentIDInUseError(msg, opts);
|
|
239
247
|
throw new LoomcycleError(msg, opts);
|
|
240
248
|
case 413:
|
|
241
|
-
|
|
249
|
+
// Every 413 used to be a SnapshotTooLargeError, so the two classes
|
|
250
|
+
// below extend it: an existing `instanceof SnapshotTooLargeError`
|
|
251
|
+
// still matches all three.
|
|
252
|
+
if (opts.code === "snapshot_too_large")
|
|
253
|
+
throw new SnapshotTooLargeError(msg, opts);
|
|
254
|
+
if (opts.code === "prompt_too_large")
|
|
255
|
+
throw new PromptTooLargeError(msg, opts);
|
|
256
|
+
throw new RequestTooLargeError(msg, opts);
|
|
242
257
|
case 422: {
|
|
243
258
|
// 422 is shared between snapshot version errors (existing)
|
|
244
259
|
// and v0.8.22 substrate tool refusals. Discriminate by body:
|
|
@@ -247,7 +262,7 @@ export async function raiseFromResponse(resp) {
|
|
|
247
262
|
try {
|
|
248
263
|
const parsed = JSON.parse(bodyText);
|
|
249
264
|
if (parsed.code === "tool_refused") {
|
|
250
|
-
throw new SubstrateToolRefusedError(parsed.error ?? msg, { status, bodyText, tool: parsed.tool });
|
|
265
|
+
throw new SubstrateToolRefusedError(parsed.error ?? msg, { status, bodyText, code: parsed.code, tool: parsed.tool });
|
|
251
266
|
}
|
|
252
267
|
}
|
|
253
268
|
catch (e) {
|
|
@@ -259,6 +274,20 @@ export async function raiseFromResponse(resp) {
|
|
|
259
274
|
throw new SnapshotVersionError(msg, opts);
|
|
260
275
|
}
|
|
261
276
|
case 429: {
|
|
277
|
+
// 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).
|
|
280
|
+
if (opts.code === "token_limit_exceeded") {
|
|
281
|
+
const body = bodyObject(bodyText) ?? {};
|
|
282
|
+
throw new TokenLimitExceededError(msg, {
|
|
283
|
+
...opts,
|
|
284
|
+
scope: stringField(body.scope),
|
|
285
|
+
scopeId: stringField(body.scope_id),
|
|
286
|
+
used: numberField(body.used),
|
|
287
|
+
limit: numberField(body.limit),
|
|
288
|
+
window: stringField(body.window),
|
|
289
|
+
});
|
|
290
|
+
}
|
|
262
291
|
// v0.10.1: distinguish per-user quota exhaustion from
|
|
263
292
|
// operator-wide backpressure. The shapes share the 429 status
|
|
264
293
|
// but the JSON body's `code` field discriminates. Consumers
|
|
@@ -274,6 +303,7 @@ export async function raiseFromResponse(resp) {
|
|
|
274
303
|
throw new PerUserQuotaExhaustedError(parsed.error ?? msg, {
|
|
275
304
|
status,
|
|
276
305
|
bodyText,
|
|
306
|
+
code: parsed.code,
|
|
277
307
|
userId: parsed.user_id,
|
|
278
308
|
cap: parsed.cap,
|
|
279
309
|
retryAfterMs: Number.isFinite(retryAfterMs) ? retryAfterMs : undefined,
|
|
@@ -295,6 +325,36 @@ export async function raiseFromResponse(resp) {
|
|
|
295
325
|
throw new LoomcycleError(msg, opts);
|
|
296
326
|
}
|
|
297
327
|
}
|
|
328
|
+
/** bodyCode returns the string `code` of a JSON error body, or undefined when
|
|
329
|
+
* the body is not a JSON object or has none. Statuses are shared between
|
|
330
|
+
* unrelated conditions (a 400 is any bad request; a 429 is backpressure, a
|
|
331
|
+
* user quota or a token budget), and the code is what tells them apart. */
|
|
332
|
+
function bodyCode(bodyText) {
|
|
333
|
+
return stringField(bodyObject(bodyText)?.code);
|
|
334
|
+
}
|
|
335
|
+
/** bodyObject returns a JSON error body as an object, or undefined when the
|
|
336
|
+
* body is not JSON or is a JSON array or scalar. */
|
|
337
|
+
function bodyObject(bodyText) {
|
|
338
|
+
try {
|
|
339
|
+
const parsed = JSON.parse(bodyText);
|
|
340
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
341
|
+
return parsed;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// not JSON: a plain-text error body has no fields
|
|
346
|
+
}
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
349
|
+
/** stringField / numberField read one body field, dropping a value of the
|
|
350
|
+
* wrong type: an error's typed fields must not carry whatever a proxy or an
|
|
351
|
+
* older server put under that name. An empty string counts as absent. */
|
|
352
|
+
function stringField(v) {
|
|
353
|
+
return typeof v === "string" && v !== "" ? v : undefined;
|
|
354
|
+
}
|
|
355
|
+
function numberField(v) {
|
|
356
|
+
return typeof v === "number" && Number.isFinite(v) ? v : undefined;
|
|
357
|
+
}
|
|
298
358
|
/** stockStatusPhrase returns a stock reason phrase for the common
|
|
299
359
|
* HTTP statuses raiseFromResponse handles. Used as a fallback when
|
|
300
360
|
* Response.statusText is empty (HTTP/2 strips reason phrases). */
|
package/dist/index.d.ts
CHANGED
|
@@ -115,7 +115,9 @@
|
|
|
115
115
|
* AuthError, UnavailableError, InvalidArgumentError,
|
|
116
116
|
* PauseNotConfiguredError (subclass of UnavailableError),
|
|
117
117
|
* AlreadyPausingError, NotPausedError, SnapshotNotFoundError,
|
|
118
|
-
* SnapshotTooLargeError,
|
|
118
|
+
* SnapshotTooLargeError, RequestTooLargeError + PromptTooLargeError
|
|
119
|
+
* (both subclasses of SnapshotTooLargeError), TokenLimitExceededError
|
|
120
|
+
* (subclass of BackpressureError), SnapshotVersionError,
|
|
119
121
|
* SubstrateToolRefusedError (v0.8.22)
|
|
120
122
|
*
|
|
121
123
|
* Transport: HTTP+SSE. Auth: Bearer token via the Authorization
|
|
@@ -130,5 +132,5 @@ export { InteractiveSession } from "./interactive.js";
|
|
|
130
132
|
export type { InteractiveSessionOps } from "./interactive.js";
|
|
131
133
|
export { ClientToolHost, clientToolsURL, CLIENT_TOOL_SUBPROTOCOL } from "./client-tools.js";
|
|
132
134
|
export type { ClientToolSchema, ClientToolInvocation, ConnectClientToolsOptions, WebSocketLike, WebSocketCtor, } from "./client-tools.js";
|
|
133
|
-
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, 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, EffectiveConfigResponse, EffectiveConfigSource, EffectiveValue, RetuneRunResponse, RunConfigRecord, SubagentHoldInfo, RunConfigResponse, RunPromptResponse, RunPromptSnapshot, PromptBlock, TokenLimit, TokenLimitsResponse, ConfigResponse, ConfigProvider, ConfigModel, ConfigSearch, ConfigInstance, SetTokenLimitRequest, CredentialScope, CredentialMeta, CredentialListResponse, } from "./types.js";
|
|
134
|
-
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.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, 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, 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";
|
package/dist/index.js
CHANGED
|
@@ -115,7 +115,9 @@
|
|
|
115
115
|
* AuthError, UnavailableError, InvalidArgumentError,
|
|
116
116
|
* PauseNotConfiguredError (subclass of UnavailableError),
|
|
117
117
|
* AlreadyPausingError, NotPausedError, SnapshotNotFoundError,
|
|
118
|
-
* SnapshotTooLargeError,
|
|
118
|
+
* SnapshotTooLargeError, RequestTooLargeError + PromptTooLargeError
|
|
119
|
+
* (both subclasses of SnapshotTooLargeError), TokenLimitExceededError
|
|
120
|
+
* (subclass of BackpressureError), SnapshotVersionError,
|
|
119
121
|
* SubstrateToolRefusedError (v0.8.22)
|
|
120
122
|
*
|
|
121
123
|
* Transport: HTTP+SSE. Auth: Bearer token via the Authorization
|
|
@@ -128,4 +130,4 @@
|
|
|
128
130
|
export { LoomcycleClient } from "./client.js";
|
|
129
131
|
export { InteractiveSession } from "./interactive.js";
|
|
130
132
|
export { ClientToolHost, clientToolsURL, CLIENT_TOOL_SUBPROTOCOL } from "./client-tools.js";
|
|
131
|
-
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
|
133
|
+
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";
|