@loomcycle/client 0.15.0 → 0.18.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 CHANGED
@@ -6,12 +6,15 @@ TypeScript client for the [loomcycle](https://github.com/denn-gubsky/loomcycle)
6
6
 
7
7
  ## Status
8
8
 
9
- **v0.11.4** — 42 methods covering run streaming, agent metadata, transcript, pause/resume/state, snapshot lifecycle, memory admin, interruption resolve, hook registration, **v0.8.22 substrate admin (agentDef + skillDef)**, **v0.9.x n8n Phase 0 (listChannels + streamUserRunStates)**, **v0.9.x content_sha256**, **v0.9.x dynamic MCP server registration (mcpServerDef)**, **v0.10.3 Library v2 enumeration (listLibraryAgents/Skills/McpServers)**, **v0.11.0 LLM Gateway (llmChat + llmStream)**, **v0.11.4 OpenAI Embeddings (embeddings)**, and health.
9
+ **v0.18.0** — 51 methods covering run streaming, agent metadata, transcript, pause/resume/state, snapshot lifecycle, memory admin, interruption resolve, hook registration, **v0.8.22 substrate admin (agentDef + skillDef)**, **v0.9.x n8n Phase 0 (listChannels + streamUserRunStates)**, **v0.9.x content_sha256**, **v0.9.x dynamic MCP server registration (mcpServerDef)** + **v0.18.0 typed `mcpServerDefVerify` + `ensureMcpServer` (idempotent register-if-changed)**, **v0.10.3 Library v2 enumeration (listLibraryAgents/Skills/McpServers)**, **v0.11.0 LLM Gateway (llmChat + llmStream)**, **v0.11.4 OpenAI Embeddings (embeddings)**, **v0.17.0 OSS multi-tenant auth (operatorTokenDef + whoami + tenant-scoped listUsers / listUserAgents — RFC L)**, and health.
10
10
 
11
11
  > Migrating from raw `fetch` against `/v1/*`? See **[docs/MIGRATING-FROM-HTTP.md](./docs/MIGRATING-FROM-HTTP.md)** for a side-by-side walkthrough.
12
12
 
13
13
  ### What's new since v0.8.18
14
14
 
15
+ - **`ensureMcpServer` / `mcpServerDefVerify`** (v0.18.0) — typed ergonomics for the dynamic-MCP dedup flow. `ensureMcpServer({name, url, headers?, rediscover?})` registers a callback MCP server **idempotently**: it runs `create` (a no-op in loomcycle ≥ v0.18.0 when the active def already carries identical content) plus an optional `rediscover` (a no-op on unchanged tools), and returns `{defId, version, changed, discoveredToolCount?}` — so a consumer re-registering on every startup gets `changed: false` once its registration content is stable. Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders **literal** (don't bake a per-restart token) or the content varies each boot and dedup can't engage. `mcpServerDefVerify(name, sha)` is the typed `op: verify` wrapper (`matches: true` = no-op signal).
16
+ - **`operatorTokenDef` / `whoami` + tenant-scoped reads** (v0.17.0, RFC L) — the OSS multi-tenant authorization surface. `operatorTokenDef` is the op-discriminated admin tool over the `OperatorTokenDef` substrate (create / rotate / retire per-principal bearer tokens); `whoami()` returns the authoritative `(tenant, subject, scopes, is_admin)` resolved from the calling bearer; `listUsers({ tenant })` / `listUserAgents(userId, { tenant })` accept a super-admin tenant-focus (ignored server-side for a tenant principal — its own tenant is forced).
17
+
15
18
  - **`llmChat` / `llmStream`** (v0.11.0) — direct LLM call surface that bypasses the agent loop. Provider routing + auth + retry without the ~50-200 ms per-turn overhead of a full `runStreaming` spawn. Drives n8n's `LoomCycleChatModel` AI Agent sub-node + any LangChain `BaseChatModel` consumer.
16
19
  - **`listLibraryAgents` / `listLibrarySkills` / `listLibraryMcpServers`** (v0.10.3) — typed wrappers around the v0.9.3 Library v2 endpoints. Each returns a `LibraryListResponse<T>` with source-tagged entries (`"static-only"` / `"dynamic-only"` / `"both"`) merging yaml + substrate views.
17
20
  - **`mcpServerDef`** (v0.9.x) — runtime registration of HTTP / Streamable-HTTP MCP servers without yaml edits. Same op grammar (create / fork / promote / retire / rediscover) as `agentDef` / `skillDef`.
@@ -122,6 +125,7 @@ All methods are async / return `Promise<T>` unless noted; streaming methods retu
122
125
  | `pauseRuntime(opts?: { timeoutMs? })` | `Promise<PauseResult>` | Quiesce the runtime. Raises `AlreadyPausingError` on 409, `PauseNotConfiguredError` on 503. |
123
126
  | `resumeRuntime()` | `Promise<ResumeResult>` | Release the quiesce. Raises `NotPausedError` on 409. |
124
127
  | `getRuntimeState()` | `Promise<RuntimeStateResponse>` | Current state + paused-runs count. |
128
+ | `resolveProbe()` | `Promise<ResolverMatrix>` | Force an immediate provider re-probe; returns the refreshed availability matrix. Raises `UnavailableError` on 503 (no resolver / no probe loop). |
125
129
 
126
130
  ### Snapshot lifecycle (v0.8.17 / v0.8.18)
127
131
 
@@ -156,7 +156,12 @@ class LoomcycleClient {
156
156
  * request); the adapter trims before returning. Useful for the
157
157
  * n8n trigger pattern "show me all sub-runs spawned by parent X." */
158
158
  async listUserAgents(userId, opts) {
159
- const q = opts?.status ? `?status=${encodeURIComponent(opts.status)}` : "";
159
+ const params = new URLSearchParams();
160
+ if (opts?.status)
161
+ params.set("status", opts.status);
162
+ if (opts?.tenant)
163
+ params.set("tenant", opts.tenant);
164
+ const q = params.toString() ? `?${params.toString()}` : "";
160
165
  const resp = await (0, fetch_helpers_js_1.jsonFetch)(this.ctx, `/v1/users/${encodeURIComponent(userId)}/agents${q}`, opts);
161
166
  const all = resp.agents ?? [];
162
167
  if (opts?.parentAgentId !== undefined && opts.parentAgentId !== "") {
@@ -174,10 +179,20 @@ class LoomcycleClient {
174
179
  async health(opts) {
175
180
  return (0, fetch_helpers_js_1.jsonFetch)(this.ctx, "/healthz", opts);
176
181
  }
177
- /** Admin: list known users with running-count summary. Drives the
178
- * Web UI's user picker; operators with bearer auth can call too. */
182
+ /** List known users with running-count summary. Drives the Web UI's
183
+ * user picker. Tenant-scoped server-side since v0.17.0 (RFC L): a
184
+ * tenant principal sees only its own tenant's users; an admin sees all,
185
+ * or focuses one tenant via `tenant` (?tenant=). */
179
186
  async listUsers(opts) {
180
- return (0, fetch_helpers_js_1.jsonFetch)(this.ctx, "/v1/_users", opts);
187
+ const q = opts?.tenant ? `?tenant=${encodeURIComponent(opts.tenant)}` : "";
188
+ return (0, fetch_helpers_js_1.jsonFetch)(this.ctx, `/v1/_users${q}`, opts);
189
+ }
190
+ /** Whoami — the authenticated principal (RFC L v0.17.0). Any
191
+ * authenticated bearer; returns its authoritative tenant / subject /
192
+ * scopes + `is_admin`. `open_mode: true` when the server runs without
193
+ * the token substrate (single shared LOOMCYCLE_AUTH_TOKEN). */
194
+ async whoami(opts) {
195
+ return (0, fetch_helpers_js_1.jsonFetch)(this.ctx, "/v1/_me", opts);
181
196
  }
182
197
  // ---- v0.8.17/8.18 Pause / Resume / State ----
183
198
  /** Quiesce the runtime. Idempotent tools cancel immediately;
@@ -199,6 +214,14 @@ class LoomcycleClient {
199
214
  async getRuntimeState(opts) {
200
215
  return (0, fetch_helpers_js_1.jsonFetch)(this.ctx, "/v1/_state", opts);
201
216
  }
217
+ /** Trigger an immediate re-probe of every configured provider and
218
+ * return the refreshed availability matrix. Operator-only escape
219
+ * hatch when a transient outage stalls every provider and the
220
+ * runtime would otherwise 503 until the next periodic probe.
221
+ * Mirrors POST /v1/_resolve/probe. */
222
+ async resolveProbe(opts) {
223
+ return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_resolve/probe", undefined, opts);
224
+ }
202
225
  // ---- Snapshot lifecycle ----
203
226
  /** Capture running-state into a per-section-semver JSON envelope.
204
227
  * Raises SnapshotTooLargeError on 413 when the envelope exceeds
@@ -419,8 +442,10 @@ class LoomcycleClient {
419
442
  * Hard constraints (substrate refuses these):
420
443
  * - Transport must be `http` or `streamable-http` (stdio stays
421
444
  * yaml-only — dynamic registration doesn't allow process spawn).
422
- * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (SSRF
423
- * defence at the registration boundary).
445
+ * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
446
+ * v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
447
+ * a self-hosted loopback callback like `http://localhost:3000/api/mcp`
448
+ * belongs (SSRF defence at the registration boundary).
424
449
  * - Name colliding with a static cfg.MCPServers entry is refused
425
450
  * (yaml is ground truth; use a different name).
426
451
  *
@@ -430,6 +455,57 @@ class LoomcycleClient {
430
455
  async mcpServerDef(input, opts) {
431
456
  return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_mcpserverdef", input, opts);
432
457
  }
458
+ /** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
459
+ * hash for `name`?" `matches: true` is the no-op signal (the analog of
460
+ * the agent/skill verify-before-create dedup). Thin typed wrapper over
461
+ * {@link mcpServerDef}. */
462
+ async mcpServerDefVerify(name, contentSha256, opts) {
463
+ return (await this.mcpServerDef({ op: "verify", name, content_sha256: contentSha256 }, opts));
464
+ }
465
+ /** Register (or refresh) a dynamic MCP server idempotently — the typed
466
+ * "register-if-changed" convenience for a consumer that re-registers its
467
+ * own callback server on every startup.
468
+ *
469
+ * Runs `create` (which is content-addressed-idempotent in loomcycle
470
+ * ≥ v0.18.0 — a byte-identical re-registration is a no-op, not a new
471
+ * version) and, when {@link EnsureMcpServerOptions.rediscover} is set, a
472
+ * `tools/list` rediscover (also idempotent on unchanged tools). The
473
+ * returned {@link EnsureMcpServerResult.changed} is false when loomcycle
474
+ * deduped both — so a stable-content re-register on every boot is a clean
475
+ * no-op. Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL
476
+ * (don't resolve a per-restart token) or the content varies each boot and
477
+ * dedup can't engage. */
478
+ async ensureMcpServer(opts, callOpts) {
479
+ const overlay = {
480
+ transport: opts.transport ?? "http",
481
+ url: opts.url,
482
+ };
483
+ if (opts.headers)
484
+ overlay.headers = opts.headers;
485
+ const createInput = { op: "create", name: opts.name, overlay };
486
+ if (opts.description)
487
+ createInput.description = opts.description;
488
+ const created = (await this.mcpServerDef(createInput, callOpts));
489
+ let row = created;
490
+ let changed = created.deduplicated !== true;
491
+ let discoveredToolCount;
492
+ if (opts.rediscover) {
493
+ const red = (await this.mcpServerDef({ op: "rediscover", name: opts.name }, callOpts));
494
+ row = red;
495
+ if (red.deduplicated !== true)
496
+ changed = true;
497
+ discoveredToolCount = red.discovered;
498
+ }
499
+ const result = {
500
+ name: opts.name,
501
+ defId: row.def_id,
502
+ version: row.version,
503
+ changed,
504
+ };
505
+ if (discoveredToolCount !== undefined)
506
+ result.discoveredToolCount = discoveredToolCount;
507
+ return result;
508
+ }
433
509
  /** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
434
510
  * Author + fork + retire scheduled-run definitions at runtime.
435
511
  * Mirror of {@link LoomcycleClient.agentDef} for schedules — the
@@ -522,6 +598,13 @@ class LoomcycleClient {
522
598
  async memoryBackendDef(input, opts) {
523
599
  return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_memorybackenddef", input, opts);
524
600
  }
601
+ /** OperatorTokenDef substrate ops (create/rotate/retire/get/list) —
602
+ * RFC L OSS multi-tenant authorization. Operator-admin only. The
603
+ * token plaintext is returned ONCE in the create/rotate response.
604
+ * Mirrors POST /v1/_operatortokendef. */
605
+ async operatorTokenDef(input, opts) {
606
+ return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_operatortokendef", input, opts);
607
+ }
525
608
  // ---- v0.10.3 Library v2 enumeration (read-only, merged yaml+substrate) ----
526
609
  /** List every agent the runtime knows about — yaml-static + dynamic
527
610
  * AgentDefs merged into one envelope per name. Each entry carries
package/dist/cjs/index.js CHANGED
@@ -17,12 +17,14 @@
17
17
  * listUserAgents(userId, opts?): Promise<Agent[]>
18
18
  * getTranscript(sessionId): Promise<TranscriptResponse>
19
19
  * health(): Promise<HealthResponse>
20
- * listUsers(): Promise<ListUsersResponse>
20
+ * listUsers(opts?): Promise<ListUsersResponse> // tenant-scoped (RFC L)
21
+ * whoami(): Promise<WhoamiResponse> // RFC L principal (v0.17.0)
21
22
  *
22
23
  * // Pause / Resume / State (v0.8.17/8.18)
23
24
  * pauseRuntime(opts?): Promise<PauseResult>
24
25
  * resumeRuntime(): Promise<ResumeResult>
25
26
  * getRuntimeState(): Promise<RuntimeStateResponse>
27
+ * resolveProbe(opts?): Promise<ResolverMatrix>
26
28
  *
27
29
  * // Snapshot lifecycle (v0.8.17/8.18)
28
30
  * createSnapshot(opts?): Promise<SnapshotCreateResponse>
@@ -47,6 +49,8 @@
47
49
  * agentDef(input): Promise<SubstrateToolResponse>
48
50
  * skillDef(input): Promise<SubstrateToolResponse>
49
51
  * mcpServerDef(input): Promise<SubstrateToolResponse>
52
+ * mcpServerDefVerify(name, sha): Promise<MCPServerDefVerifyResult> // v0.18.0
53
+ * ensureMcpServer(opts): Promise<EnsureMcpServerResult> // v0.18.0 — idempotent register-if-changed
50
54
  * scheduleDef(input): Promise<SubstrateToolResponse>
51
55
  *
52
56
  * // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
package/dist/client.d.ts CHANGED
@@ -23,7 +23,7 @@
23
23
  * via fetch-helpers.ts:raiseFromResponse — see README.md for the
24
24
  * full mapping table.
25
25
  */
26
- import type { Agent, AgentEvent, AgentStatus, CancelAgentResult, ClientOptions, ContinueOptions, CreateSnapshotOptions, HealthResponse, Hook, InterruptListResponse, InterruptStatus, AckChannelOptions, ChannelAckResult, ChannelDescriptor, ChannelPeekResult, ChannelPublishResult, ChannelSubscribeResult, CreateChannelOptions, ListChannelsResponse, PeekChannelOptions, PublishChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, SubscribeChannelOptions, UpdateChannelOptions, LibraryAgentDefinition, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, ListUsersResponse, LLMChatOptions, LLMChatResponse, LLMChatStreamItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, MemoryEntriesResponse, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopesResponse, PauseResult, RegisterHookOptions, RegisterHookResponse, ResolveInterruptOptions, ResumeResult, RunOptions, RunStateStreamItem, RuntimeStateResponse, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotRestoreResponse, StreamUserRunStatesOptions, SubstrateToolInput, SubstrateToolResponse, TranscriptResponse } from "./types.js";
26
+ import type { Agent, AgentEvent, AgentStatus, CancelAgentResult, ClientOptions, ContinueOptions, CreateSnapshotOptions, EnsureMcpServerOptions, EnsureMcpServerResult, HealthResponse, Hook, InterruptListResponse, InterruptStatus, AckChannelOptions, ChannelAckResult, ChannelDescriptor, ChannelPeekResult, ChannelPublishResult, ChannelSubscribeResult, CreateChannelOptions, ListChannelsResponse, PeekChannelOptions, PublishChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, SubscribeChannelOptions, UpdateChannelOptions, LibraryAgentDefinition, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, ListUsersResponse, LLMChatOptions, LLMChatResponse, LLMChatStreamItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, MCPServerDefVerifyResult, MemoryEntriesResponse, MemoryEntryResponse, MemoryScopeIDsResponse, MemoryScopesResponse, PauseResult, RegisterHookOptions, RegisterHookResponse, ResolveInterruptOptions, ResumeResult, ResolverMatrix, RunOptions, RunStateStreamItem, RuntimeStateResponse, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotRestoreResponse, StreamUserRunStatesOptions, SubstrateToolInput, SubstrateToolResponse, TranscriptResponse, WhoamiResponse } from "./types.js";
27
27
  export declare class LoomcycleClient {
28
28
  private ctx;
29
29
  constructor(opts?: ClientOptions);
@@ -89,6 +89,9 @@ export declare class LoomcycleClient {
89
89
  listUserAgents(userId: string, opts?: {
90
90
  status?: AgentStatus;
91
91
  parentAgentId?: string;
92
+ /** Super-admin tenant-focus (?tenant=, RFC L v0.17.0). Ignored
93
+ * server-side for a tenant principal — its own tenant is forced. */
94
+ tenant?: string;
92
95
  signal?: AbortSignal;
93
96
  }): Promise<Agent[]>;
94
97
  /** Read the full event log for a session. Each entry has seq,
@@ -101,11 +104,21 @@ export declare class LoomcycleClient {
101
104
  health(opts?: {
102
105
  signal?: AbortSignal;
103
106
  }): Promise<HealthResponse>;
104
- /** Admin: list known users with running-count summary. Drives the
105
- * Web UI's user picker; operators with bearer auth can call too. */
107
+ /** List known users with running-count summary. Drives the Web UI's
108
+ * user picker. Tenant-scoped server-side since v0.17.0 (RFC L): a
109
+ * tenant principal sees only its own tenant's users; an admin sees all,
110
+ * or focuses one tenant via `tenant` (?tenant=). */
106
111
  listUsers(opts?: {
112
+ tenant?: string;
107
113
  signal?: AbortSignal;
108
114
  }): Promise<ListUsersResponse>;
115
+ /** Whoami — the authenticated principal (RFC L v0.17.0). Any
116
+ * authenticated bearer; returns its authoritative tenant / subject /
117
+ * scopes + `is_admin`. `open_mode: true` when the server runs without
118
+ * the token substrate (single shared LOOMCYCLE_AUTH_TOKEN). */
119
+ whoami(opts?: {
120
+ signal?: AbortSignal;
121
+ }): Promise<WhoamiResponse>;
109
122
  /** Quiesce the runtime. Idempotent tools cancel immediately;
110
123
  * non-idempotent + external tools get a grace window then
111
124
  * force-cancel. Raises AlreadyPausingError on 409,
@@ -123,6 +136,14 @@ export declare class LoomcycleClient {
123
136
  getRuntimeState(opts?: {
124
137
  signal?: AbortSignal;
125
138
  }): Promise<RuntimeStateResponse>;
139
+ /** Trigger an immediate re-probe of every configured provider and
140
+ * return the refreshed availability matrix. Operator-only escape
141
+ * hatch when a transient outage stalls every provider and the
142
+ * runtime would otherwise 503 until the next periodic probe.
143
+ * Mirrors POST /v1/_resolve/probe. */
144
+ resolveProbe(opts?: {
145
+ signal?: AbortSignal;
146
+ }): Promise<ResolverMatrix>;
126
147
  /** Capture running-state into a per-section-semver JSON envelope.
127
148
  * Raises SnapshotTooLargeError on 413 when the envelope exceeds
128
149
  * LOOMCYCLE_SNAPSHOT_MAX_BYTES (default 512 MiB). */
@@ -278,8 +299,10 @@ export declare class LoomcycleClient {
278
299
  * Hard constraints (substrate refuses these):
279
300
  * - Transport must be `http` or `streamable-http` (stdio stays
280
301
  * yaml-only — dynamic registration doesn't allow process spawn).
281
- * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (SSRF
282
- * defence at the registration boundary).
302
+ * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
303
+ * v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
304
+ * a self-hosted loopback callback like `http://localhost:3000/api/mcp`
305
+ * belongs (SSRF defence at the registration boundary).
283
306
  * - Name colliding with a static cfg.MCPServers entry is refused
284
307
  * (yaml is ground truth; use a different name).
285
308
  *
@@ -289,6 +312,29 @@ export declare class LoomcycleClient {
289
312
  mcpServerDef(input: SubstrateToolInput, opts?: {
290
313
  signal?: AbortSignal;
291
314
  }): Promise<SubstrateToolResponse>;
315
+ /** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
316
+ * hash for `name`?" `matches: true` is the no-op signal (the analog of
317
+ * the agent/skill verify-before-create dedup). Thin typed wrapper over
318
+ * {@link mcpServerDef}. */
319
+ mcpServerDefVerify(name: string, contentSha256: string, opts?: {
320
+ signal?: AbortSignal;
321
+ }): Promise<MCPServerDefVerifyResult>;
322
+ /** Register (or refresh) a dynamic MCP server idempotently — the typed
323
+ * "register-if-changed" convenience for a consumer that re-registers its
324
+ * own callback server on every startup.
325
+ *
326
+ * Runs `create` (which is content-addressed-idempotent in loomcycle
327
+ * ≥ v0.18.0 — a byte-identical re-registration is a no-op, not a new
328
+ * version) and, when {@link EnsureMcpServerOptions.rediscover} is set, a
329
+ * `tools/list` rediscover (also idempotent on unchanged tools). The
330
+ * returned {@link EnsureMcpServerResult.changed} is false when loomcycle
331
+ * deduped both — so a stable-content re-register on every boot is a clean
332
+ * no-op. Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL
333
+ * (don't resolve a per-restart token) or the content varies each boot and
334
+ * dedup can't engage. */
335
+ ensureMcpServer(opts: EnsureMcpServerOptions, callOpts?: {
336
+ signal?: AbortSignal;
337
+ }): Promise<EnsureMcpServerResult>;
292
338
  /** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
293
339
  * Author + fork + retire scheduled-run definitions at runtime.
294
340
  * Mirror of {@link LoomcycleClient.agentDef} for schedules — the
@@ -381,6 +427,13 @@ export declare class LoomcycleClient {
381
427
  memoryBackendDef(input: SubstrateToolInput, opts?: {
382
428
  signal?: AbortSignal;
383
429
  }): Promise<SubstrateToolResponse>;
430
+ /** OperatorTokenDef substrate ops (create/rotate/retire/get/list) —
431
+ * RFC L OSS multi-tenant authorization. Operator-admin only. The
432
+ * token plaintext is returned ONCE in the create/rotate response.
433
+ * Mirrors POST /v1/_operatortokendef. */
434
+ operatorTokenDef(input: SubstrateToolInput, opts?: {
435
+ signal?: AbortSignal;
436
+ }): Promise<SubstrateToolResponse>;
384
437
  /** List every agent the runtime knows about — yaml-static + dynamic
385
438
  * AgentDefs merged into one envelope per name. Each entry carries
386
439
  * `source: "static-only" | "dynamic-only" | "both"` so callers can
package/dist/client.js CHANGED
@@ -153,7 +153,12 @@ export class LoomcycleClient {
153
153
  * request); the adapter trims before returning. Useful for the
154
154
  * n8n trigger pattern "show me all sub-runs spawned by parent X." */
155
155
  async listUserAgents(userId, opts) {
156
- const q = opts?.status ? `?status=${encodeURIComponent(opts.status)}` : "";
156
+ const params = new URLSearchParams();
157
+ if (opts?.status)
158
+ params.set("status", opts.status);
159
+ if (opts?.tenant)
160
+ params.set("tenant", opts.tenant);
161
+ const q = params.toString() ? `?${params.toString()}` : "";
157
162
  const resp = await jsonFetch(this.ctx, `/v1/users/${encodeURIComponent(userId)}/agents${q}`, opts);
158
163
  const all = resp.agents ?? [];
159
164
  if (opts?.parentAgentId !== undefined && opts.parentAgentId !== "") {
@@ -171,10 +176,20 @@ export class LoomcycleClient {
171
176
  async health(opts) {
172
177
  return jsonFetch(this.ctx, "/healthz", opts);
173
178
  }
174
- /** Admin: list known users with running-count summary. Drives the
175
- * Web UI's user picker; operators with bearer auth can call too. */
179
+ /** List known users with running-count summary. Drives the Web UI's
180
+ * user picker. Tenant-scoped server-side since v0.17.0 (RFC L): a
181
+ * tenant principal sees only its own tenant's users; an admin sees all,
182
+ * or focuses one tenant via `tenant` (?tenant=). */
176
183
  async listUsers(opts) {
177
- return jsonFetch(this.ctx, "/v1/_users", opts);
184
+ const q = opts?.tenant ? `?tenant=${encodeURIComponent(opts.tenant)}` : "";
185
+ return jsonFetch(this.ctx, `/v1/_users${q}`, opts);
186
+ }
187
+ /** Whoami — the authenticated principal (RFC L v0.17.0). Any
188
+ * authenticated bearer; returns its authoritative tenant / subject /
189
+ * scopes + `is_admin`. `open_mode: true` when the server runs without
190
+ * the token substrate (single shared LOOMCYCLE_AUTH_TOKEN). */
191
+ async whoami(opts) {
192
+ return jsonFetch(this.ctx, "/v1/_me", opts);
178
193
  }
179
194
  // ---- v0.8.17/8.18 Pause / Resume / State ----
180
195
  /** Quiesce the runtime. Idempotent tools cancel immediately;
@@ -196,6 +211,14 @@ export class LoomcycleClient {
196
211
  async getRuntimeState(opts) {
197
212
  return jsonFetch(this.ctx, "/v1/_state", opts);
198
213
  }
214
+ /** Trigger an immediate re-probe of every configured provider and
215
+ * return the refreshed availability matrix. Operator-only escape
216
+ * hatch when a transient outage stalls every provider and the
217
+ * runtime would otherwise 503 until the next periodic probe.
218
+ * Mirrors POST /v1/_resolve/probe. */
219
+ async resolveProbe(opts) {
220
+ return postJSON(this.ctx, "/v1/_resolve/probe", undefined, opts);
221
+ }
199
222
  // ---- Snapshot lifecycle ----
200
223
  /** Capture running-state into a per-section-semver JSON envelope.
201
224
  * Raises SnapshotTooLargeError on 413 when the envelope exceeds
@@ -416,8 +439,10 @@ export class LoomcycleClient {
416
439
  * Hard constraints (substrate refuses these):
417
440
  * - Transport must be `http` or `streamable-http` (stdio stays
418
441
  * yaml-only — dynamic registration doesn't allow process spawn).
419
- * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (SSRF
420
- * defence at the registration boundary).
442
+ * - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
443
+ * v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
444
+ * a self-hosted loopback callback like `http://localhost:3000/api/mcp`
445
+ * belongs (SSRF defence at the registration boundary).
421
446
  * - Name colliding with a static cfg.MCPServers entry is refused
422
447
  * (yaml is ground truth; use a different name).
423
448
  *
@@ -427,6 +452,57 @@ export class LoomcycleClient {
427
452
  async mcpServerDef(input, opts) {
428
453
  return postJSON(this.ctx, "/v1/_mcpserverdef", input, opts);
429
454
  }
455
+ /** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
456
+ * hash for `name`?" `matches: true` is the no-op signal (the analog of
457
+ * the agent/skill verify-before-create dedup). Thin typed wrapper over
458
+ * {@link mcpServerDef}. */
459
+ async mcpServerDefVerify(name, contentSha256, opts) {
460
+ return (await this.mcpServerDef({ op: "verify", name, content_sha256: contentSha256 }, opts));
461
+ }
462
+ /** Register (or refresh) a dynamic MCP server idempotently — the typed
463
+ * "register-if-changed" convenience for a consumer that re-registers its
464
+ * own callback server on every startup.
465
+ *
466
+ * Runs `create` (which is content-addressed-idempotent in loomcycle
467
+ * ≥ v0.18.0 — a byte-identical re-registration is a no-op, not a new
468
+ * version) and, when {@link EnsureMcpServerOptions.rediscover} is set, a
469
+ * `tools/list` rediscover (also idempotent on unchanged tools). The
470
+ * returned {@link EnsureMcpServerResult.changed} is false when loomcycle
471
+ * deduped both — so a stable-content re-register on every boot is a clean
472
+ * no-op. Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL
473
+ * (don't resolve a per-restart token) or the content varies each boot and
474
+ * dedup can't engage. */
475
+ async ensureMcpServer(opts, callOpts) {
476
+ const overlay = {
477
+ transport: opts.transport ?? "http",
478
+ url: opts.url,
479
+ };
480
+ if (opts.headers)
481
+ overlay.headers = opts.headers;
482
+ const createInput = { op: "create", name: opts.name, overlay };
483
+ if (opts.description)
484
+ createInput.description = opts.description;
485
+ const created = (await this.mcpServerDef(createInput, callOpts));
486
+ let row = created;
487
+ let changed = created.deduplicated !== true;
488
+ let discoveredToolCount;
489
+ if (opts.rediscover) {
490
+ const red = (await this.mcpServerDef({ op: "rediscover", name: opts.name }, callOpts));
491
+ row = red;
492
+ if (red.deduplicated !== true)
493
+ changed = true;
494
+ discoveredToolCount = red.discovered;
495
+ }
496
+ const result = {
497
+ name: opts.name,
498
+ defId: row.def_id,
499
+ version: row.version,
500
+ changed,
501
+ };
502
+ if (discoveredToolCount !== undefined)
503
+ result.discoveredToolCount = discoveredToolCount;
504
+ return result;
505
+ }
430
506
  /** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
431
507
  * Author + fork + retire scheduled-run definitions at runtime.
432
508
  * Mirror of {@link LoomcycleClient.agentDef} for schedules — the
@@ -519,6 +595,13 @@ export class LoomcycleClient {
519
595
  async memoryBackendDef(input, opts) {
520
596
  return postJSON(this.ctx, "/v1/_memorybackenddef", input, opts);
521
597
  }
598
+ /** OperatorTokenDef substrate ops (create/rotate/retire/get/list) —
599
+ * RFC L OSS multi-tenant authorization. Operator-admin only. The
600
+ * token plaintext is returned ONCE in the create/rotate response.
601
+ * Mirrors POST /v1/_operatortokendef. */
602
+ async operatorTokenDef(input, opts) {
603
+ return postJSON(this.ctx, "/v1/_operatortokendef", input, opts);
604
+ }
522
605
  // ---- v0.10.3 Library v2 enumeration (read-only, merged yaml+substrate) ----
523
606
  /** List every agent the runtime knows about — yaml-static + dynamic
524
607
  * AgentDefs merged into one envelope per name. Each entry carries
package/dist/index.d.ts CHANGED
@@ -16,12 +16,14 @@
16
16
  * listUserAgents(userId, opts?): Promise<Agent[]>
17
17
  * getTranscript(sessionId): Promise<TranscriptResponse>
18
18
  * health(): Promise<HealthResponse>
19
- * listUsers(): Promise<ListUsersResponse>
19
+ * listUsers(opts?): Promise<ListUsersResponse> // tenant-scoped (RFC L)
20
+ * whoami(): Promise<WhoamiResponse> // RFC L principal (v0.17.0)
20
21
  *
21
22
  * // Pause / Resume / State (v0.8.17/8.18)
22
23
  * pauseRuntime(opts?): Promise<PauseResult>
23
24
  * resumeRuntime(): Promise<ResumeResult>
24
25
  * getRuntimeState(): Promise<RuntimeStateResponse>
26
+ * resolveProbe(opts?): Promise<ResolverMatrix>
25
27
  *
26
28
  * // Snapshot lifecycle (v0.8.17/8.18)
27
29
  * createSnapshot(opts?): Promise<SnapshotCreateResponse>
@@ -46,6 +48,8 @@
46
48
  * agentDef(input): Promise<SubstrateToolResponse>
47
49
  * skillDef(input): Promise<SubstrateToolResponse>
48
50
  * mcpServerDef(input): Promise<SubstrateToolResponse>
51
+ * mcpServerDefVerify(name, sha): Promise<MCPServerDefVerifyResult> // v0.18.0
52
+ * ensureMcpServer(opts): Promise<EnsureMcpServerResult> // v0.18.0 — idempotent register-if-changed
49
53
  * scheduleDef(input): Promise<SubstrateToolResponse>
50
54
  *
51
55
  * // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
@@ -78,5 +82,5 @@
78
82
  * See `adapters/ts/README.md` for usage examples.
79
83
  */
80
84
  export { LoomcycleClient } from "./client.js";
81
- export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, ParentContext, 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, CreateChannelOptions, UpdateChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, } from "./types.js";
85
+ export type { AgentEvent, ClientOptions, ContinueOptions, EventType, HostWidening, ParentContext, PromptContent, PromptSegment, RetryInfo, RunOptions, ToolUse, Usage, Agent, AgentStatus, AgentUsage, CancelAgentResult, ListAgentsResponse, TranscriptEvent, TranscriptResponse, HealthResponse, ListUsersResponse, UserSummary, WhoamiResponse, PauseResult, ResumeResult, RuntimeStateResponse, RuntimeStateStatus, ResolverMatrix, ResolverModelStatus, ResolverProviderAvailability, 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, CreateChannelOptions, UpdateChannelOptions, SetMemoryEntryOptions, SetMemoryEntryResponse, AgentDefRowResponse, AgentDefVerifyResult, SkillDefVerifyResult, EnsureMcpServerOptions, EnsureMcpServerResult, MCPServerDefRowResponse, MCPServerDefVerifyResult, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, } from "./types.js";
82
86
  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
@@ -16,12 +16,14 @@
16
16
  * listUserAgents(userId, opts?): Promise<Agent[]>
17
17
  * getTranscript(sessionId): Promise<TranscriptResponse>
18
18
  * health(): Promise<HealthResponse>
19
- * listUsers(): Promise<ListUsersResponse>
19
+ * listUsers(opts?): Promise<ListUsersResponse> // tenant-scoped (RFC L)
20
+ * whoami(): Promise<WhoamiResponse> // RFC L principal (v0.17.0)
20
21
  *
21
22
  * // Pause / Resume / State (v0.8.17/8.18)
22
23
  * pauseRuntime(opts?): Promise<PauseResult>
23
24
  * resumeRuntime(): Promise<ResumeResult>
24
25
  * getRuntimeState(): Promise<RuntimeStateResponse>
26
+ * resolveProbe(opts?): Promise<ResolverMatrix>
25
27
  *
26
28
  * // Snapshot lifecycle (v0.8.17/8.18)
27
29
  * createSnapshot(opts?): Promise<SnapshotCreateResponse>
@@ -46,6 +48,8 @@
46
48
  * agentDef(input): Promise<SubstrateToolResponse>
47
49
  * skillDef(input): Promise<SubstrateToolResponse>
48
50
  * mcpServerDef(input): Promise<SubstrateToolResponse>
51
+ * mcpServerDefVerify(name, sha): Promise<MCPServerDefVerifyResult> // v0.18.0
52
+ * ensureMcpServer(opts): Promise<EnsureMcpServerResult> // v0.18.0 — idempotent register-if-changed
49
53
  * scheduleDef(input): Promise<SubstrateToolResponse>
50
54
  *
51
55
  * // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
package/dist/types.d.ts CHANGED
@@ -336,6 +336,18 @@ export interface UserSummary {
336
336
  export interface ListUsersResponse {
337
337
  users: UserSummary[];
338
338
  }
339
+ /** GET /v1/_me — the authenticated principal resolved from the bearer.
340
+ * `open_mode` is true when the server runs without the OperatorTokenDef
341
+ * substrate (single shared LOOMCYCLE_AUTH_TOKEN); `legacy` is true for a
342
+ * shared-token principal when the substrate IS enabled. */
343
+ export interface WhoamiResponse {
344
+ tenant_id: string;
345
+ subject: string;
346
+ scopes: string[];
347
+ is_admin: boolean;
348
+ legacy: boolean;
349
+ open_mode?: boolean;
350
+ }
339
351
  export type RuntimeStateStatus = "running" | "pausing" | "paused";
340
352
  export interface PauseResult {
341
353
  state: string;
@@ -353,6 +365,25 @@ export interface RuntimeStateResponse {
353
365
  state: RuntimeStateStatus;
354
366
  paused_runs_count: number;
355
367
  }
368
+ export interface ResolverModelStatus {
369
+ listed: boolean;
370
+ stalled: boolean;
371
+ }
372
+ export interface ResolverProviderAvailability {
373
+ excluded: boolean;
374
+ reachable: boolean;
375
+ models: Record<string, ResolverModelStatus>;
376
+ /** RFC3339 timestamp of the last probe for this provider. */
377
+ last_check: string;
378
+ last_error?: string;
379
+ }
380
+ /** The resolver availability matrix, captured right after a forced
381
+ * re-probe. Same shape as GET /v1/_resolver. */
382
+ export interface ResolverMatrix {
383
+ /** RFC3339 timestamp when this matrix snapshot was assembled. */
384
+ generated_at: string;
385
+ providers: Record<string, ResolverProviderAvailability>;
386
+ }
356
387
  export interface SnapshotDescriptor {
357
388
  id: string;
358
389
  created_at: string;
@@ -576,7 +607,7 @@ export interface PostHookCall {
576
607
  * the adapter doesn't re-validate. Use the optional `extra` index
577
608
  * signature for forward-compat fields. */
578
609
  export type SubstrateToolInput = {
579
- op: "create" | "fork" | "get" | "list" | "promote" | "retire";
610
+ op: "create" | "fork" | "get" | "list" | "promote" | "retire" | "rediscover" | "verify";
580
611
  name?: string;
581
612
  def_id?: string;
582
613
  parent_def_id?: string;
@@ -907,6 +938,43 @@ export interface MCPServerDefRowResponse {
907
938
  content_sha256?: string;
908
939
  /** Only populated on `set` / `fork` responses (auto-promoted?). */
909
940
  promoted?: boolean;
941
+ /** True when create/rediscover was a content-addressed no-op
942
+ * (loomcycle ≥ v0.18.0): the active def already carried identical
943
+ * content (create) or identical discovered_tools (rediscover), so no
944
+ * new version was minted. Absent (undefined) on a real mint. */
945
+ deduplicated?: boolean;
946
+ /** Only on `rediscover` responses — the number of tools discovered. */
947
+ discovered?: number;
948
+ }
949
+ /** Options for {@link LoomcycleClient.ensureMcpServer}. */
950
+ export interface EnsureMcpServerOptions {
951
+ /** Substrate name (not a static cfg.MCPServers name). */
952
+ name: string;
953
+ /** Absolute MCP endpoint, e.g. `http://localhost:3000/api/mcp`. */
954
+ url: string;
955
+ /** Default `"http"`. */
956
+ transport?: "http" | "streamable-http";
957
+ /** Per-request headers, stored verbatim. Keep `${run.*}` / `${LOOMCYCLE_*}`
958
+ * substitution placeholders LITERAL (don't resolve a token yourself) so
959
+ * the registration content is stable across restarts — that's what lets
960
+ * loomcycle's idempotent create dedup the re-registration. */
961
+ headers?: Record<string, string>;
962
+ description?: string;
963
+ /** Run a `tools/list` rediscover after registering. Default false. */
964
+ rediscover?: boolean;
965
+ }
966
+ /** Result of {@link LoomcycleClient.ensureMcpServer}. */
967
+ export interface EnsureMcpServerResult {
968
+ name: string;
969
+ defId: string;
970
+ version: number;
971
+ /** True when this call minted a new version (create and/or rediscover);
972
+ * false when loomcycle deduped it (active def already current). A
973
+ * consumer re-registering on every boot expects `changed: false` once
974
+ * the registration content is stable. */
975
+ changed: boolean;
976
+ /** Populated when `rediscover` ran: the number of tools discovered. */
977
+ discoveredToolCount?: number;
910
978
  }
911
979
  /** Response shape for `MCPServerDef verify`. Same semantics as
912
980
  * AgentDefVerifyResult / SkillDefVerifyResult — answers "is the
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loomcycle/client",
3
- "version": "0.15.0",
4
- "description": "TypeScript client for the loomcycle sidecar (HTTP+SSE). 46 methods covering run streaming, agent metadata, pause/resume/state, snapshot lifecycle, memory admin (incl. v0.9.0 Vector Memory embed_stats + reembed AND v0.11.5 setMemoryEntry + deleteMemoryEntry), interruption resolve, hook management, v0.8.22 substrate admin (agentDef + skillDef), v0.9.x n8n Phase 0 (listChannels + streamUserRunStates), v0.9.x Channel CRUD (publishChannel + subscribeChannel + peekChannel + ackChannel), v0.11.5 Channel admin CRUD (createChannel + updateChannel + deleteChannel — runtime substrate; yaml channels refuse mutation with HTTP 409), v0.9.x content_sha256 verify, v0.9.1 transcript first-cycle, v0.9.x dynamic MCP server registration (mcpServerDef + MCPServerDefVerifyResult), v0.10.3 Library v2 enumeration (listLibraryAgents + listLibrarySkills + listLibraryMcpServers), and v0.11.0 LLM Gateway (llmChat + llmStream — direct provider routing without agent overhead; primary target is n8n's LoomCycleChatModel AI Agent sub-node and any LangChain-compatible consumer). v0.10.1 — dual ESM + CommonJS distribution (additive — ESM consumers unchanged; CJS consumers like n8n's community-node loader now work).",
3
+ "version": "0.18.0",
4
+ "description": "TypeScript client for the loomcycle sidecar (HTTP+SSE). 51 methods covering run streaming, agent metadata, pause/resume/state, resolver re-probe (resolveProbe — issue #88 operator escape hatch), operator-token admin (operatorTokenDef — RFC L OSS multi-tenant auth) + whoami (RFC L authoritative principal, v0.17.0) + tenant-scoped listUsers / listUserAgents, dynamic MCP registration (mcpServerDef + v0.18.0 typed mcpServerDefVerify + ensureMcpServer idempotent register-if-changed), snapshot lifecycle, memory admin (incl. v0.9.0 Vector Memory embed_stats + reembed AND v0.11.5 setMemoryEntry + deleteMemoryEntry), interruption resolve, hook management, v0.8.22 substrate admin (agentDef + skillDef), v0.9.x n8n Phase 0 (listChannels + streamUserRunStates), v0.9.x Channel CRUD (publishChannel + subscribeChannel + peekChannel + ackChannel), v0.11.5 Channel admin CRUD (createChannel + updateChannel + deleteChannel — runtime substrate; yaml channels refuse mutation with HTTP 409), v0.9.x content_sha256 verify, v0.9.1 transcript first-cycle, v0.9.x dynamic MCP server registration (mcpServerDef + MCPServerDefVerifyResult), v0.10.3 Library v2 enumeration (listLibraryAgents + listLibrarySkills + listLibraryMcpServers), and v0.11.0 LLM Gateway (llmChat + llmStream — direct provider routing without agent overhead; primary target is n8n's LoomCycleChatModel AI Agent sub-node and any LangChain-compatible consumer). 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": {