@loomcycle/client 0.17.0 → 0.20.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 +2 -1
- package/dist/cjs/client.js +98 -2
- package/dist/cjs/index.js +2 -0
- package/dist/client.d.ts +53 -3
- package/dist/client.js +98 -2
- package/dist/index.d.ts +3 -1
- package/dist/index.js +2 -0
- package/dist/types.d.ts +112 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -6,12 +6,13 @@ TypeScript client for the [loomcycle](https://github.com/denn-gubsky/loomcycle)
|
|
|
6
6
|
|
|
7
7
|
## Status
|
|
8
8
|
|
|
9
|
-
**v0.
|
|
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).
|
|
15
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).
|
|
16
17
|
|
|
17
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.
|
package/dist/cjs/client.js
CHANGED
|
@@ -418,6 +418,41 @@ class LoomcycleClient {
|
|
|
418
418
|
async agentDef(input, opts) {
|
|
419
419
|
return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_agentdef", input, opts);
|
|
420
420
|
}
|
|
421
|
+
/** Register (or refresh) a code-js agent idempotently from an INLINE JS body
|
|
422
|
+
* — the typed "ship a code agent with no host filesystem" convenience
|
|
423
|
+
* (RFC J), mirror of {@link LoomcycleClient.ensureMcpServer}.
|
|
424
|
+
*
|
|
425
|
+
* Runs `agentDef({op:"create", overlay:{provider:"code-js", code_body, …}})`,
|
|
426
|
+
* which is content-addressed-idempotent in loomcycle: a byte-identical
|
|
427
|
+
* re-registration is a no-op (`changed:false`), not a new version. This is
|
|
428
|
+
* what makes code agents work across container boundaries / pure-cloud —
|
|
429
|
+
* the JS no longer has to exist at `agent_code/<name>/index.js` on the
|
|
430
|
+
* sidecar's disk.
|
|
431
|
+
*
|
|
432
|
+
* Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the sidecar — the same
|
|
433
|
+
* switch that registers the code-js provider. Without it the create is
|
|
434
|
+
* refused (raises {@link SubstrateToolRefusedError}). Keep `${run.*}` /
|
|
435
|
+
* `${LOOMCYCLE_*}` placeholders in the body LITERAL so the content stays
|
|
436
|
+
* stable and dedup engages on re-register. */
|
|
437
|
+
async ensureCodeAgent(opts, callOpts) {
|
|
438
|
+
const overlay = { provider: "code-js", code_body: opts.code };
|
|
439
|
+
if (opts.allowedTools)
|
|
440
|
+
overlay.allowed_tools = opts.allowedTools;
|
|
441
|
+
if (opts.tier)
|
|
442
|
+
overlay.tier = opts.tier;
|
|
443
|
+
if (opts.model)
|
|
444
|
+
overlay.model = opts.model;
|
|
445
|
+
const input = { op: "create", name: opts.name, overlay };
|
|
446
|
+
if (opts.description)
|
|
447
|
+
input.description = opts.description;
|
|
448
|
+
const row = (await this.agentDef(input, callOpts));
|
|
449
|
+
return {
|
|
450
|
+
name: opts.name,
|
|
451
|
+
defId: row.def_id,
|
|
452
|
+
version: row.version,
|
|
453
|
+
changed: row.deduplicated !== true,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
421
456
|
/** Invoke the SkillDef substrate tool over HTTP. Mirror of
|
|
422
457
|
* {@link LoomcycleClient.agentDef} for skills (v0.8.22+). Same
|
|
423
458
|
* input grammar, same error class on refusal. See the
|
|
@@ -442,8 +477,10 @@ class LoomcycleClient {
|
|
|
442
477
|
* Hard constraints (substrate refuses these):
|
|
443
478
|
* - Transport must be `http` or `streamable-http` (stdio stays
|
|
444
479
|
* yaml-only — dynamic registration doesn't allow process spawn).
|
|
445
|
-
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (
|
|
446
|
-
*
|
|
480
|
+
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
|
|
481
|
+
* v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
|
|
482
|
+
* a self-hosted loopback callback like `http://localhost:3000/api/mcp`
|
|
483
|
+
* belongs (SSRF defence at the registration boundary).
|
|
447
484
|
* - Name colliding with a static cfg.MCPServers entry is refused
|
|
448
485
|
* (yaml is ground truth; use a different name).
|
|
449
486
|
*
|
|
@@ -453,6 +490,65 @@ class LoomcycleClient {
|
|
|
453
490
|
async mcpServerDef(input, opts) {
|
|
454
491
|
return (0, fetch_helpers_js_1.postJSON)(this.ctx, "/v1/_mcpserverdef", input, opts);
|
|
455
492
|
}
|
|
493
|
+
/** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
|
|
494
|
+
* hash for `name`?" `matches: true` is the no-op signal (the analog of
|
|
495
|
+
* the agent/skill verify-before-create dedup). Thin typed wrapper over
|
|
496
|
+
* {@link mcpServerDef}. */
|
|
497
|
+
async mcpServerDefVerify(name, contentSha256, opts) {
|
|
498
|
+
return (await this.mcpServerDef({ op: "verify", name, content_sha256: contentSha256 }, opts));
|
|
499
|
+
}
|
|
500
|
+
/** Register (or refresh) a dynamic MCP server idempotently — the typed
|
|
501
|
+
* "register-if-changed" convenience for a consumer that re-registers its
|
|
502
|
+
* own callback server on every startup.
|
|
503
|
+
*
|
|
504
|
+
* Runs `create`, which is content-addressed-idempotent (a byte-identical
|
|
505
|
+
* re-registration is a no-op, not a new version) AND auto-discovers the
|
|
506
|
+
* upstream's tools at ingestion — so {@link EnsureMcpServerResult.changed}
|
|
507
|
+
* is false on a stable-content re-register, and
|
|
508
|
+
* {@link EnsureMcpServerResult.discoveredToolCount} is populated straight
|
|
509
|
+
* from the `create` (no separate rediscover needed for the count). On a
|
|
510
|
+
* deduplicated re-register the count is absent (the tool surface was
|
|
511
|
+
* unchanged), so it reflects only the freshly-discovered case.
|
|
512
|
+
*
|
|
513
|
+
* Pass {@link EnsureMcpServerOptions.rediscover} only to FORCE a refresh
|
|
514
|
+
* when the upstream's tools changed but the registration content didn't.
|
|
515
|
+
*
|
|
516
|
+
* Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL (don't
|
|
517
|
+
* resolve a per-restart token) or the content varies each boot and dedup
|
|
518
|
+
* can't engage. */
|
|
519
|
+
async ensureMcpServer(opts, callOpts) {
|
|
520
|
+
const overlay = {
|
|
521
|
+
transport: opts.transport ?? "http",
|
|
522
|
+
url: opts.url,
|
|
523
|
+
};
|
|
524
|
+
if (opts.headers)
|
|
525
|
+
overlay.headers = opts.headers;
|
|
526
|
+
const createInput = { op: "create", name: opts.name, overlay };
|
|
527
|
+
if (opts.description)
|
|
528
|
+
createInput.description = opts.description;
|
|
529
|
+
const created = (await this.mcpServerDef(createInput, callOpts));
|
|
530
|
+
let row = created;
|
|
531
|
+
let changed = created.deduplicated !== true;
|
|
532
|
+
// create auto-discovers at ingestion → the count is on the create response.
|
|
533
|
+
let discoveredToolCount = created.discovered;
|
|
534
|
+
if (opts.rediscover) {
|
|
535
|
+
const red = (await this.mcpServerDef({ op: "rediscover", name: opts.name }, callOpts));
|
|
536
|
+
row = red;
|
|
537
|
+
if (red.deduplicated !== true)
|
|
538
|
+
changed = true;
|
|
539
|
+
if (red.discovered !== undefined)
|
|
540
|
+
discoveredToolCount = red.discovered;
|
|
541
|
+
}
|
|
542
|
+
const result = {
|
|
543
|
+
name: opts.name,
|
|
544
|
+
defId: row.def_id,
|
|
545
|
+
version: row.version,
|
|
546
|
+
changed,
|
|
547
|
+
};
|
|
548
|
+
if (discoveredToolCount !== undefined)
|
|
549
|
+
result.discoveredToolCount = discoveredToolCount;
|
|
550
|
+
return result;
|
|
551
|
+
}
|
|
456
552
|
/** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
|
|
457
553
|
* Author + fork + retire scheduled-run definitions at runtime.
|
|
458
554
|
* Mirror of {@link LoomcycleClient.agentDef} for schedules — the
|
package/dist/cjs/index.js
CHANGED
|
@@ -49,6 +49,8 @@
|
|
|
49
49
|
* agentDef(input): Promise<SubstrateToolResponse>
|
|
50
50
|
* skillDef(input): Promise<SubstrateToolResponse>
|
|
51
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
|
|
52
54
|
* scheduleDef(input): Promise<SubstrateToolResponse>
|
|
53
55
|
*
|
|
54
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, ResolverMatrix, RunOptions, RunStateStreamItem, RuntimeStateResponse, SnapshotCreateResponse, SnapshotDescriptor, SnapshotEnvelope, SnapshotRestoreResponse, StreamUserRunStatesOptions, SubstrateToolInput, SubstrateToolResponse, TranscriptResponse, WhoamiResponse } from "./types.js";
|
|
26
|
+
import type { Agent, AgentEvent, AgentStatus, CancelAgentResult, ClientOptions, ContinueOptions, CreateSnapshotOptions, EnsureCodeAgentOptions, EnsureCodeAgentResult, 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);
|
|
@@ -275,6 +275,25 @@ export declare class LoomcycleClient {
|
|
|
275
275
|
agentDef(input: SubstrateToolInput, opts?: {
|
|
276
276
|
signal?: AbortSignal;
|
|
277
277
|
}): Promise<SubstrateToolResponse>;
|
|
278
|
+
/** Register (or refresh) a code-js agent idempotently from an INLINE JS body
|
|
279
|
+
* — the typed "ship a code agent with no host filesystem" convenience
|
|
280
|
+
* (RFC J), mirror of {@link LoomcycleClient.ensureMcpServer}.
|
|
281
|
+
*
|
|
282
|
+
* Runs `agentDef({op:"create", overlay:{provider:"code-js", code_body, …}})`,
|
|
283
|
+
* which is content-addressed-idempotent in loomcycle: a byte-identical
|
|
284
|
+
* re-registration is a no-op (`changed:false`), not a new version. This is
|
|
285
|
+
* what makes code agents work across container boundaries / pure-cloud —
|
|
286
|
+
* the JS no longer has to exist at `agent_code/<name>/index.js` on the
|
|
287
|
+
* sidecar's disk.
|
|
288
|
+
*
|
|
289
|
+
* Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the sidecar — the same
|
|
290
|
+
* switch that registers the code-js provider. Without it the create is
|
|
291
|
+
* refused (raises {@link SubstrateToolRefusedError}). Keep `${run.*}` /
|
|
292
|
+
* `${LOOMCYCLE_*}` placeholders in the body LITERAL so the content stays
|
|
293
|
+
* stable and dedup engages on re-register. */
|
|
294
|
+
ensureCodeAgent(opts: EnsureCodeAgentOptions, callOpts?: {
|
|
295
|
+
signal?: AbortSignal;
|
|
296
|
+
}): Promise<EnsureCodeAgentResult>;
|
|
278
297
|
/** Invoke the SkillDef substrate tool over HTTP. Mirror of
|
|
279
298
|
* {@link LoomcycleClient.agentDef} for skills (v0.8.22+). Same
|
|
280
299
|
* input grammar, same error class on refusal. See the
|
|
@@ -299,8 +318,10 @@ export declare class LoomcycleClient {
|
|
|
299
318
|
* Hard constraints (substrate refuses these):
|
|
300
319
|
* - Transport must be `http` or `streamable-http` (stdio stays
|
|
301
320
|
* yaml-only — dynamic registration doesn't allow process spawn).
|
|
302
|
-
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (
|
|
303
|
-
*
|
|
321
|
+
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
|
|
322
|
+
* v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
|
|
323
|
+
* a self-hosted loopback callback like `http://localhost:3000/api/mcp`
|
|
324
|
+
* belongs (SSRF defence at the registration boundary).
|
|
304
325
|
* - Name colliding with a static cfg.MCPServers entry is refused
|
|
305
326
|
* (yaml is ground truth; use a different name).
|
|
306
327
|
*
|
|
@@ -310,6 +331,35 @@ export declare class LoomcycleClient {
|
|
|
310
331
|
mcpServerDef(input: SubstrateToolInput, opts?: {
|
|
311
332
|
signal?: AbortSignal;
|
|
312
333
|
}): Promise<SubstrateToolResponse>;
|
|
334
|
+
/** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
|
|
335
|
+
* hash for `name`?" `matches: true` is the no-op signal (the analog of
|
|
336
|
+
* the agent/skill verify-before-create dedup). Thin typed wrapper over
|
|
337
|
+
* {@link mcpServerDef}. */
|
|
338
|
+
mcpServerDefVerify(name: string, contentSha256: string, opts?: {
|
|
339
|
+
signal?: AbortSignal;
|
|
340
|
+
}): Promise<MCPServerDefVerifyResult>;
|
|
341
|
+
/** Register (or refresh) a dynamic MCP server idempotently — the typed
|
|
342
|
+
* "register-if-changed" convenience for a consumer that re-registers its
|
|
343
|
+
* own callback server on every startup.
|
|
344
|
+
*
|
|
345
|
+
* Runs `create`, which is content-addressed-idempotent (a byte-identical
|
|
346
|
+
* re-registration is a no-op, not a new version) AND auto-discovers the
|
|
347
|
+
* upstream's tools at ingestion — so {@link EnsureMcpServerResult.changed}
|
|
348
|
+
* is false on a stable-content re-register, and
|
|
349
|
+
* {@link EnsureMcpServerResult.discoveredToolCount} is populated straight
|
|
350
|
+
* from the `create` (no separate rediscover needed for the count). On a
|
|
351
|
+
* deduplicated re-register the count is absent (the tool surface was
|
|
352
|
+
* unchanged), so it reflects only the freshly-discovered case.
|
|
353
|
+
*
|
|
354
|
+
* Pass {@link EnsureMcpServerOptions.rediscover} only to FORCE a refresh
|
|
355
|
+
* when the upstream's tools changed but the registration content didn't.
|
|
356
|
+
*
|
|
357
|
+
* Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL (don't
|
|
358
|
+
* resolve a per-restart token) or the content varies each boot and dedup
|
|
359
|
+
* can't engage. */
|
|
360
|
+
ensureMcpServer(opts: EnsureMcpServerOptions, callOpts?: {
|
|
361
|
+
signal?: AbortSignal;
|
|
362
|
+
}): Promise<EnsureMcpServerResult>;
|
|
313
363
|
/** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
|
|
314
364
|
* Author + fork + retire scheduled-run definitions at runtime.
|
|
315
365
|
* Mirror of {@link LoomcycleClient.agentDef} for schedules — the
|
package/dist/client.js
CHANGED
|
@@ -415,6 +415,41 @@ export class LoomcycleClient {
|
|
|
415
415
|
async agentDef(input, opts) {
|
|
416
416
|
return postJSON(this.ctx, "/v1/_agentdef", input, opts);
|
|
417
417
|
}
|
|
418
|
+
/** Register (or refresh) a code-js agent idempotently from an INLINE JS body
|
|
419
|
+
* — the typed "ship a code agent with no host filesystem" convenience
|
|
420
|
+
* (RFC J), mirror of {@link LoomcycleClient.ensureMcpServer}.
|
|
421
|
+
*
|
|
422
|
+
* Runs `agentDef({op:"create", overlay:{provider:"code-js", code_body, …}})`,
|
|
423
|
+
* which is content-addressed-idempotent in loomcycle: a byte-identical
|
|
424
|
+
* re-registration is a no-op (`changed:false`), not a new version. This is
|
|
425
|
+
* what makes code agents work across container boundaries / pure-cloud —
|
|
426
|
+
* the JS no longer has to exist at `agent_code/<name>/index.js` on the
|
|
427
|
+
* sidecar's disk.
|
|
428
|
+
*
|
|
429
|
+
* Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the sidecar — the same
|
|
430
|
+
* switch that registers the code-js provider. Without it the create is
|
|
431
|
+
* refused (raises {@link SubstrateToolRefusedError}). Keep `${run.*}` /
|
|
432
|
+
* `${LOOMCYCLE_*}` placeholders in the body LITERAL so the content stays
|
|
433
|
+
* stable and dedup engages on re-register. */
|
|
434
|
+
async ensureCodeAgent(opts, callOpts) {
|
|
435
|
+
const overlay = { provider: "code-js", code_body: opts.code };
|
|
436
|
+
if (opts.allowedTools)
|
|
437
|
+
overlay.allowed_tools = opts.allowedTools;
|
|
438
|
+
if (opts.tier)
|
|
439
|
+
overlay.tier = opts.tier;
|
|
440
|
+
if (opts.model)
|
|
441
|
+
overlay.model = opts.model;
|
|
442
|
+
const input = { op: "create", name: opts.name, overlay };
|
|
443
|
+
if (opts.description)
|
|
444
|
+
input.description = opts.description;
|
|
445
|
+
const row = (await this.agentDef(input, callOpts));
|
|
446
|
+
return {
|
|
447
|
+
name: opts.name,
|
|
448
|
+
defId: row.def_id,
|
|
449
|
+
version: row.version,
|
|
450
|
+
changed: row.deduplicated !== true,
|
|
451
|
+
};
|
|
452
|
+
}
|
|
418
453
|
/** Invoke the SkillDef substrate tool over HTTP. Mirror of
|
|
419
454
|
* {@link LoomcycleClient.agentDef} for skills (v0.8.22+). Same
|
|
420
455
|
* input grammar, same error class on refusal. See the
|
|
@@ -439,8 +474,10 @@ export class LoomcycleClient {
|
|
|
439
474
|
* Hard constraints (substrate refuses these):
|
|
440
475
|
* - Transport must be `http` or `streamable-http` (stdio stays
|
|
441
476
|
* yaml-only — dynamic registration doesn't allow process spawn).
|
|
442
|
-
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST (
|
|
443
|
-
*
|
|
477
|
+
* - URL hostname must be in LOOMCYCLE_HTTP_HOST_ALLOWLIST or (since
|
|
478
|
+
* v0.17.x) LOOMCYCLE_HTTP_PRIVATE_HOST_ALLOWLIST — the latter is where
|
|
479
|
+
* a self-hosted loopback callback like `http://localhost:3000/api/mcp`
|
|
480
|
+
* belongs (SSRF defence at the registration boundary).
|
|
444
481
|
* - Name colliding with a static cfg.MCPServers entry is refused
|
|
445
482
|
* (yaml is ground truth; use a different name).
|
|
446
483
|
*
|
|
@@ -450,6 +487,65 @@ export class LoomcycleClient {
|
|
|
450
487
|
async mcpServerDef(input, opts) {
|
|
451
488
|
return postJSON(this.ctx, "/v1/_mcpserverdef", input, opts);
|
|
452
489
|
}
|
|
490
|
+
/** Typed `MCPServerDef verify` — "is `contentSha256` the active version's
|
|
491
|
+
* hash for `name`?" `matches: true` is the no-op signal (the analog of
|
|
492
|
+
* the agent/skill verify-before-create dedup). Thin typed wrapper over
|
|
493
|
+
* {@link mcpServerDef}. */
|
|
494
|
+
async mcpServerDefVerify(name, contentSha256, opts) {
|
|
495
|
+
return (await this.mcpServerDef({ op: "verify", name, content_sha256: contentSha256 }, opts));
|
|
496
|
+
}
|
|
497
|
+
/** Register (or refresh) a dynamic MCP server idempotently — the typed
|
|
498
|
+
* "register-if-changed" convenience for a consumer that re-registers its
|
|
499
|
+
* own callback server on every startup.
|
|
500
|
+
*
|
|
501
|
+
* Runs `create`, which is content-addressed-idempotent (a byte-identical
|
|
502
|
+
* re-registration is a no-op, not a new version) AND auto-discovers the
|
|
503
|
+
* upstream's tools at ingestion — so {@link EnsureMcpServerResult.changed}
|
|
504
|
+
* is false on a stable-content re-register, and
|
|
505
|
+
* {@link EnsureMcpServerResult.discoveredToolCount} is populated straight
|
|
506
|
+
* from the `create` (no separate rediscover needed for the count). On a
|
|
507
|
+
* deduplicated re-register the count is absent (the tool surface was
|
|
508
|
+
* unchanged), so it reflects only the freshly-discovered case.
|
|
509
|
+
*
|
|
510
|
+
* Pass {@link EnsureMcpServerOptions.rediscover} only to FORCE a refresh
|
|
511
|
+
* when the upstream's tools changed but the registration content didn't.
|
|
512
|
+
*
|
|
513
|
+
* Keep `${run.*}` / `${LOOMCYCLE_*}` header placeholders LITERAL (don't
|
|
514
|
+
* resolve a per-restart token) or the content varies each boot and dedup
|
|
515
|
+
* can't engage. */
|
|
516
|
+
async ensureMcpServer(opts, callOpts) {
|
|
517
|
+
const overlay = {
|
|
518
|
+
transport: opts.transport ?? "http",
|
|
519
|
+
url: opts.url,
|
|
520
|
+
};
|
|
521
|
+
if (opts.headers)
|
|
522
|
+
overlay.headers = opts.headers;
|
|
523
|
+
const createInput = { op: "create", name: opts.name, overlay };
|
|
524
|
+
if (opts.description)
|
|
525
|
+
createInput.description = opts.description;
|
|
526
|
+
const created = (await this.mcpServerDef(createInput, callOpts));
|
|
527
|
+
let row = created;
|
|
528
|
+
let changed = created.deduplicated !== true;
|
|
529
|
+
// create auto-discovers at ingestion → the count is on the create response.
|
|
530
|
+
let discoveredToolCount = created.discovered;
|
|
531
|
+
if (opts.rediscover) {
|
|
532
|
+
const red = (await this.mcpServerDef({ op: "rediscover", name: opts.name }, callOpts));
|
|
533
|
+
row = red;
|
|
534
|
+
if (red.deduplicated !== true)
|
|
535
|
+
changed = true;
|
|
536
|
+
if (red.discovered !== undefined)
|
|
537
|
+
discoveredToolCount = red.discovered;
|
|
538
|
+
}
|
|
539
|
+
const result = {
|
|
540
|
+
name: opts.name,
|
|
541
|
+
defId: row.def_id,
|
|
542
|
+
version: row.version,
|
|
543
|
+
changed,
|
|
544
|
+
};
|
|
545
|
+
if (discoveredToolCount !== undefined)
|
|
546
|
+
result.discoveredToolCount = discoveredToolCount;
|
|
547
|
+
return result;
|
|
548
|
+
}
|
|
453
549
|
/** Invoke the v1.x RFC E ScheduleDef substrate tool over HTTP.
|
|
454
550
|
* Author + fork + retire scheduled-run definitions at runtime.
|
|
455
551
|
* Mirror of {@link LoomcycleClient.agentDef} for schedules — the
|
package/dist/index.d.ts
CHANGED
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
* agentDef(input): Promise<SubstrateToolResponse>
|
|
49
49
|
* skillDef(input): Promise<SubstrateToolResponse>
|
|
50
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
|
|
51
53
|
* scheduleDef(input): Promise<SubstrateToolResponse>
|
|
52
54
|
*
|
|
53
55
|
* // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
|
|
@@ -80,5 +82,5 @@
|
|
|
80
82
|
* See `adapters/ts/README.md` for usage examples.
|
|
81
83
|
*/
|
|
82
84
|
export { LoomcycleClient } from "./client.js";
|
|
83
|
-
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, 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, AgentDefOverlay, EnsureCodeAgentOptions, EnsureCodeAgentResult, LibraryAgentDefinition, LibraryEntry, LibraryListResponse, LibraryMcpServerDefinition, LibrarySkillDefinition, LLMChatContent, LLMChatMessage, LLMChatOptions, LLMChatResponse, LLMChatStreamDelta, LLMChatStreamItem, LLMChatToolCall, LLMChatUsage, LLMTool, LLMEmbeddingItem, LLMEmbeddingsOptions, LLMEmbeddingsResponse, LLMEmbeddingsUsage, } from "./types.js";
|
|
84
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
|
@@ -48,6 +48,8 @@
|
|
|
48
48
|
* agentDef(input): Promise<SubstrateToolResponse>
|
|
49
49
|
* skillDef(input): Promise<SubstrateToolResponse>
|
|
50
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
|
|
51
53
|
* scheduleDef(input): Promise<SubstrateToolResponse>
|
|
52
54
|
*
|
|
53
55
|
* // Library v2 enumeration (v0.10.3 — yaml+substrate merged)
|
package/dist/types.d.ts
CHANGED
|
@@ -607,7 +607,7 @@ export interface PostHookCall {
|
|
|
607
607
|
* the adapter doesn't re-validate. Use the optional `extra` index
|
|
608
608
|
* signature for forward-compat fields. */
|
|
609
609
|
export type SubstrateToolInput = {
|
|
610
|
-
op: "create" | "fork" | "get" | "list" | "promote" | "retire";
|
|
610
|
+
op: "create" | "fork" | "get" | "list" | "promote" | "retire" | "rediscover" | "verify";
|
|
611
611
|
name?: string;
|
|
612
612
|
def_id?: string;
|
|
613
613
|
parent_def_id?: string;
|
|
@@ -886,6 +886,10 @@ export interface AgentDefRowResponse {
|
|
|
886
886
|
/** Only populated on `set` / `fork` responses (was the new row
|
|
887
887
|
* auto-promoted to active?). Absent on get/list. */
|
|
888
888
|
promoted?: boolean;
|
|
889
|
+
/** True when create was a content-addressed no-op: the active def already
|
|
890
|
+
* carried identical content, so no new version was minted. Absent on a
|
|
891
|
+
* real mint. Drives {@link LoomcycleClient.ensureCodeAgent}'s `changed`. */
|
|
892
|
+
deduplicated?: boolean;
|
|
889
893
|
}
|
|
890
894
|
/** Response shape for `AgentDef verify`. Answers "is the supplied
|
|
891
895
|
* content_sha256 the active deployed version of this name?"
|
|
@@ -938,6 +942,113 @@ export interface MCPServerDefRowResponse {
|
|
|
938
942
|
content_sha256?: string;
|
|
939
943
|
/** Only populated on `set` / `fork` responses (auto-promoted?). */
|
|
940
944
|
promoted?: boolean;
|
|
945
|
+
/** True when create/rediscover was a content-addressed no-op
|
|
946
|
+
* (loomcycle ≥ v0.18.0): the active def already carried identical
|
|
947
|
+
* content (create) or identical discovered_tools (rediscover), so no
|
|
948
|
+
* new version was minted. Absent (undefined) on a real mint. */
|
|
949
|
+
deduplicated?: boolean;
|
|
950
|
+
/** Number of tools discovered via the upstream's `tools/list`. Present on
|
|
951
|
+
* `rediscover` responses and — since loomcycle auto-discovers at ingestion
|
|
952
|
+
* — on a fresh `create`/`fork` that ran the handshake. Absent on a
|
|
953
|
+
* deduplicated create (the active tool surface was unchanged) and when
|
|
954
|
+
* `discover:false` was passed. */
|
|
955
|
+
discovered?: number;
|
|
956
|
+
}
|
|
957
|
+
/** Options for {@link LoomcycleClient.ensureMcpServer}. */
|
|
958
|
+
export interface EnsureMcpServerOptions {
|
|
959
|
+
/** Substrate name (not a static cfg.MCPServers name). */
|
|
960
|
+
name: string;
|
|
961
|
+
/** Absolute MCP endpoint, e.g. `http://localhost:3000/api/mcp`. */
|
|
962
|
+
url: string;
|
|
963
|
+
/** Default `"http"`. */
|
|
964
|
+
transport?: "http" | "streamable-http";
|
|
965
|
+
/** Per-request headers, stored verbatim. Keep `${run.*}` / `${LOOMCYCLE_*}`
|
|
966
|
+
* substitution placeholders LITERAL (don't resolve a token yourself) so
|
|
967
|
+
* the registration content is stable across restarts — that's what lets
|
|
968
|
+
* loomcycle's idempotent create dedup the re-registration. */
|
|
969
|
+
headers?: Record<string, string>;
|
|
970
|
+
description?: string;
|
|
971
|
+
/** Force a `tools/list` refresh after registering. Default false.
|
|
972
|
+
*
|
|
973
|
+
* You usually do NOT need this: registration auto-discovers the upstream's
|
|
974
|
+
* tools at ingestion, so {@link EnsureMcpServerResult.discoveredToolCount}
|
|
975
|
+
* is already populated from the `create`. Set this only to force a re-read
|
|
976
|
+
* when the upstream's tool surface changed but the registration content
|
|
977
|
+
* (url/headers) did not — a plain re-register would dedup and keep the
|
|
978
|
+
* cached tools, whereas a rediscover re-runs the handshake. */
|
|
979
|
+
rediscover?: boolean;
|
|
980
|
+
}
|
|
981
|
+
/** Result of {@link LoomcycleClient.ensureMcpServer}. */
|
|
982
|
+
export interface EnsureMcpServerResult {
|
|
983
|
+
name: string;
|
|
984
|
+
defId: string;
|
|
985
|
+
version: number;
|
|
986
|
+
/** True when this call minted a new version (create and/or rediscover);
|
|
987
|
+
* false when loomcycle deduped it (active def already current). A
|
|
988
|
+
* consumer re-registering on every boot expects `changed: false` once
|
|
989
|
+
* the registration content is stable. */
|
|
990
|
+
changed: boolean;
|
|
991
|
+
/** Populated when `rediscover` ran: the number of tools discovered. */
|
|
992
|
+
discoveredToolCount?: number;
|
|
993
|
+
}
|
|
994
|
+
/** Typed `overlay` for an {@link LoomcycleClient.agentDef} create/fork —
|
|
995
|
+
* the mutable subset of an agent definition. All fields optional (a fork
|
|
996
|
+
* overlays only what changes). The `[extra]` tail keeps it forward-compatible
|
|
997
|
+
* with fields the in-process tool may accept that the adapter doesn't model
|
|
998
|
+
* yet — the tool owns the authoritative schema; the adapter doesn't re-validate.
|
|
999
|
+
*
|
|
1000
|
+
* `code_body` is the inline code-js orchestrator source (RFC J): set it (with
|
|
1001
|
+
* `provider: "code-js"`) to ingest a code agent through the substrate with NO
|
|
1002
|
+
* host filesystem bind — the symmetry that makes code agents work in
|
|
1003
|
+
* containers / pure-cloud. Requires `LOOMCYCLE_CODE_AGENTS_ENABLED=1` on the
|
|
1004
|
+
* sidecar; create/fork refuses a non-empty `code_body` otherwise. */
|
|
1005
|
+
export interface AgentDefOverlay {
|
|
1006
|
+
provider?: string;
|
|
1007
|
+
model?: string;
|
|
1008
|
+
/** Inline code-js source. Empty/absent ⇒ the provider falls back to
|
|
1009
|
+
* `agent_code/<name>/index.js`. Stored verbatim (whitespace is hash-
|
|
1010
|
+
* significant); participates in content_sha256. */
|
|
1011
|
+
code_body?: string;
|
|
1012
|
+
tier?: string;
|
|
1013
|
+
effort?: string;
|
|
1014
|
+
max_tokens?: number;
|
|
1015
|
+
max_iterations?: number;
|
|
1016
|
+
max_concurrent_children?: number;
|
|
1017
|
+
system_prompt?: string;
|
|
1018
|
+
allowed_tools?: string[];
|
|
1019
|
+
skills?: string[];
|
|
1020
|
+
memory_scopes?: string[];
|
|
1021
|
+
memory_quota_bytes?: number;
|
|
1022
|
+
memory_backend?: string;
|
|
1023
|
+
retry_attempts?: number;
|
|
1024
|
+
[extra: string]: unknown;
|
|
1025
|
+
}
|
|
1026
|
+
/** Options for {@link LoomcycleClient.ensureCodeAgent}. */
|
|
1027
|
+
export interface EnsureCodeAgentOptions {
|
|
1028
|
+
/** Agent name (substrate; must not collide with a static cfg.Agents name —
|
|
1029
|
+
* use a fork for those). */
|
|
1030
|
+
name: string;
|
|
1031
|
+
/** The inline code-js orchestrator source (the `function run(input){…}` body).
|
|
1032
|
+
* Keep any `${run.*}` / `${LOOMCYCLE_*}` placeholders LITERAL so the content
|
|
1033
|
+
* is stable across restarts — that's what lets loomcycle dedup the
|
|
1034
|
+
* re-registration. */
|
|
1035
|
+
code: string;
|
|
1036
|
+
/** The agent's allowed_tools ceiling (must be a subset of the caller's). */
|
|
1037
|
+
allowedTools?: string[];
|
|
1038
|
+
/** Per-user tier policy name (mutually exclusive with `model` in practice). */
|
|
1039
|
+
tier?: string;
|
|
1040
|
+
/** Pin a concrete model id (overrides tier resolution). */
|
|
1041
|
+
model?: string;
|
|
1042
|
+
description?: string;
|
|
1043
|
+
}
|
|
1044
|
+
/** Result of {@link LoomcycleClient.ensureCodeAgent}. */
|
|
1045
|
+
export interface EnsureCodeAgentResult {
|
|
1046
|
+
name: string;
|
|
1047
|
+
defId: string;
|
|
1048
|
+
version: number;
|
|
1049
|
+
/** True when this call minted a new version; false when loomcycle deduped
|
|
1050
|
+
* it (identical body + config already active). */
|
|
1051
|
+
changed: boolean;
|
|
941
1052
|
}
|
|
942
1053
|
/** Response shape for `MCPServerDef verify`. Same semantics as
|
|
943
1054
|
* AgentDefVerifyResult / SkillDefVerifyResult — answers "is the
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loomcycle/client",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "TypeScript client for the loomcycle sidecar (HTTP+SSE).
|
|
3
|
+
"version": "0.20.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). v0.19.0 — typed inline code-js agent ingestion (AgentDefOverlay.code_body + ensureCodeAgent — register a deterministic code agent through the substrate with no host filesystem bind; RFC J). v0.20.0 — ensureMcpServer surfaces discoveredToolCount straight from create (loomcycle now auto-discovers MCP tools at ingestion); rediscover is now an explicit force-refresh.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"repository": {
|