@loomcycle/client 0.10.0 → 0.10.2
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 +18 -0
- package/dist/cjs/client.js +734 -0
- package/dist/cjs/errors.js +246 -0
- package/dist/cjs/fetch-helpers.js +253 -0
- package/dist/cjs/index.js +91 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/stream.js +84 -0
- package/dist/cjs/types.js +11 -0
- package/dist/errors.d.ts +50 -0
- package/dist/errors.js +50 -0
- package/dist/fetch-helpers.js +29 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +9 -5
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Wire-shape types for the loomcycle HTTP+SSE surface. Field names use
|
|
4
|
+
* snake_case to match the Go server's JSON output (no client-side
|
|
5
|
+
* conversion — what's on the wire is what you get).
|
|
6
|
+
*
|
|
7
|
+
* Public API method *parameters* use camelCase (JS norm); see
|
|
8
|
+
* `client.ts` for the input shapes (RunOptions, CreateSnapshotOptions,
|
|
9
|
+
* etc.) — those are translated to snake_case in the request body.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/dist/errors.d.ts
CHANGED
|
@@ -66,6 +66,56 @@ export declare class BackpressureError extends LoomcycleError {
|
|
|
66
66
|
bodyText?: string;
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
|
+
/**
|
|
70
|
+
* PerUserQuotaExhaustedError signals that the caller has hit their
|
|
71
|
+
* per-user cap on in-flight (active+queued) runs. Distinct from
|
|
72
|
+
* BackpressureError because the appropriate retry strategy differs:
|
|
73
|
+
* backpressure is operator-wide load (exponential backoff with jitter),
|
|
74
|
+
* per-user quota is "you specifically need to wait" (fixed window —
|
|
75
|
+
* server hint: `Retry-After: 5` seconds).
|
|
76
|
+
*
|
|
77
|
+
* v0.10.1+. Maps from HTTP 429 + JSON body
|
|
78
|
+
* `{"code":"per_user_quota_exhausted","user_id":"...","cap":N}`.
|
|
79
|
+
*
|
|
80
|
+
* The `userId` and `cap` fields are populated from the JSON body when
|
|
81
|
+
* the response is parseable; null when the server didn't include them
|
|
82
|
+
* (very old loomcycle binaries or non-JSON 429 responses).
|
|
83
|
+
*
|
|
84
|
+
* Typical handling:
|
|
85
|
+
*
|
|
86
|
+
* try { await client.runStreaming(...); }
|
|
87
|
+
* catch (e) {
|
|
88
|
+
* if (e instanceof PerUserQuotaExhaustedError) {
|
|
89
|
+
* // Wait the server-suggested window, then retry.
|
|
90
|
+
* await sleep(e.retryAfterMs ?? 5000);
|
|
91
|
+
* return client.runStreaming(...);
|
|
92
|
+
* }
|
|
93
|
+
* if (e instanceof BackpressureError) {
|
|
94
|
+
* // Operator-wide load — jittered backoff.
|
|
95
|
+
* await sleep(jittered(2000, 30000));
|
|
96
|
+
* return client.runStreaming(...);
|
|
97
|
+
* }
|
|
98
|
+
* throw e;
|
|
99
|
+
* }
|
|
100
|
+
*/
|
|
101
|
+
export declare class PerUserQuotaExhaustedError extends LoomcycleError {
|
|
102
|
+
/** Server-side user identifier the cap applies to. Null when the
|
|
103
|
+
* server didn't include it in the JSON body. */
|
|
104
|
+
readonly userId: string | null;
|
|
105
|
+
/** Per-user cap value as configured on the server (active+queued).
|
|
106
|
+
* Null when the server didn't include it. */
|
|
107
|
+
readonly cap: number | null;
|
|
108
|
+
/** Server-suggested retry window in milliseconds, from the
|
|
109
|
+
* Retry-After header. Null when absent. */
|
|
110
|
+
readonly retryAfterMs: number | null;
|
|
111
|
+
constructor(message: string, opts?: {
|
|
112
|
+
status?: number;
|
|
113
|
+
bodyText?: string;
|
|
114
|
+
userId?: string;
|
|
115
|
+
cap?: number;
|
|
116
|
+
retryAfterMs?: number;
|
|
117
|
+
});
|
|
118
|
+
}
|
|
69
119
|
export declare class AuthError extends LoomcycleError {
|
|
70
120
|
constructor(message: string, opts?: {
|
|
71
121
|
status?: number;
|
package/dist/errors.js
CHANGED
|
@@ -68,6 +68,56 @@ export class BackpressureError extends LoomcycleError {
|
|
|
68
68
|
this.name = "BackpressureError";
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* PerUserQuotaExhaustedError signals that the caller has hit their
|
|
73
|
+
* per-user cap on in-flight (active+queued) runs. Distinct from
|
|
74
|
+
* BackpressureError because the appropriate retry strategy differs:
|
|
75
|
+
* backpressure is operator-wide load (exponential backoff with jitter),
|
|
76
|
+
* per-user quota is "you specifically need to wait" (fixed window —
|
|
77
|
+
* server hint: `Retry-After: 5` seconds).
|
|
78
|
+
*
|
|
79
|
+
* v0.10.1+. Maps from HTTP 429 + JSON body
|
|
80
|
+
* `{"code":"per_user_quota_exhausted","user_id":"...","cap":N}`.
|
|
81
|
+
*
|
|
82
|
+
* The `userId` and `cap` fields are populated from the JSON body when
|
|
83
|
+
* the response is parseable; null when the server didn't include them
|
|
84
|
+
* (very old loomcycle binaries or non-JSON 429 responses).
|
|
85
|
+
*
|
|
86
|
+
* Typical handling:
|
|
87
|
+
*
|
|
88
|
+
* try { await client.runStreaming(...); }
|
|
89
|
+
* catch (e) {
|
|
90
|
+
* if (e instanceof PerUserQuotaExhaustedError) {
|
|
91
|
+
* // Wait the server-suggested window, then retry.
|
|
92
|
+
* await sleep(e.retryAfterMs ?? 5000);
|
|
93
|
+
* return client.runStreaming(...);
|
|
94
|
+
* }
|
|
95
|
+
* if (e instanceof BackpressureError) {
|
|
96
|
+
* // Operator-wide load — jittered backoff.
|
|
97
|
+
* await sleep(jittered(2000, 30000));
|
|
98
|
+
* return client.runStreaming(...);
|
|
99
|
+
* }
|
|
100
|
+
* throw e;
|
|
101
|
+
* }
|
|
102
|
+
*/
|
|
103
|
+
export class PerUserQuotaExhaustedError extends LoomcycleError {
|
|
104
|
+
/** Server-side user identifier the cap applies to. Null when the
|
|
105
|
+
* server didn't include it in the JSON body. */
|
|
106
|
+
userId;
|
|
107
|
+
/** Per-user cap value as configured on the server (active+queued).
|
|
108
|
+
* Null when the server didn't include it. */
|
|
109
|
+
cap;
|
|
110
|
+
/** Server-suggested retry window in milliseconds, from the
|
|
111
|
+
* Retry-After header. Null when absent. */
|
|
112
|
+
retryAfterMs;
|
|
113
|
+
constructor(message, opts) {
|
|
114
|
+
super(message, opts);
|
|
115
|
+
this.name = "PerUserQuotaExhaustedError";
|
|
116
|
+
this.userId = opts?.userId ?? null;
|
|
117
|
+
this.cap = opts?.cap ?? null;
|
|
118
|
+
this.retryAfterMs = opts?.retryAfterMs ?? null;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
71
121
|
export class AuthError extends LoomcycleError {
|
|
72
122
|
constructor(message, opts) {
|
|
73
123
|
super(message, opts);
|
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, HookNotFoundError, InvalidArgumentError, LoomcycleError, NotFoundError, NotPausedError, PauseNotConfiguredError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
|
12
|
+
import { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, ChannelCursorRegressionError, HookNotFoundError, InvalidArgumentError, LoomcycleError, NotFoundError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, 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. */
|
|
@@ -187,8 +187,35 @@ export async function raiseFromResponse(resp) {
|
|
|
187
187
|
}
|
|
188
188
|
throw new SnapshotVersionError(msg, opts);
|
|
189
189
|
}
|
|
190
|
-
case 429:
|
|
190
|
+
case 429: {
|
|
191
|
+
// v0.10.1: distinguish per-user quota exhaustion from
|
|
192
|
+
// operator-wide backpressure. The shapes share the 429 status
|
|
193
|
+
// but the JSON body's `code` field discriminates. Consumers
|
|
194
|
+
// branch retry strategies on the typed error.
|
|
195
|
+
try {
|
|
196
|
+
const parsed = JSON.parse(bodyText);
|
|
197
|
+
if (parsed.code === "per_user_quota_exhausted") {
|
|
198
|
+
// Retry-After is `<seconds>` per RFC; convert to ms.
|
|
199
|
+
const retryAfterRaw = resp.headers.get("retry-after");
|
|
200
|
+
const retryAfterMs = retryAfterRaw
|
|
201
|
+
? Number.parseInt(retryAfterRaw, 10) * 1000
|
|
202
|
+
: undefined;
|
|
203
|
+
throw new PerUserQuotaExhaustedError(parsed.error ?? msg, {
|
|
204
|
+
status,
|
|
205
|
+
bodyText,
|
|
206
|
+
userId: parsed.user_id,
|
|
207
|
+
cap: parsed.cap,
|
|
208
|
+
retryAfterMs: Number.isFinite(retryAfterMs) ? retryAfterMs : undefined,
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
catch (e) {
|
|
213
|
+
// Re-throw the typed error; fall through on JSON-parse fail.
|
|
214
|
+
if (e instanceof PerUserQuotaExhaustedError)
|
|
215
|
+
throw e;
|
|
216
|
+
}
|
|
191
217
|
throw new BackpressureError(msg, opts);
|
|
218
|
+
}
|
|
192
219
|
case 503:
|
|
193
220
|
if (bodyLower.includes("pause") && bodyLower.includes("not configured"))
|
|
194
221
|
throw new PauseNotConfiguredError(msg, opts);
|
package/dist/index.d.ts
CHANGED
|
@@ -65,4 +65,4 @@
|
|
|
65
65
|
*/
|
|
66
66
|
export { LoomcycleClient } from "./client.js";
|
|
67
67
|
export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, PromptContent, PromptSegment, RetryInfo, RunOptions, ToolUse, Usage, Agent, AgentStatus, AgentUsage, CancelAgentResult, ListAgentsResponse, TranscriptEvent, TranscriptResponse, HealthResponse, ListUsersResponse, UserSummary, PauseResult, ResumeResult, RuntimeStateResponse, RuntimeStateStatus, CreateSnapshotOptions, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotListResponse, SnapshotRestoreResponse, MemoryEntriesResponse, MemoryEntry, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopeIDSummary, MemoryScopeKind, MemoryScopesResponse, InterruptListResponse, InterruptRow, InterruptStatus, ResolveInterruptOptions, Hook, HookFailMode, HookPhase, HookToolCall, HookToolResult, ListHooksResponse, PostHookCall, PostHookResult, PreHookCall, PreHookResult, RegisterHookOptions, RegisterHookResponse, SubstrateToolInput, SubstrateToolResponse, SystemPromptPayload, UserInputPayload, ChannelDescriptor, ListChannelsResponse, RunStateEvent, RunStateStreamClose, RunStateStreamItem, RunStateStreamOpen, StreamUserRunStatesOptions, AckChannelOptions, ChannelAckResult, ChannelMessageItem, ChannelPeekResult, ChannelPublishResult, ChannelScope, ChannelSubscribeResult, PeekChannelOptions, PublishChannelOptions, SubscribeChannelOptions, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, } from "./types.js";
|
|
68
|
-
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, HookNotFoundError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
|
68
|
+
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, HookNotFoundError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
package/dist/index.js
CHANGED
|
@@ -64,4 +64,4 @@
|
|
|
64
64
|
* See `adapters/ts/README.md` for usage examples.
|
|
65
65
|
*/
|
|
66
66
|
export { LoomcycleClient } from "./client.js";
|
|
67
|
-
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, HookNotFoundError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
|
67
|
+
export { AgentIDInUseError, AgentNotFoundError, AlreadyPausingError, AuthError, BackpressureError, HookNotFoundError, NotFoundError, InvalidArgumentError, ChannelCursorRegressionError, LoomcycleError, NotPausedError, PauseNotConfiguredError, PerUserQuotaExhaustedError, SessionBusyError, SessionNotFoundError, SnapshotNotFoundError, SnapshotTooLargeError, SnapshotVersionError, SubstrateToolRefusedError, UnavailableError, } from "./errors.js";
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomcycle/client",
|
|
3
|
-
"version": "0.10.
|
|
4
|
-
"description": "TypeScript client for the loomcycle sidecar (HTTP+SSE). 36 methods covering run streaming, agent metadata, pause/resume/state, snapshot lifecycle, memory admin (incl. v0.9.0 Vector Memory embed_stats + reembed), interruption resolve, hook management, v0.8.22 substrate admin (agentDef + skillDef), v0.9.x n8n Phase 0 (listChannels + streamUserRunStates — with debug-mode synthetic open/close meta-frames + client-side parentAgentId filter), v0.9.x Channel CRUD (publishChannel + subscribeChannel + peekChannel + ackChannel — admin scope=global + per-user scope=user surfaces), v0.9.x content_sha256 (AgentDefVerifyResult + SkillDefVerifyResult types for the bundle-vs-deployed comparison workflow), v0.9.1 transcript first-cycle (SystemPromptPayload + UserInputPayload), and v0.9.x dynamic MCP server registration (mcpServerDef + MCPServerDefVerifyResult — register HTTP/Streamable-HTTP MCP servers at runtime without yaml edits).",
|
|
3
|
+
"version": "0.10.2",
|
|
4
|
+
"description": "TypeScript client for the loomcycle sidecar (HTTP+SSE). 36 methods covering run streaming, agent metadata, pause/resume/state, snapshot lifecycle, memory admin (incl. v0.9.0 Vector Memory embed_stats + reembed), interruption resolve, hook management, v0.8.22 substrate admin (agentDef + skillDef), v0.9.x n8n Phase 0 (listChannels + streamUserRunStates — with debug-mode synthetic open/close meta-frames + client-side parentAgentId filter), v0.9.x Channel CRUD (publishChannel + subscribeChannel + peekChannel + ackChannel — admin scope=global + per-user scope=user surfaces), v0.9.x content_sha256 (AgentDefVerifyResult + SkillDefVerifyResult types for the bundle-vs-deployed comparison workflow), v0.9.1 transcript first-cycle (SystemPromptPayload + UserInputPayload), and v0.9.x dynamic MCP server registration (mcpServerDef + MCPServerDefVerifyResult — register HTTP/Streamable-HTTP MCP servers at runtime without yaml edits). v0.10.1 — dual ESM + CommonJS distribution (additive — ESM consumers unchanged; CJS consumers like n8n's community-node loader now work).",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|
|
@@ -13,12 +13,14 @@
|
|
|
13
13
|
"bugs": {
|
|
14
14
|
"url": "https://github.com/denn-gubsky/loomcycle/issues"
|
|
15
15
|
},
|
|
16
|
-
"main": "./dist/index.js",
|
|
16
|
+
"main": "./dist/cjs/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
17
18
|
"types": "./dist/index.d.ts",
|
|
18
19
|
"exports": {
|
|
19
20
|
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
20
22
|
"import": "./dist/index.js",
|
|
21
|
-
"
|
|
23
|
+
"require": "./dist/cjs/index.js"
|
|
22
24
|
}
|
|
23
25
|
},
|
|
24
26
|
"files": [
|
|
@@ -26,7 +28,9 @@
|
|
|
26
28
|
"README.md"
|
|
27
29
|
],
|
|
28
30
|
"scripts": {
|
|
29
|
-
"build": "tsc",
|
|
31
|
+
"build": "tsc && tsc -p tsconfig.cjs.json && node -e \"require('fs').writeFileSync('dist/cjs/package.json', JSON.stringify({type:'commonjs'}, null, 2))\"",
|
|
32
|
+
"build:esm": "tsc",
|
|
33
|
+
"build:cjs": "tsc -p tsconfig.cjs.json && node -e \"require('fs').writeFileSync('dist/cjs/package.json', JSON.stringify({type:'commonjs'}, null, 2))\"",
|
|
30
34
|
"typecheck": "tsc --noEmit",
|
|
31
35
|
"test": "vitest run",
|
|
32
36
|
"test:watch": "vitest"
|