@copilotkit/runtime 1.66.1 → 1.66.2-canary.1785866877
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/package.cjs +1 -1
- package/dist/runtime/package.mjs +1 -1
- package/dist/v2/runtime/core/channel-manager.cjs +109 -28
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +109 -28
- package/dist/v2/runtime/core/channel-manager.mjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.cjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.cjs.map +1 -1
- package/dist/v2/runtime/handlers/intelligence/run.mjs +3 -0
- package/dist/v2/runtime/handlers/intelligence/run.mjs.map +1 -1
- package/package.json +6 -6
package/dist/package.cjs
CHANGED
|
@@ -5,7 +5,7 @@ const require_runtime = require('./_virtual/_rolldown/runtime.cjs');
|
|
|
5
5
|
var require_package = /* @__PURE__ */ require_runtime.__commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.66.
|
|
8
|
+
"version": "1.66.2-canary.1785866877",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
package/dist/runtime/package.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { __commonJSMin } from "../_virtual/_rolldown/runtime.mjs";
|
|
|
5
5
|
var require_package = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
6
6
|
module.exports = {
|
|
7
7
|
"name": "@copilotkit/runtime",
|
|
8
|
-
"version": "1.66.
|
|
8
|
+
"version": "1.66.2-canary.1785866877",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
|
@@ -289,6 +289,12 @@ async function hydrateManagedContent(content, intelligence) {
|
|
|
289
289
|
function isSetupRequired(err) {
|
|
290
290
|
return err instanceof ChannelSetupRequiredError || typeof err === "object" && err !== null && err.code === "SETUP_REQUIRED";
|
|
291
291
|
}
|
|
292
|
+
/** Whether a failed initial activation can recover without new configuration. */
|
|
293
|
+
function isRetryableActivationError(err) {
|
|
294
|
+
if (typeof err !== "object" || err === null) return false;
|
|
295
|
+
const value = err;
|
|
296
|
+
return (value.code === "GATEWAY_UNREACHABLE" || value.code === "GATEWAY_JOIN_FAILED") && value.retryable === true;
|
|
297
|
+
}
|
|
292
298
|
/**
|
|
293
299
|
* Whether `err` is a Node/runtime module-resolution failure — i.e. the error
|
|
294
300
|
* a dynamic `import()` throws when the target package is not installed.
|
|
@@ -302,8 +308,14 @@ function isModuleNotFound(err) {
|
|
|
302
308
|
}
|
|
303
309
|
/** Default deadline (ms) for a single `handle.stop()` during teardown. */
|
|
304
310
|
const DEFAULT_STOP_HANDLE_TIMEOUT_MS = 5e3;
|
|
305
|
-
/**
|
|
311
|
+
/** First delay (ms) before logging that a dropped session is still down. */
|
|
306
312
|
const DEFAULT_RECONNECT_LOG_INTERVAL_MS = 3e4;
|
|
313
|
+
/** Longest delay (ms) between reminders during one continuous outage. */
|
|
314
|
+
const DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS = 15 * 6e4;
|
|
315
|
+
/** First delay (ms) before retrying a transient initial activation failure. */
|
|
316
|
+
const DEFAULT_ACTIVATION_RETRY_DELAY_MS = 1e3;
|
|
317
|
+
/** Longest delay (ms) between transient initial activation attempts. */
|
|
318
|
+
const DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS = 3e4;
|
|
307
319
|
/**
|
|
308
320
|
* Reject with `timeoutMessage` after `timeoutMs` if `inner` has not settled,
|
|
309
321
|
* otherwise pass `inner` through. When `timeoutMs` is undefined, `inner` is
|
|
@@ -336,17 +348,18 @@ function withTimeout(inner, timeoutMs, timeoutMessage) {
|
|
|
336
348
|
* {@link activate} starts it and a second call is a no-op. Activation throws
|
|
337
349
|
* SYNCHRONOUSLY (a {@link ChannelConfigError}) only for a misconfiguration it
|
|
338
350
|
* can detect up front — a duplicate or missing Channel name. Every OTHER
|
|
339
|
-
* activation failure is recorded as the Channel's status (`error`,
|
|
340
|
-
* `setup_required` for a missing provider) and surfaced through
|
|
341
|
-
* and {@link ready} rather than thrown.
|
|
351
|
+
* permanent activation failure is recorded as the Channel's status (`error`,
|
|
352
|
+
* or `setup_required` for a missing provider) and surfaced through
|
|
353
|
+
* {@link status} and {@link ready} rather than thrown. A retryable initial
|
|
354
|
+
* gateway outage stays unsettled and retries until it connects or the manager
|
|
355
|
+
* stops.
|
|
342
356
|
*
|
|
343
|
-
*
|
|
357
|
+
* Established-session reconnection is delegated to the Phoenix connection
|
|
344
358
|
* layer that backs the launcher. When a managed control socket drops, Phoenix's
|
|
345
|
-
* `Socket` reconnects and rejoins with the same Runtime declaration.
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
*
|
|
349
|
-
* The manager therefore never re-activates on a drop.
|
|
359
|
+
* `Socket` reconnects and rejoins with the same Runtime declaration. The manager
|
|
360
|
+
* never re-activates an already-started Channel. It does retry a transient
|
|
361
|
+
* INITIAL gateway activation failure: that happens before the launcher adds or
|
|
362
|
+
* starts the managed adapter, so a later attempt is safe.
|
|
350
363
|
*
|
|
351
364
|
* It DOES, however, reflect real connection health through the session's
|
|
352
365
|
* `onStateChange` observer so {@link ChannelManager.status} stays honest rather
|
|
@@ -381,8 +394,8 @@ var ChannelManager = class {
|
|
|
381
394
|
/**
|
|
382
395
|
* Start activation of every declared Channel (lazy + idempotent). Mints a
|
|
383
396
|
* distinct runtime instance id per Channel, derives its activation config,
|
|
384
|
-
* and calls the engine.
|
|
385
|
-
* to `online`/`setup_required`/`error
|
|
397
|
+
* and calls the engine. Transient gateway failures retry with exponential
|
|
398
|
+
* backoff; other outcomes transition to `online`/`setup_required`/`error`.
|
|
386
399
|
*/
|
|
387
400
|
activate() {
|
|
388
401
|
if (this.activated || this.stopped) return;
|
|
@@ -399,24 +412,23 @@ var ChannelManager = class {
|
|
|
399
412
|
rejectSettled = reject;
|
|
400
413
|
});
|
|
401
414
|
settled.catch(() => {});
|
|
415
|
+
const entry = {
|
|
416
|
+
status: "connecting",
|
|
417
|
+
handle: void 0,
|
|
418
|
+
handleStopped: false,
|
|
419
|
+
settled
|
|
420
|
+
};
|
|
402
421
|
let activation;
|
|
403
|
-
let config;
|
|
404
422
|
try {
|
|
405
|
-
config = require_channel_activation_config.deriveChannelActivationConfig({
|
|
423
|
+
const config = require_channel_activation_config.deriveChannelActivationConfig({
|
|
406
424
|
intelligence: this.intelligence,
|
|
407
425
|
channel,
|
|
408
426
|
runtimeInstanceId
|
|
409
427
|
});
|
|
410
|
-
activation = this.
|
|
428
|
+
activation = this.activateWithRetry(config, channel, name, entry);
|
|
411
429
|
} catch (err) {
|
|
412
430
|
activation = Promise.reject(err);
|
|
413
431
|
}
|
|
414
|
-
const entry = {
|
|
415
|
-
status: "connecting",
|
|
416
|
-
handle: void 0,
|
|
417
|
-
handleStopped: false,
|
|
418
|
-
settled
|
|
419
|
-
};
|
|
420
432
|
activation.then(async (handle) => {
|
|
421
433
|
entry.handle = handle;
|
|
422
434
|
if (this.stopped) {
|
|
@@ -469,6 +481,54 @@ var ChannelManager = class {
|
|
|
469
481
|
}
|
|
470
482
|
}
|
|
471
483
|
/**
|
|
484
|
+
* Retry only transient failures from the pre-adapter gateway connection.
|
|
485
|
+
* Permanent errors reject on the first attempt; teardown cancels a pending
|
|
486
|
+
* timer while preserving the existing late-settle handling for in-flight work.
|
|
487
|
+
*/
|
|
488
|
+
activateWithRetry(config, channel, name, entry) {
|
|
489
|
+
return new Promise((resolve, reject) => {
|
|
490
|
+
const attempt = () => {
|
|
491
|
+
let activation;
|
|
492
|
+
try {
|
|
493
|
+
activation = this.activateChannel(config, channel);
|
|
494
|
+
} catch (err) {
|
|
495
|
+
activation = Promise.reject(err);
|
|
496
|
+
}
|
|
497
|
+
activation.then((handle) => {
|
|
498
|
+
this.clearActivationRetry(entry);
|
|
499
|
+
resolve(handle);
|
|
500
|
+
}, (err) => {
|
|
501
|
+
if (this.stopped || !isRetryableActivationError(err)) {
|
|
502
|
+
this.clearActivationRetry(entry);
|
|
503
|
+
reject(err);
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
const delayMs = entry.activationRetryDelayMs ?? DEFAULT_ACTIVATION_RETRY_DELAY_MS;
|
|
507
|
+
entry.status = "reconnecting";
|
|
508
|
+
entry.activationRetryDelayMs = Math.min(delayMs * 2, DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS);
|
|
509
|
+
this.log?.(`channel "${name}" failed to activate; retrying in ${delayMs}ms`, err);
|
|
510
|
+
const timer = setTimeout(() => {
|
|
511
|
+
entry.activationRetryTimer = void 0;
|
|
512
|
+
entry.cancelActivationRetry = void 0;
|
|
513
|
+
if (this.stopped || entry.status === "stopped") {
|
|
514
|
+
reject(err);
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
entry.status = "connecting";
|
|
518
|
+
attempt();
|
|
519
|
+
}, delayMs);
|
|
520
|
+
timer.unref?.();
|
|
521
|
+
entry.activationRetryTimer = timer;
|
|
522
|
+
entry.cancelActivationRetry = () => {
|
|
523
|
+
this.clearActivationRetry(entry);
|
|
524
|
+
reject(err);
|
|
525
|
+
};
|
|
526
|
+
});
|
|
527
|
+
};
|
|
528
|
+
attempt();
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
/**
|
|
472
532
|
* Throw if two declared Channels share a `name`. `entries` is keyed by name,
|
|
473
533
|
* so a duplicate would overwrite the first Channel's entry and leak its live
|
|
474
534
|
* session. Called at the very start of {@link activate}, before any engine
|
|
@@ -611,29 +671,49 @@ var ChannelManager = class {
|
|
|
611
671
|
return entry.downSince === void 0 ? "unknown" : `${Math.round((Date.now() - entry.downSince) / 1e3)}s`;
|
|
612
672
|
}
|
|
613
673
|
/**
|
|
614
|
-
* Repeat a "still down" line for as long as this outage lasts
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
* idle one.
|
|
674
|
+
* Repeat a "still down" line for as long as this outage lasts, with an
|
|
675
|
+
* exponential delay capped at 15 minutes. Runs THROUGH `gave_up` on purpose:
|
|
676
|
+
* that transition is where the old behavior went quiet, and an operator
|
|
677
|
+
* watching a silent process cannot tell a dead bot from an idle one.
|
|
618
678
|
*/
|
|
619
679
|
startReconnectLog(name, entry) {
|
|
620
680
|
if (entry.reconnectLogTimer !== void 0) return;
|
|
621
|
-
const
|
|
681
|
+
const delayMs = entry.reconnectLogDelayMs ?? this.reconnectLogIntervalMs;
|
|
682
|
+
const timer = setTimeout(() => {
|
|
683
|
+
entry.reconnectLogTimer = void 0;
|
|
622
684
|
if (this.stopped || entry.status === "stopped") {
|
|
623
685
|
this.clearReconnectLog(entry);
|
|
624
686
|
return;
|
|
625
687
|
}
|
|
626
688
|
this.log?.(`channel "${name}" managed session still down after ${this.downFor(entry)}; Phoenix is retrying`);
|
|
627
|
-
|
|
689
|
+
entry.reconnectLogDelayMs = Math.min(delayMs * 2, Math.max(this.reconnectLogIntervalMs, DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS));
|
|
690
|
+
this.startReconnectLog(name, entry);
|
|
691
|
+
}, delayMs);
|
|
628
692
|
timer.unref?.();
|
|
629
693
|
entry.reconnectLogTimer = timer;
|
|
630
694
|
}
|
|
631
695
|
/** Stop this entry's "still down" repeat, if one is running. */
|
|
632
696
|
clearReconnectLog(entry) {
|
|
633
697
|
if (entry.reconnectLogTimer !== void 0) {
|
|
634
|
-
|
|
698
|
+
clearTimeout(entry.reconnectLogTimer);
|
|
635
699
|
entry.reconnectLogTimer = void 0;
|
|
636
700
|
}
|
|
701
|
+
entry.reconnectLogDelayMs = void 0;
|
|
702
|
+
}
|
|
703
|
+
/** Cancel a pending transient activation retry and reset its backoff. */
|
|
704
|
+
clearActivationRetry(entry) {
|
|
705
|
+
if (entry.activationRetryTimer !== void 0) {
|
|
706
|
+
clearTimeout(entry.activationRetryTimer);
|
|
707
|
+
entry.activationRetryTimer = void 0;
|
|
708
|
+
}
|
|
709
|
+
entry.activationRetryDelayMs = void 0;
|
|
710
|
+
entry.cancelActivationRetry = void 0;
|
|
711
|
+
}
|
|
712
|
+
/** Cancel a scheduled activation retry and settle its wrapper. */
|
|
713
|
+
cancelActivationRetry(entry) {
|
|
714
|
+
const cancel = entry.cancelActivationRetry;
|
|
715
|
+
if (cancel) cancel();
|
|
716
|
+
else this.clearActivationRetry(entry);
|
|
637
717
|
}
|
|
638
718
|
/**
|
|
639
719
|
* Drive a single entry to its terminal `stopped` state, tearing down its
|
|
@@ -670,6 +750,7 @@ var ChannelManager = class {
|
|
|
670
750
|
async stopEntry(entry) {
|
|
671
751
|
entry.status = "stopped";
|
|
672
752
|
this.clearReconnectLog(entry);
|
|
753
|
+
this.cancelActivationRetry(entry);
|
|
673
754
|
if (entry.handle && !entry.handleStopped) {
|
|
674
755
|
entry.handleStopped = true;
|
|
675
756
|
const handle = entry.handle;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"channel-manager.cjs","names":["MCPMiddleware","INTELLIGENCE_MEMORY_GRANT_HEADER","INTELLIGENCE_USER_ID_HEADER","AbstractAgent","EMPTY","EventType","deriveChannelActivationConfig","ChannelConfigError"],"sources":["../../../../src/v2/runtime/core/channel-manager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n ChannelConfigError,\n deriveChannelActivationConfig,\n} from \"./channel-activation-config\";\nimport type { ChannelActivationConfig } from \"./channel-activation-config\";\nimport type { CopilotKitIntelligence } from \"../intelligence-platform\";\nimport { AbstractAgent, EventType } from \"@ag-ui/client\";\nimport type {\n AgentSubscriber,\n BaseEvent,\n Message,\n RunAgentParameters,\n RunAgentResult,\n} from \"@ag-ui/client\";\nimport { EMPTY } from \"rxjs\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { AgentRunner } from \"../runner/agent-runner\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../intelligence-platform/client\";\n// Type-only: @copilotkit/channels is pure-ESM, so a value import would break this\n// package's CJS output (see `core/runtime.ts` and `channel-activation-config.ts`\n// for the same constraint).\nimport type {\n Channel,\n ReplyContinuationOptions,\n ResolvedChannelMemory,\n} from \"@copilotkit/channels\";\n\n/**\n * Lifecycle status of a single Channel activation, or of the manager overall.\n *\n * - `connecting`: activation in flight, not yet settled.\n * - `online`: activation resolved AND the managed session can currently send.\n * A drop moves the Channel to `reconnecting` (not `online`); a successful\n * rejoin restores `online`.\n * - `setup_required`: the Channel is declared but has no managed provider yet —\n * a valid degraded state, not a failure.\n * - `reconnecting`: the managed session dropped and Phoenix is retrying — not\n * currently sendable. The manager does NOT re-activate (reconnection is\n * delegated to the Phoenix connection layer); it only reflects the health the\n * session reports via its `onStateChange` observer.\n * - `stopped`: {@link ChannelManager.stop} has torn the Channel down.\n * - `error`: activation rejected with a non-setup error, or a previously-online\n * control link gave up reconnecting after its bounded reconnect window.\n *\n * A Channel may carry developer-supplied direct adapters alongside the managed\n * Intelligence adapter. The managed engine owns the shared Channel lifecycle;\n * each adapter still receives only its own ingress and sends only its own\n * provider output.\n */\nexport type ChannelStatus =\n | \"connecting\"\n | \"online\"\n | \"setup_required\"\n | \"reconnecting\"\n | \"stopped\"\n | \"error\";\n\n/**\n * The lifecycle control surface a Channel host uses to drive and observe\n * managed Channel activation.\n */\nexport interface ChannelsControl {\n /**\n * Resolve once every declared Channel has settled to a terminal, non-connecting\n * state (`online` or `setup_required`). Rejects if any Channel is in `error`,\n * or — when `timeoutMs` is given — if the whole set has not settled in time.\n */\n ready(opts?: { timeoutMs?: number }): Promise<void>;\n /** Snapshot the overall status and the per-Channel status map. */\n status(): { overall: ChannelStatus; channels: Record<string, ChannelStatus> };\n /** Tear down every activated Channel. Idempotent. */\n stop(): Promise<void>;\n}\n\n/**\n * Signals that a declared Channel cannot be activated because no managed\n * provider exists for it yet. The engine throws this (or any error whose\n * `code === \"SETUP_REQUIRED\"`) to move a Channel to `setup_required` rather\n * than `error` — a declared-but-unprovisioned Channel is a valid degraded\n * state, not a failure.\n */\nexport class ChannelSetupRequiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ChannelSetupRequiredError\";\n }\n}\n\n/**\n * The activation engine: given a resolved {@link ChannelActivationConfig} and\n * the declared {@link Channel}, bring the Channel online and return its handle.\n * Injected in tests (a fake engine); defaults to the Realtime Gateway launcher.\n */\nexport type ActivateChannelEngine = (\n config: ChannelActivationConfig,\n channel: Channel,\n) => Promise<ChannelsHandle>;\n\n/**\n * Minimal structural view of the `@copilotkit/channels-intelligence`\n * `ChannelsHandle`. Declared locally (not imported) because the runtime is a\n * CJS package that must not take a static dependency on the pure-ESM\n * channels-intelligence package — the default engine reaches its launcher\n * through a dynamic `import()` instead. The manager only ever needs `stop()`.\n */\nexport interface ChannelsHandle {\n /** Activation metadata declared to Intelligence. Unused by the manager. */\n metadata: unknown;\n /** Stop the underlying Channel(s) and release transports. */\n stop(): Promise<void>;\n /**\n * Optional seam: register a callback the handle fires when its managed\n * session drops. Retained as a per-episode drop breadcrumb; the manager drives\n * status from {@link ChannelsHandle.onStateChange} instead. Present on the\n * Realtime Gateway launcher handle; optional for non-gateway/test handles.\n */\n onClose?(cb: () => void): void;\n /**\n * Optional seam: register a connection-health observer the handle fires as its\n * managed session moves between `online` (sendable), `reconnecting` (dropped,\n * Phoenix retrying), and `gave_up` (dead after the bounded reconnect window).\n * The manager uses this to keep {@link ChannelManager.status} honest — it does\n * NOT re-activate on a drop (reconnection is delegated to the Phoenix\n * connection layer; see {@link ChannelManager}). Optional so non-gateway or\n * test handles that do not implement it are always invoked as\n * `handle.onStateChange?.(cb)`.\n */\n onStateChange?(\n cb: (\n state: \"online\" | \"reconnecting\" | \"gave_up\",\n detail?: { reason?: string; code?: string },\n ) => void,\n ): void;\n}\n\n/** Constructor arguments for {@link ChannelManager}. */\nexport interface ChannelManagerArgs {\n /** The Intelligence runtime client the activation config is derived from. */\n intelligence: CopilotKitIntelligence;\n /** The declared framework Channels to activate. */\n channels: Channel[];\n /** Standard runtime AgentRunner used by managed Channel executions. */\n runner?: AgentRunner;\n /** Standard thread-lock TTL forwarded to Channel AgentRunner heartbeats. */\n lockTtlSeconds?: number;\n /** Standard thread-lock heartbeat cadence used by Channel AgentRunner calls. */\n lockHeartbeatIntervalSeconds?: number;\n /** Must match web Intelligence runs so channel + HTTP share the same lock key. */\n lockKeyPrefix?: string;\n /**\n * Activation engine. Defaults to a wrapper over the channels-intelligence\n * Realtime Gateway launcher (`startChannelsOverRealtimeGateway`), reached via\n * dynamic import so this CJS package keeps no static ESM dependency.\n */\n activateChannel?: ActivateChannelEngine;\n /** Mint a runtime instance id per Channel. Defaults to `rti_{uuid-no-dashes}`. */\n mintRuntimeInstanceId?: () => string;\n /** Diagnostic sink. Forwarded to the launcher/transport when the default\n * activation engine is used, so transport-level drops surface in the managed\n * path (not just activation-level events). */\n log?: (msg: string, meta?: unknown) => void;\n /**\n * How often (ms) to repeat a \"still down\" log while a managed session is\n * disconnected. A dropped session was previously silent for as long as the\n * outage lasted, which made a dead bot indistinguishable from an idle one\n * (OSS-670). Injectable so tests need no fake timers. Default 30000.\n */\n reconnectLogIntervalMs?: number;\n /** Per-handle deadline (ms) for `handle.stop()` during {@link ChannelManager.stop}\n * so a wedged stop can't hang SIGTERM shutdown. Default 5000. */\n stopHandleTimeoutMs?: number;\n}\n\n/** Per-Channel mutable activation entry tracked by the manager. */\ninterface ChannelEntry {\n status: ChannelStatus;\n /** Resolves on `online`/`setup_required`; rejects on `error`. Awaited by `ready`. */\n readonly settled: Promise<void>;\n handle?: ChannelsHandle;\n /**\n * Whether {@link ChannelManager.stopEntry} has already stopped `handle`. Gates\n * the single-stop guarantee: the success settle handler and `stop()` can both\n * reach the same entry in the same tick, but the handle is torn down at most\n * once.\n */\n handleStopped: boolean;\n /** Epoch ms this outage episode began; unset while the session is healthy. */\n downSince?: number;\n /** Repeating \"still down\" logger for this outage; cleared on recovery/teardown. */\n reconnectLogTimer?: ReturnType<typeof setInterval>;\n}\n\n/**\n * Runtime installs this pure-ESM package as a direct dependency, but the\n * specifier must stay non-literal so it never becomes a static dependency of\n * the runtime's CJS build. The packed-consumer contract is enforced by\n * `scripts/release/verify-runtime-package.ts`.\n */\nconst CHANNELS_INTELLIGENCE_SPECIFIER = \"@copilotkit/channels-intelligence\";\n\n/**\n * Structural view of the `@copilotkit/channels-intelligence` module surface the\n * default engine consumes. Declared locally (not imported) for the same\n * CJS/ESM-boundary reason the {@link ChannelsHandle} view is.\n */\nexport interface ChannelsIntelligenceModule {\n startChannelsOverRealtimeGateway: (\n channels: Channel[],\n opts: {\n wsUrl: string;\n apiKey: string;\n scope: { projectId: number; channelName: string };\n runtimeInstanceId: string;\n /** Optional per-Channel override for managed tool-call visibility. */\n showToolStatus?: boolean;\n /** Optional per-Channel tuning for continuation messages on long replies. */\n replyContinuation?: ReplyContinuationOptions;\n /** Intelligence app-api HTTP base URL, forwarded to the transport so the\n * managed realtime path enables file/history parity (HTTP-only) — OSS-476. */\n appApiBaseUrl?: string;\n /** Diagnostic sink forwarded to the launcher/transport so transport-level\n * drop diagnostics (e.g. a version-skew missing-leaseToken outage) are not\n * silent in the managed path. */\n log?: (msg: string, meta?: unknown) => void;\n runCanonical(args: {\n agent: AbstractAgent;\n deliveryId: string;\n signal?: AbortSignal;\n threadId: string;\n runId: string;\n userId: string;\n agentId: string;\n tools: readonly {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }[];\n context: readonly { description: string; value: string }[];\n persistedInputMessages: Message[];\n execute(\n subscriber: AgentSubscriber,\n canonicalRun?: { threadId: string; runId: string },\n ): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n }): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n loadHistory(args: {\n deliveryId: string;\n threadId: string;\n appUserId: string;\n }): Promise<Message[]>;\n },\n ) => Promise<ChannelsHandle>;\n}\n\n/**\n * Default engine: wrap the channels-intelligence Realtime Gateway launcher.\n *\n * The module is reached through an injectable importer that defaults to a\n * dynamic `import()` of a non-literal specifier, so the pure-ESM\n * `@copilotkit/channels-intelligence` never becomes a static dependency of this\n * CJS package (mirrors the runtime's other channels seams). The `import`\n * seam is a parameter purely so this function's config→opts mapping and its\n * module-not-found / generic-error branches are unit-testable WITHOUT the real\n * package installed; production always uses the default importer.\n *\n * Passes NO `org`/`channelId` — the launcher's realtime scope treats them as\n * optional.\n *\n * @param config - Resolved activation config for the Channel.\n * @param channel - The Channel to activate.\n * @param importChannelsIntelligence - Test seam; loads the channels-intelligence\n * module. Defaults to a dynamic import of the real package.\n * @param log - Optional diagnostic sink forwarded to the launcher/transport so\n * transport-level drop diagnostics are not silent in the managed path.\n * @returns The launcher's {@link ChannelsHandle}.\n */\nexport async function defaultActivateChannel(\n config: ChannelActivationConfig,\n channel: Channel,\n importChannelsIntelligence: () => Promise<ChannelsIntelligenceModule> = () =>\n import(\n CHANNELS_INTELLIGENCE_SPECIFIER\n ) as Promise<ChannelsIntelligenceModule>,\n log?: (msg: string, meta?: unknown) => void,\n services?: {\n runner: AgentRunner;\n intelligence: CopilotKitIntelligence;\n lockTtlSeconds?: number;\n lockHeartbeatIntervalSeconds?: number;\n lockKeyPrefix?: string;\n },\n): Promise<ChannelsHandle> {\n let mod: ChannelsIntelligenceModule;\n try {\n mod = await importChannelsIntelligence();\n } catch (err) {\n if (isModuleNotFound(err)) {\n throw new Error(\n \"Managed Channels require '@copilotkit/channels-intelligence' to be installed. Add it to your app's dependencies.\",\n { cause: err },\n );\n }\n throw err;\n }\n if (!services) {\n throw new Error(\n \"Managed Channels require the runtime AgentRunner and Intelligence client\",\n );\n }\n return mod.startChannelsOverRealtimeGateway([channel], {\n wsUrl: config.wsUrl,\n apiKey: config.apiKey,\n scope: { projectId: config.projectId, channelName: config.channelName },\n runtimeInstanceId: config.runtimeInstanceId,\n ...(config.showToolStatus !== undefined\n ? { showToolStatus: config.showToolStatus }\n : {}),\n ...(config.replyContinuation !== undefined\n ? { replyContinuation: config.replyContinuation }\n : {}),\n // Forward the app-api HTTP base URL so the transport wires file/history\n // (HTTP-only) on the NORMAL managed path — without this, Channels started by\n // the CopilotRuntime handler run with no history/file support (OSS-476).\n appApiBaseUrl: config.apiUrl,\n // Forward the manager's diagnostic sink down to the launcher/transport so a\n // transport-level drop (e.g. a version-skew missing-leaseToken outage) is\n // observable in the managed path, not just activation-level events.\n ...(log ? { log } : {}),\n runCanonical: (args) =>\n runCanonicalChannelAgent(\n services.runner,\n services.intelligence,\n services.lockTtlSeconds ?? 20,\n services.lockHeartbeatIntervalSeconds ?? 15,\n args,\n services.lockKeyPrefix,\n ),\n loadHistory: async ({ deliveryId, threadId, appUserId }) => {\n const history = await services.intelligence.getThreadMessages({\n threadId,\n userId: appUserId,\n channelDeliveryId: deliveryId,\n });\n return Promise.all(\n history.messages.map((message) =>\n toAgentMessage(message, services.intelligence),\n ),\n );\n },\n });\n}\n\ninterface CanonicalRunArgs {\n agent: AbstractAgent;\n deliveryId: string;\n signal?: AbortSignal;\n threadId: string;\n runId: string;\n userId: string;\n memory?: ResolvedChannelMemory;\n agentId: string;\n tools: readonly {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }[];\n context: readonly { description: string; value: string }[];\n persistedInputMessages: Message[];\n execute(\n subscriber: AgentSubscriber,\n canonicalRun?: { threadId: string; runId: string },\n ): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n}\n\n/** Attach grant-scoped Intelligence Memory tools to one isolated Channel agent. */\nexport function attachChannelMemory(\n agent: AbstractAgent,\n intelligence: CopilotKitIntelligence,\n memory: ResolvedChannelMemory | undefined,\n): void {\n if (!memory) return;\n const middlewareAgent = agent as AbstractAgent & {\n use?: (middleware: unknown) => void;\n };\n if (typeof middlewareAgent.use !== \"function\") {\n const error = new Error(\n \"Channel Memory requires an agent with middleware support\",\n ) as Error & { code?: string };\n error.name = \"ChannelMemoryAgentUnsupportedError\";\n error.code = \"channel_memory_agent_unsupported\";\n throw error;\n }\n middlewareAgent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(memory.grant),\n ...(memory.user\n ? { [INTELLIGENCE_USER_ID_HEADER]: memory.user.id }\n : {}),\n },\n },\n ]),\n );\n}\n\n/** One outer agent that lets the standard runner own the whole local tool loop. */\nclass ChannelOuterAgent extends AbstractAgent {\n constructor(\n private readonly inner: AbstractAgent,\n private readonly canonicalThreadId: string,\n private readonly executeLoop: CanonicalRunArgs[\"execute\"],\n ) {\n super({\n threadId: inner.threadId,\n initialMessages: inner.messages,\n initialState: inner.state,\n ...(inner.agentId ? { agentId: inner.agentId } : {}),\n });\n }\n\n run(): ReturnType<AbstractAgent[\"run\"]> {\n return EMPTY;\n }\n\n override async runAgent(\n parameters?: RunAgentParameters,\n subscriber?: AgentSubscriber,\n ): Promise<RunAgentResult> {\n if (!parameters?.runId) {\n throw new Error(\"Canonical Channel run requires a runId\");\n }\n const result = await this.executeLoop(subscriber ?? {}, {\n threadId: this.canonicalThreadId,\n runId: parameters.runId,\n });\n return { result, newMessages: [] };\n }\n\n override abortRun(): void {\n this.inner.abortRun();\n }\n}\n\n/** Drive one public Channel run through the runtime's existing AgentRunner. */\nasync function runCanonicalChannelAgent(\n runner: AgentRunner,\n intelligence: CopilotKitIntelligence,\n lockTtlSeconds: number,\n lockHeartbeatIntervalSeconds: number,\n args: CanonicalRunArgs,\n lockKeyPrefix?: string,\n): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n}> {\n const lock = await intelligence.ɵacquireThreadLock({\n threadId: args.threadId,\n runId: args.runId,\n userId: args.userId,\n agentId: args.agentId,\n channelDeliveryId: args.deliveryId,\n ttlSeconds: lockTtlSeconds,\n ...(lockKeyPrefix !== undefined ? { lockKeyPrefix } : {}),\n });\n const canonicalThreadId = lock.threadId;\n const canonicalRunId = lock.runId;\n let result = { iterations: 0, interrupted: false };\n attachChannelMemory(args.agent, intelligence, args.memory);\n const outer = new ChannelOuterAgent(\n args.agent,\n canonicalThreadId,\n async (subscriber, canonicalRun) => {\n result = await args.execute(subscriber, canonicalRun);\n return result;\n },\n );\n let stopPromise: Promise<boolean | undefined> | undefined;\n let heartbeatError: unknown;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n const stopCanonicalRun = (): void => {\n stopPromise ??= Promise.resolve()\n .then(() =>\n runner.stop({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n }),\n )\n .catch(() => false);\n };\n const abortCanonicalRun = (): void => {\n try {\n args.agent.abortRun();\n } catch {\n // The exact runner stop remains the authoritative cancellation path.\n }\n stopCanonicalRun();\n };\n args.signal?.addEventListener(\"abort\", abortCanonicalRun, { once: true });\n heartbeatTimer = setInterval(() => {\n intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: lockTtlSeconds,\n ...(lockKeyPrefix !== undefined ? { lockKeyPrefix } : {}),\n })\n .catch((error: unknown) => {\n if (heartbeatTimer === undefined) return;\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n heartbeatError = error;\n try {\n args.agent.abortRun();\n } catch {\n // The runner stop below remains the authoritative cancellation path.\n }\n stopCanonicalRun();\n });\n }, lockHeartbeatIntervalSeconds * 1_000);\n heartbeatTimer.unref?.();\n\n try {\n await new Promise<void>((resolve, reject) => {\n let terminalError: (Error & { code?: string }) | undefined;\n const stream = runner.run({\n threadId: canonicalThreadId,\n agent: outer,\n input: {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n messages: args.agent.messages,\n state: args.agent.state,\n tools: [...args.tools],\n context: [...args.context],\n forwardedProps: undefined,\n },\n persistedInputMessages: args.persistedInputMessages,\n });\n stream.subscribe({\n next: (event: BaseEvent) => {\n if (event.type !== EventType.RUN_ERROR || terminalError) return;\n const message =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Canonical Channel agent run failed\";\n terminalError = new Error(message);\n terminalError.name = \"ChannelCanonicalRunError\";\n if (\n \"code\" in event &&\n typeof event.code === \"string\" &&\n event.code.length > 0\n ) {\n terminalError.code = event.code;\n }\n },\n error: reject,\n complete: () => {\n if (terminalError) {\n reject(terminalError);\n } else {\n resolve();\n }\n },\n });\n if (args.signal?.aborted) {\n abortCanonicalRun();\n }\n });\n } finally {\n args.signal?.removeEventListener(\"abort\", abortCanonicalRun);\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n // Always release the product thread lock from the Runtime side. Gateway\n // may also release on terminal AG-UI ingestion; cleanup is idempotent and\n // covers runner paths that never stream terminal events (or lose them).\n await intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n })\n .catch(() => undefined);\n }\n\n if (heartbeatError !== undefined) {\n await stopPromise;\n throw heartbeatError;\n }\n return result;\n}\n\n/** Convert canonical Intelligence history into AG-UI messages. */\nasync function toAgentMessage(\n message: {\n id: string;\n role: string;\n activityType?: string;\n content?: unknown;\n toolCalls?: Array<{ id: string; name: string; args: string }>;\n toolCallId?: string;\n },\n intelligence: CopilotKitIntelligence,\n): Promise<Message> {\n const content = await hydrateManagedContent(message.content, intelligence);\n return {\n id: message.id,\n role: message.role as Message[\"role\"],\n content: content ?? \"\",\n ...(message.activityType ? { activityType: message.activityType } : {}),\n ...(message.toolCalls\n ? {\n toolCalls: message.toolCalls.map((call) => ({\n id: call.id,\n type: \"function\" as const,\n function: { name: call.name, arguments: call.args },\n })),\n }\n : {}),\n ...(message.toolCallId ? { toolCallId: message.toolCallId } : {}),\n } as Message;\n}\n\n/** Resolves managed asset references only at the authorized Runtime boundary. */\nasync function hydrateManagedContent(\n content: unknown,\n intelligence: CopilotKitIntelligence,\n): Promise<unknown> {\n if (Array.isArray(content)) {\n return Promise.all(\n content.map(async (part) => {\n if (\n typeof part !== \"object\" ||\n part === null ||\n !(\"source\" in part) ||\n typeof part.source !== \"object\" ||\n part.source === null ||\n !(\"value\" in part.source) ||\n typeof part.source.value !== \"string\" ||\n !part.source.value.startsWith(\"cpki-asset://\")\n ) {\n return part;\n }\n const assetId = part.source.value.slice(\"cpki-asset://\".length);\n const asset = await intelligence.ɵgetManagedChannelAsset(assetId);\n return {\n ...part,\n source: {\n type: \"data\",\n value: Buffer.from(asset.bytes).toString(\"base64\"),\n mimeType:\n asset.mimeType ??\n (\"mimeType\" in part.source &&\n typeof part.source.mimeType === \"string\"\n ? part.source.mimeType\n : \"application/octet-stream\"),\n },\n };\n }),\n );\n }\n\n if (\n typeof content === \"object\" &&\n content !== null &&\n \"assetId\" in content &&\n typeof content.assetId === \"string\"\n ) {\n const asset = await intelligence.ɵgetManagedChannelAsset(content.assetId);\n return {\n ...content,\n source: {\n type: \"data\",\n value: Buffer.from(asset.bytes).toString(\"base64\"),\n mimeType:\n asset.mimeType ??\n (\"mimeType\" in content && typeof content.mimeType === \"string\"\n ? content.mimeType\n : \"application/octet-stream\"),\n },\n };\n }\n\n return content;\n}\n\n/** Whether `err` signals a missing managed provider rather than a hard failure. */\nfunction isSetupRequired(err: unknown): boolean {\n return (\n err instanceof ChannelSetupRequiredError ||\n (typeof err === \"object\" &&\n err !== null &&\n (err as { code?: unknown }).code === \"SETUP_REQUIRED\")\n );\n}\n\n/**\n * Whether `err` is a Node/runtime module-resolution failure — i.e. the error\n * a dynamic `import()` throws when the target package is not installed.\n * Exported so the friendly-error path in {@link defaultActivateChannel} can be\n * unit-tested without forcing a real failing import.\n */\nexport function isModuleNotFound(err: unknown): boolean {\n if (typeof err !== \"object\" || err === null) {\n return false;\n }\n const code = (err as { code?: unknown }).code;\n return code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n}\n\n/** Default deadline (ms) for a single `handle.stop()` during teardown. */\nconst DEFAULT_STOP_HANDLE_TIMEOUT_MS = 5_000;\n\n/** Default cadence (ms) for the \"still down\" log while a session is dropped. */\nconst DEFAULT_RECONNECT_LOG_INTERVAL_MS = 30_000;\n\n/**\n * Reject with `timeoutMessage` after `timeoutMs` if `inner` has not settled,\n * otherwise pass `inner` through. When `timeoutMs` is undefined, `inner` is\n * returned unchanged. The timer is `unref`'d so a pending deadline never keeps\n * the process alive, and `inner` always has a settle handler attached, so a\n * timed-out promise that later settles never surfaces as unhandled.\n */\nfunction withTimeout<T>(\n inner: Promise<T>,\n timeoutMs: number | undefined,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs === undefined) {\n return inner;\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(timeoutMessage)),\n timeoutMs,\n );\n (timer as unknown as { unref?: () => void }).unref?.();\n inner.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\n/**\n * Drives Channel activation for an Intelligence runtime: lazily activates each\n * declared Channel through the managed engine, tracks per-Channel lifecycle\n * status, exposes readiness, and tears everything down. Existing direct\n * adapters remain on the Channel; the launcher attaches the one managed\n * adapter before starting the combined adapter array.\n *\n * Activation is lazy and idempotent — constructing the manager does nothing;\n * {@link activate} starts it and a second call is a no-op. Activation throws\n * SYNCHRONOUSLY (a {@link ChannelConfigError}) only for a misconfiguration it\n * can detect up front — a duplicate or missing Channel name. Every OTHER\n * activation failure is recorded as the Channel's status (`error`, or\n * `setup_required` for a missing provider) and surfaced through {@link status}\n * and {@link ready} rather than thrown.\n *\n * Reconnection is NOT handled here — it is delegated to the Phoenix connection\n * layer that backs the launcher. When a managed control socket drops, Phoenix's\n * `Socket` reconnects and rejoins with the same Runtime declaration. Active\n * deliveries request fresh one-use join tokens through that control link. A\n * re-activation here would be both redundant AND broken: re-invoking the engine\n * on an already-started `Channel` throws in `channel.addAdapter` (started=true).\n * The manager therefore never re-activates on a drop.\n *\n * It DOES, however, reflect real connection health through the session's\n * `onStateChange` observer so {@link ChannelManager.status} stays honest rather\n * than reporting `online` forever after a drop: a drop moves the Channel to\n * `reconnecting`, a successful rejoin restores `online`, and a bounded give-up\n * (Phoenix would otherwise retry forever) moves it to `error`.\n */\nexport class ChannelManager implements ChannelsControl {\n private readonly intelligence: CopilotKitIntelligence;\n private readonly runner?: AgentRunner;\n private readonly lockTtlSeconds: number;\n private readonly lockHeartbeatIntervalSeconds: number;\n private readonly lockKeyPrefix?: string;\n private readonly channels: Channel[];\n private readonly activateChannel: ActivateChannelEngine;\n private readonly mintRuntimeInstanceId: () => string;\n private readonly log?: (msg: string, meta?: unknown) => void;\n private readonly stopHandleTimeoutMs: number;\n private readonly reconnectLogIntervalMs: number;\n\n private readonly entries = new Map<string, ChannelEntry>();\n private activated = false;\n private stopped = false;\n\n /** @param args - See {@link ChannelManagerArgs}. */\n constructor(args: ChannelManagerArgs) {\n this.intelligence = args.intelligence;\n this.runner = args.runner;\n this.lockTtlSeconds = args.lockTtlSeconds ?? 20;\n this.lockHeartbeatIntervalSeconds = args.lockHeartbeatIntervalSeconds ?? 15;\n this.lockKeyPrefix = args.lockKeyPrefix;\n this.channels = args.channels;\n this.log = args.log;\n // When using the default engine, forward the manager's log DOWN to the\n // launcher/transport (via defaultActivateChannel's log param) so a\n // transport-level drop is observable in the managed path. `this.log` is read\n // lazily at activation time, so this closure always sees the assigned sink.\n this.activateChannel =\n args.activateChannel ??\n ((config, channel) =>\n defaultActivateChannel(\n config,\n channel,\n undefined,\n this.log,\n this.runner\n ? {\n runner: this.runner,\n intelligence: this.intelligence,\n lockTtlSeconds: this.lockTtlSeconds,\n lockHeartbeatIntervalSeconds: this.lockHeartbeatIntervalSeconds,\n ...(this.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: this.lockKeyPrefix }\n : {}),\n }\n : undefined,\n ));\n this.mintRuntimeInstanceId =\n args.mintRuntimeInstanceId ??\n (() => `rti_${randomUUID().replace(/-/g, \"\")}`);\n this.stopHandleTimeoutMs =\n args.stopHandleTimeoutMs ?? DEFAULT_STOP_HANDLE_TIMEOUT_MS;\n this.reconnectLogIntervalMs =\n args.reconnectLogIntervalMs ?? DEFAULT_RECONNECT_LOG_INTERVAL_MS;\n }\n\n /**\n * Start activation of every declared Channel (lazy + idempotent). Mints a\n * distinct runtime instance id per Channel, derives its activation config,\n * and calls the engine. Records each Channel as `connecting`, transitioning\n * to `online`/`setup_required`/`error` as its activation settles.\n */\n activate(): void {\n // Short-circuit on BOTH latches: `activated` makes activation idempotent,\n // and `stopped` prevents a post-`stop()` activate() from opening transports\n // on a dead manager. (A late activation self-heals via the post-settle guard,\n // but never starting it is cheaper and clearer.)\n if (this.activated || this.stopped) {\n return;\n }\n // Reject duplicate Channel names BEFORE kicking off any engine call. The\n // manager keys `entries` by name, so a duplicate would let the second\n // activation's entry silently overwrite the first — leaking the first\n // Channel's control link out of status()/ready()/stop(). Fail loud here so\n // nothing is ever activated in that state.\n this.assertUniqueChannelNames();\n this.activated = true;\n\n // Every declared Channel gets the managed adapter. Any developer-supplied\n // direct adapters stay in the same adapter array and are started by the\n // launcher's single `channel.ɵruntime.start()` call.\n for (const channel of this.channels) {\n channel.ɵruntime.enableIntelligenceMemory();\n const name = channel.name!;\n const runtimeInstanceId = this.mintRuntimeInstanceId();\n\n let resolveSettled!: () => void;\n let rejectSettled!: (err: unknown) => void;\n const settled = new Promise<void>((resolve, reject) => {\n resolveSettled = resolve;\n rejectSettled = reject;\n });\n // ready() awaits `settled`; if nothing ever handles a rejection there,\n // Node reports an unhandled rejection. Attach a no-op catch so the\n // promise is always considered handled — ready() still sees the reason.\n settled.catch(() => {});\n\n // Invoke the engine synchronously so activation is observably started the\n // moment activate() returns (callers assert the engine was called and see\n // `connecting` before awaiting ready). A synchronous config/engine throw is\n // turned into a rejected activation so it becomes this channel's status\n // rather than throwing out of activate().\n let activation: Promise<ChannelsHandle>;\n let config: ChannelActivationConfig | undefined;\n try {\n config = deriveChannelActivationConfig({\n intelligence: this.intelligence,\n channel,\n runtimeInstanceId,\n });\n activation = this.activateChannel(config, channel);\n } catch (err) {\n activation = Promise.reject(err);\n }\n\n // The deferred `.then` callbacks capture `entry` and run only after the\n // literal has fully initialized, so referencing it here is safe.\n const entry: ChannelEntry = {\n status: \"connecting\",\n handle: undefined,\n handleStopped: false,\n settled,\n };\n\n // Anchor the settle handlers. Both branches route every teardown through\n // the idempotent `stopEntry`, so a late settle can never resurrect a\n // `stopped` entry and a handle is torn down at most once. The handlers\n // only mutate state (never throw), so the trailing no-op catch just keeps\n // the chain from surfacing as an unhandled rejection.\n activation\n .then(\n async (handle) => {\n entry.handle = handle;\n if (this.stopped) {\n // stop() ran before this activation settled, so it could not tear\n // down a handle that did not exist yet. Release it now (idempotent)\n // and keep the Channel `stopped`.\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n entry.status = \"online\";\n this.registerConnectionObserver(name, entry);\n resolveSettled();\n },\n async (err: unknown) => {\n if (this.stopped) {\n // A rejection that arrives AFTER stop() must NOT resurrect the\n // entry into `error`/`setup_required`: the Channel is already\n // being torn down. Keep it `stopped` and resolve `settled` so a\n // subsequent ready() does not reject on a stopped Channel.\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n if (isSetupRequired(err)) {\n const hasDirectAdapter = channel.adapters.some(\n (adapter) => !adapter.__intelligenceChannel,\n );\n if (hasDirectAdapter) {\n try {\n // Managed setup may be incomplete while a developer-owned\n // transport is fully configured. Keep that transport alive;\n // a later runtime restart can attach the managed adapter once\n // Intelligence setup is complete.\n await channel.ɵruntime.start();\n entry.handle = {\n metadata: {},\n stop: () => channel.ɵruntime.stop(),\n };\n if (this.stopped) {\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n } catch (directError) {\n if (this.stopped) {\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n entry.status = \"error\";\n this.log?.(\n `channel \"${name}\" failed to start its direct adapters while managed setup is incomplete`,\n directError,\n );\n rejectSettled(directError);\n return;\n }\n }\n entry.status = \"setup_required\";\n this.log?.(`channel \"${name}\" requires setup`, err);\n resolveSettled();\n } else {\n entry.status = \"error\";\n this.log?.(`channel \"${name}\" failed to activate`, err);\n rejectSettled(err);\n }\n },\n )\n .catch(() => {});\n\n this.entries.set(name, entry);\n }\n }\n\n /**\n * Throw if two declared Channels share a `name`. `entries` is keyed by name,\n * so a duplicate would overwrite the first Channel's entry and leak its live\n * session. Called at the very start of {@link activate}, before any engine\n * call, so a misconfiguration fails loud instead of silently.\n *\n * @throws {ChannelConfigError} If any Channel is missing a name, or if any\n * name appears more than once.\n */\n private assertUniqueChannelNames(): void {\n const seen = new Set<string>();\n for (const channel of this.channels) {\n const name = channel.name;\n // Check for a missing/empty name FIRST: `channel.name!` on a nameless\n // Channel keys as the string \"undefined\", which would otherwise report a\n // spurious duplicate for two nameless Channels before the accurate\n // missing-name error. Fail with the precise error instead.\n if (!name) {\n throw new ChannelConfigError(\n \"A managed Channel is missing a `name` — every declared Channel must \" +\n \"have a unique, non-empty name (pass createChannel({ name })).\",\n );\n }\n if (seen.has(name)) {\n throw new ChannelConfigError(\n `Duplicate managed Channel name \"${name}\" — every declared Channel ` +\n `must have a unique name.`,\n );\n }\n seen.add(name);\n }\n }\n\n /**\n * Resolve when every declared Channel has settled to\n * `online`/`setup_required` through its managed activation.\n *\n * Activates lazily if not already started — so a first call rejects with the\n * same {@link ChannelConfigError} as the synchronous throw from\n * {@link activate} for an up-front misconfiguration (duplicate/missing Channel\n * names). Once activation has been kicked off, all OTHER failures are surfaced\n * here instead: this rejects with an `AggregateError` if any Channel settled\n * to `error` OR — when `timeoutMs` is given — did not settle in time. The\n * `timeoutMs` deadline is applied PER CHANNEL, so the aggregate carries each\n * failed Channel's real reason AND a named timeout for each Channel still\n * hanging: a genuine activation error is never masked by a sibling that hangs\n * (a pre-fix set-wide timeout discarded the real reason in that case).\n *\n * A STOPPED manager short-circuits and resolves: a Channel that settled to\n * `error` BEFORE {@link stop} already rejected its `settled` promise, so\n * awaiting it here would throw an `AggregateError` even though\n * {@link status}.overall is `\"stopped\"` — inconsistent with the case where the\n * Channel was still online at stop() (which resolves). A stopped manager has\n * nothing left to be ready for, so resolve uniformly.\n *\n * `ready()` is ONE-SHOT: it settles on the INITIAL activation outcome. Later\n * connection-health transitions (a live Channel dropping to `reconnecting`, or\n * giving up to `error`) are reported through {@link status} — where `online`\n * means currently-sendable — but do NOT re-arm or re-reject an already-settled\n * `ready()`.\n */\n async ready(opts?: { timeoutMs?: number }): Promise<void> {\n if (this.stopped) {\n return;\n }\n this.activate();\n const entries = [...this.entries.entries()];\n // Apply `timeoutMs` PER CHANNEL rather than to the whole set. A single\n // set-wide timeout wrapping `allSettled` would, when one channel settles to\n // `error` while a sibling hangs, reject with only a generic timeout and\n // DISCARD the erroring channel's real reason. Timing out each channel's\n // `settled` independently lets `allSettled` collect BOTH a hung channel's\n // named timeout AND a failed channel's real error into one AggregateError.\n const results = await Promise.allSettled(\n entries.map(([name, e]) =>\n withTimeout(\n e.settled,\n opts?.timeoutMs,\n `channel \"${name}\" did not settle within ${opts?.timeoutMs}ms`,\n ),\n ),\n );\n const errors = results\n .filter((r): r is PromiseRejectedResult => r.status === \"rejected\")\n .map((r) => r.reason);\n if (errors.length > 0) {\n throw new AggregateError(\n errors,\n `ChannelManager.ready: ${errors.length} channel(s) failed to activate or settle in time`,\n );\n }\n }\n\n /**\n * Snapshot status. Every declared Channel appears keyed by name in\n * `channels` after its combined adapter lifecycle starts.\n *\n * `overall` is folded over ALL declared Channels (see {@link computeOverall}),\n * by precedence `error` > `reconnecting` > `setup_required` > `connecting` >\n * `online`. `online` means every Channel can currently send. `reconnecting`\n * outranks `setup_required` because a dropped-but-retrying Channel is an active\n * outage, louder than a steadily-degraded unprovisioned one. With no declared\n * Channels at all, `overall` is `online` (nothing\n * is degraded); once every Channel has been stopped, `overall` is `stopped`.\n */\n status(): {\n overall: ChannelStatus;\n channels: Record<string, ChannelStatus>;\n } {\n const channels: Record<string, ChannelStatus> = {};\n for (const [name, entry] of this.entries) {\n channels[name] = entry.status;\n }\n // A stopped manager is `stopped` regardless of whether it was ever activated.\n // stop() before activate() (e.g. SIGTERM during startup) leaves `entries`\n // empty, and the empty-set fold below returns `online` — a torn-down manager\n // must never read healthy. Short-circuit before that fold. (After a normal\n // activate→stop, every entry is already `stopped` and the fold agrees, so\n // this is also consistent with the populated case.)\n if (this.stopped) {\n return { overall: \"stopped\", channels };\n }\n // Before activate() has run, `entries` is empty. Folding an empty set gives\n // `online` — correct for a manager that declares NO channels (nothing is\n // degraded), but a LIE for one that declares channels and simply has not\n // opened its socket yet: activation is lazy (deferred to the first\n // `ready()`), so a not-yet-activated manager must never read `online`.\n // Report `connecting` (\"not started\") for that case so `status()` is honest\n // before any `ready()`.\n if (!this.activated && this.channels.length > 0) {\n return { overall: \"connecting\", channels };\n }\n return { overall: this.computeOverall(Object.values(channels)), channels };\n }\n\n /**\n * Fold per-Channel statuses into a single overall status (see {@link status}).\n *\n * Every declared Channel participates. Statuses are ranked\n * `error` > `reconnecting` > `setup_required` > `connecting` > `online`, so a\n * genuine failure still dominates a healthy sibling.\n * The empty-input case (no declared Channels at all) stays `online` (nothing is\n * degraded).\n */\n private computeOverall(values: ChannelStatus[]): ChannelStatus {\n if (values.length === 0) {\n return \"online\";\n }\n if (values.every((v) => v === \"stopped\")) {\n return \"stopped\";\n }\n if (values.includes(\"error\")) {\n return \"error\";\n }\n if (values.includes(\"reconnecting\")) {\n return \"reconnecting\";\n }\n if (values.includes(\"setup_required\")) {\n return \"setup_required\";\n }\n if (values.includes(\"connecting\")) {\n return \"connecting\";\n }\n return \"online\";\n }\n\n /**\n * Wire the Channel's connection-health observer (if the handle exposes the\n * optional `onStateChange` seam) so {@link ChannelManager.status} reflects real\n * health instead of reporting `online` forever after a drop:\n *\n * - `reconnecting` → status `reconnecting` (dropped, Phoenix retrying);\n * - `online` → status `online` (rejoined, sendable again);\n * - `gave_up` → status `error` (dead after the bounded reconnect window).\n *\n * Makes NO re-activation — reconnection is delegated to the Phoenix connection\n * layer (see {@link ChannelManager}), which auto-rejoins under the persistent\n * adapter. A STOPPED manager (or an already-stopped entry) ignores late\n * connection events, so a drop that fires after {@link ChannelManager.stop}\n * never resurrects the Channel out of `stopped`.\n *\n * @param name - The Channel name (map key).\n * @param entry - The Channel's activation entry.\n */\n private registerConnectionObserver(name: string, entry: ChannelEntry): void {\n entry.handle?.onStateChange?.((state, detail) => {\n // A stopped manager (or a stopped entry) ignores late connection events.\n if (this.stopped || entry.status === \"stopped\") {\n return;\n }\n const cause = detail?.reason ?? detail?.code;\n const because = cause !== undefined ? ` — ${cause}` : \"\";\n if (state === \"reconnecting\") {\n entry.status = \"reconnecting\";\n entry.downSince ??= Date.now();\n this.log?.(\n `channel \"${name}\" managed session dropped; reconnecting (Phoenix auto-rejoin)${because}`,\n );\n this.startReconnectLog(name, entry);\n } else if (state === \"online\") {\n entry.status = \"online\";\n this.clearReconnectLog(entry);\n entry.downSince = undefined;\n this.log?.(`channel \"${name}\" managed session back online`);\n } else if (state === \"gave_up\") {\n // `error` here means \"not sendable\", NOT \"dead\": Phoenix keeps retrying\n // underneath and a successful rejoin restores `online`. Say so, or the\n // line reads as terminal (OSS-670). The repeat keeps running.\n entry.status = \"error\";\n this.log?.(\n `channel \"${name}\" managed session gave up reconnecting after ${this.downFor(entry)}; ` +\n `marking error (still retrying — a successful rejoin restores online)${because}`,\n );\n }\n });\n }\n\n /** Rendered downtime for this outage episode (`\"45s\"`), or `\"unknown\"`. */\n private downFor(entry: ChannelEntry): string {\n return entry.downSince === undefined\n ? \"unknown\"\n : `${Math.round((Date.now() - entry.downSince) / 1000)}s`;\n }\n\n /**\n * Repeat a \"still down\" line for as long as this outage lasts. Runs THROUGH\n * `gave_up` on purpose: that transition is where the old behavior went quiet,\n * and an operator watching a silent process cannot tell a dead bot from an\n * idle one.\n */\n private startReconnectLog(name: string, entry: ChannelEntry): void {\n if (entry.reconnectLogTimer !== undefined) return;\n const timer = setInterval(() => {\n if (this.stopped || entry.status === \"stopped\") {\n this.clearReconnectLog(entry);\n return;\n }\n this.log?.(\n `channel \"${name}\" managed session still down after ${this.downFor(entry)}; Phoenix is retrying`,\n );\n }, this.reconnectLogIntervalMs);\n (timer as unknown as { unref?: () => void }).unref?.();\n entry.reconnectLogTimer = timer;\n }\n\n /** Stop this entry's \"still down\" repeat, if one is running. */\n private clearReconnectLog(entry: ChannelEntry): void {\n if (entry.reconnectLogTimer !== undefined) {\n clearInterval(entry.reconnectLogTimer);\n entry.reconnectLogTimer = undefined;\n }\n }\n\n /**\n * Drive a single entry to its terminal `stopped` state, tearing down its\n * handle AT MOST ONCE. Idempotent: it always sets `status = \"stopped\"`, and\n * only calls `handle.stop()` on the first invocation that sees a live,\n * not-yet-stopped handle (gated by {@link ChannelEntry.handleStopped}).\n *\n * This is the ONE guarded teardown path shared by both `stop()` and the\n * post-settle guard in {@link activate}. Because the\n * guard is per-entry and idempotent, a handle assigned in the same tick as\n * `stop()` is stopped exactly once even when both callers reach the entry, and a\n * late settle can never resurrect a `stopped` entry. The activation handle\n * releases the gateway session and stops the Channel's combined adapter array.\n *\n * `handle.stop()` failures are logged (via {@link ChannelManager.log}) but NOT\n * rethrown: the real launcher's `stop()` rethrows after `session.disconnect()`,\n * and teardown must still complete for every other entry. The call is wrapped\n * in `Promise.resolve().then(...)` so a foreign/injected handle whose `stop()`\n * throws SYNCHRONOUSLY (before any promise is created) is caught by the same\n * `.catch` — otherwise the sync throw would escape, skip `resolveSettled()` in\n * the fulfilled-then-stopped branch of {@link activate}, and hang `settled`.\n *\n * An entry with no handle yet (a still-`connecting` Channel whose transport has\n * not come up) is only marked `stopped`: there is nothing to tear down, and the\n * post-settle guard releases the transport if it arrives after `stop()`.\n *\n * A WEDGED `handle.stop()` (one that never settles) is bounded by\n * {@link ChannelManagerArgs.stopHandleTimeoutMs}: after the deadline the call\n * is logged and abandoned so it can't hang `stop()` — and thus SIGTERM\n * shutdown — forever.\n *\n * @param entry - The Channel entry to stop.\n */\n private async stopEntry(entry: ChannelEntry): Promise<void> {\n entry.status = \"stopped\";\n // An unref'd interval would not hold the process open, but a stopped\n // manager must not keep logging about a session it no longer owns.\n this.clearReconnectLog(entry);\n if (entry.handle && !entry.handleStopped) {\n entry.handleStopped = true;\n const handle = entry.handle;\n // Bound handle.stop(): a wedged stop() (e.g. a socket.disconnect that\n // never returns) must not hang teardown — and thus SIGTERM shutdown —\n // forever. On timeout, log and abandon it (the call keeps running with a\n // settle handler attached inside withTimeout, so it never surfaces as an\n // unhandled rejection) so every OTHER entry still reaches `stopped`. The\n // `Promise.resolve().then(...)` wrap also routes a SYNCHRONOUS throw from\n // a foreign handle through the same timeout+catch.\n await withTimeout(\n Promise.resolve().then(() => handle.stop()),\n this.stopHandleTimeoutMs,\n `channel handle stop() timed out after ${this.stopHandleTimeoutMs}ms during teardown`,\n ).catch((err: unknown) =>\n this.log?.(\"channel handle stop() failed during teardown\", err),\n );\n }\n }\n\n /**\n * Stop every activated Channel exactly once and mark all statuses `stopped`.\n * Idempotent — a second call is a no-op.\n *\n * Resolves promptly: {@link stopEntry} stops only the handles that already\n * exist and never blocks on activations that have not settled. A hung connect\n * (which `ready({ timeoutMs })` tolerates) has no handle to stop yet, and\n * awaiting it here would hang teardown — and thus SIGTERM shutdown — forever.\n * Any handle that arrives after this point is torn down by the post-settle\n * guard in {@link activate}, which routes through the same idempotent\n * {@link stopEntry}, so nothing leaks and nothing double-stops.\n *\n * Teardown is resilient to a throwing `handle.stop()`: `Promise.allSettled`\n * over the per-entry `stopEntry` calls guarantees one rejection can't abort\n * the rest, so every entry reaches `stopped` and `stop()` always resolves.\n * It is equally resilient to a WEDGED `handle.stop()` that never settles: each\n * is bounded by {@link ChannelManagerArgs.stopHandleTimeoutMs} inside\n * {@link stopEntry}, so a single hung handle can't hang SIGTERM shutdown.\n */\n async stop(): Promise<void> {\n if (this.stopped) {\n return;\n }\n this.stopped = true;\n\n const entries = [...this.entries.values()];\n await Promise.allSettled(entries.map((entry) => this.stopEntry(entry)));\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"channel-manager.cjs","names":["MCPMiddleware","INTELLIGENCE_MEMORY_GRANT_HEADER","INTELLIGENCE_USER_ID_HEADER","AbstractAgent","EMPTY","EventType","deriveChannelActivationConfig","ChannelConfigError"],"sources":["../../../../src/v2/runtime/core/channel-manager.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport {\n ChannelConfigError,\n deriveChannelActivationConfig,\n} from \"./channel-activation-config\";\nimport type { ChannelActivationConfig } from \"./channel-activation-config\";\nimport type { CopilotKitIntelligence } from \"../intelligence-platform\";\nimport { AbstractAgent, EventType } from \"@ag-ui/client\";\nimport type {\n AgentSubscriber,\n BaseEvent,\n Message,\n RunAgentParameters,\n RunAgentResult,\n} from \"@ag-ui/client\";\nimport { EMPTY } from \"rxjs\";\nimport { MCPMiddleware } from \"@ag-ui/mcp-middleware\";\nimport type { AgentRunner } from \"../runner/agent-runner\";\nimport {\n INTELLIGENCE_MEMORY_GRANT_HEADER,\n INTELLIGENCE_USER_ID_HEADER,\n} from \"../intelligence-platform/client\";\n// Type-only: @copilotkit/channels is pure-ESM, so a value import would break this\n// package's CJS output (see `core/runtime.ts` and `channel-activation-config.ts`\n// for the same constraint).\nimport type {\n Channel,\n ReplyContinuationOptions,\n ResolvedChannelMemory,\n} from \"@copilotkit/channels\";\n\n/**\n * Lifecycle status of a single Channel activation, or of the manager overall.\n *\n * - `connecting`: activation in flight, not yet settled.\n * - `online`: activation resolved AND the managed session can currently send.\n * A drop moves the Channel to `reconnecting` (not `online`); a successful\n * rejoin restores `online`.\n * - `setup_required`: the Channel is declared but has no managed provider yet —\n * a valid degraded state, not a failure.\n * - `reconnecting`: the managed session dropped and Phoenix is retrying — not\n * currently sendable. The manager does NOT re-activate (reconnection is\n * delegated to the Phoenix connection layer); it only reflects the health the\n * session reports via its `onStateChange` observer.\n * - `stopped`: {@link ChannelManager.stop} has torn the Channel down.\n * - `error`: activation rejected with a non-setup error, or a previously-online\n * control link gave up reconnecting after its bounded reconnect window.\n *\n * A Channel may carry developer-supplied direct adapters alongside the managed\n * Intelligence adapter. The managed engine owns the shared Channel lifecycle;\n * each adapter still receives only its own ingress and sends only its own\n * provider output.\n */\nexport type ChannelStatus =\n | \"connecting\"\n | \"online\"\n | \"setup_required\"\n | \"reconnecting\"\n | \"stopped\"\n | \"error\";\n\n/**\n * The lifecycle control surface a Channel host uses to drive and observe\n * managed Channel activation.\n */\nexport interface ChannelsControl {\n /**\n * Resolve once every declared Channel has settled to a terminal, non-connecting\n * state (`online` or `setup_required`). Rejects if any Channel is in `error`,\n * or — when `timeoutMs` is given — if the whole set has not settled in time.\n */\n ready(opts?: { timeoutMs?: number }): Promise<void>;\n /** Snapshot the overall status and the per-Channel status map. */\n status(): { overall: ChannelStatus; channels: Record<string, ChannelStatus> };\n /** Tear down every activated Channel. Idempotent. */\n stop(): Promise<void>;\n}\n\n/**\n * Signals that a declared Channel cannot be activated because no managed\n * provider exists for it yet. The engine throws this (or any error whose\n * `code === \"SETUP_REQUIRED\"`) to move a Channel to `setup_required` rather\n * than `error` — a declared-but-unprovisioned Channel is a valid degraded\n * state, not a failure.\n */\nexport class ChannelSetupRequiredError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ChannelSetupRequiredError\";\n }\n}\n\n/**\n * The activation engine: given a resolved {@link ChannelActivationConfig} and\n * the declared {@link Channel}, bring the Channel online and return its handle.\n * Injected in tests (a fake engine); defaults to the Realtime Gateway launcher.\n */\nexport type ActivateChannelEngine = (\n config: ChannelActivationConfig,\n channel: Channel,\n) => Promise<ChannelsHandle>;\n\n/**\n * Minimal structural view of the `@copilotkit/channels-intelligence`\n * `ChannelsHandle`. Declared locally (not imported) because the runtime is a\n * CJS package that must not take a static dependency on the pure-ESM\n * channels-intelligence package — the default engine reaches its launcher\n * through a dynamic `import()` instead. The manager only ever needs `stop()`.\n */\nexport interface ChannelsHandle {\n /** Activation metadata declared to Intelligence. Unused by the manager. */\n metadata: unknown;\n /** Stop the underlying Channel(s) and release transports. */\n stop(): Promise<void>;\n /**\n * Optional seam: register a callback the handle fires when its managed\n * session drops. Retained as a per-episode drop breadcrumb; the manager drives\n * status from {@link ChannelsHandle.onStateChange} instead. Present on the\n * Realtime Gateway launcher handle; optional for non-gateway/test handles.\n */\n onClose?(cb: () => void): void;\n /**\n * Optional seam: register a connection-health observer the handle fires as its\n * managed session moves between `online` (sendable), `reconnecting` (dropped,\n * Phoenix retrying), and `gave_up` (dead after the bounded reconnect window).\n * The manager uses this to keep {@link ChannelManager.status} honest — it does\n * NOT re-activate on a drop (reconnection is delegated to the Phoenix\n * connection layer; see {@link ChannelManager}). Optional so non-gateway or\n * test handles that do not implement it are always invoked as\n * `handle.onStateChange?.(cb)`.\n */\n onStateChange?(\n cb: (\n state: \"online\" | \"reconnecting\" | \"gave_up\",\n detail?: { reason?: string; code?: string },\n ) => void,\n ): void;\n}\n\n/** Constructor arguments for {@link ChannelManager}. */\nexport interface ChannelManagerArgs {\n /** The Intelligence runtime client the activation config is derived from. */\n intelligence: CopilotKitIntelligence;\n /** The declared framework Channels to activate. */\n channels: Channel[];\n /** Standard runtime AgentRunner used by managed Channel executions. */\n runner?: AgentRunner;\n /** Standard thread-lock TTL forwarded to Channel AgentRunner heartbeats. */\n lockTtlSeconds?: number;\n /** Standard thread-lock heartbeat cadence used by Channel AgentRunner calls. */\n lockHeartbeatIntervalSeconds?: number;\n /** Must match web Intelligence runs so channel + HTTP share the same lock key. */\n lockKeyPrefix?: string;\n /**\n * Activation engine. Defaults to a wrapper over the channels-intelligence\n * Realtime Gateway launcher (`startChannelsOverRealtimeGateway`), reached via\n * dynamic import so this CJS package keeps no static ESM dependency.\n */\n activateChannel?: ActivateChannelEngine;\n /** Mint a runtime instance id per Channel. Defaults to `rti_{uuid-no-dashes}`. */\n mintRuntimeInstanceId?: () => string;\n /** Diagnostic sink. Forwarded to the launcher/transport when the default\n * activation engine is used, so transport-level drops surface in the managed\n * path (not just activation-level events). */\n log?: (msg: string, meta?: unknown) => void;\n /**\n * Initial delay (ms) before a \"still down\" log while a managed session is\n * disconnected. Later reminders back off exponentially to a 15-minute cap,\n * keeping a prolonged outage visible without flooding logs. Injectable so\n * tests can use a shorter first delay. Default 30000.\n */\n reconnectLogIntervalMs?: number;\n /** Per-handle deadline (ms) for `handle.stop()` during {@link ChannelManager.stop}\n * so a wedged stop can't hang SIGTERM shutdown. Default 5000. */\n stopHandleTimeoutMs?: number;\n}\n\n/** Per-Channel mutable activation entry tracked by the manager. */\ninterface ChannelEntry {\n status: ChannelStatus;\n /** Resolves on `online`/`setup_required`; rejects on `error`. Awaited by `ready`. */\n readonly settled: Promise<void>;\n handle?: ChannelsHandle;\n /**\n * Whether {@link ChannelManager.stopEntry} has already stopped `handle`. Gates\n * the single-stop guarantee: the success settle handler and `stop()` can both\n * reach the same entry in the same tick, but the handle is torn down at most\n * once.\n */\n handleStopped: boolean;\n /** Epoch ms this outage episode began; unset while the session is healthy. */\n downSince?: number;\n /** Next \"still down\" logger for this outage; cleared on recovery/teardown. */\n reconnectLogTimer?: ReturnType<typeof setTimeout>;\n /** Delay before the next reminder; doubles after each emitted reminder. */\n reconnectLogDelayMs?: number;\n /** Next retry after a transient initial activation failure. */\n activationRetryTimer?: ReturnType<typeof setTimeout>;\n /** Delay before the next activation retry; doubles after each failed attempt. */\n activationRetryDelayMs?: number;\n /** Reject the retry wrapper when teardown cancels a pending retry. */\n cancelActivationRetry?: () => void;\n}\n\n/**\n * Runtime installs this pure-ESM package as a direct dependency, but the\n * specifier must stay non-literal so it never becomes a static dependency of\n * the runtime's CJS build. The packed-consumer contract is enforced by\n * `scripts/release/verify-runtime-package.ts`.\n */\nconst CHANNELS_INTELLIGENCE_SPECIFIER = \"@copilotkit/channels-intelligence\";\n\n/**\n * Structural view of the `@copilotkit/channels-intelligence` module surface the\n * default engine consumes. Declared locally (not imported) for the same\n * CJS/ESM-boundary reason the {@link ChannelsHandle} view is.\n */\nexport interface ChannelsIntelligenceModule {\n startChannelsOverRealtimeGateway: (\n channels: Channel[],\n opts: {\n wsUrl: string;\n apiKey: string;\n scope: { projectId: number; channelName: string };\n runtimeInstanceId: string;\n /** Optional per-Channel override for managed tool-call visibility. */\n showToolStatus?: boolean;\n /** Optional per-Channel tuning for continuation messages on long replies. */\n replyContinuation?: ReplyContinuationOptions;\n /** Intelligence app-api HTTP base URL, forwarded to the transport so the\n * managed realtime path enables file/history parity (HTTP-only) — OSS-476. */\n appApiBaseUrl?: string;\n /** Diagnostic sink forwarded to the launcher/transport so transport-level\n * drop diagnostics (e.g. a version-skew missing-leaseToken outage) are not\n * silent in the managed path. */\n log?: (msg: string, meta?: unknown) => void;\n runCanonical(args: {\n agent: AbstractAgent;\n deliveryId: string;\n signal?: AbortSignal;\n threadId: string;\n runId: string;\n userId: string;\n agentId: string;\n tools: readonly {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }[];\n context: readonly { description: string; value: string }[];\n persistedInputMessages: Message[];\n execute(\n subscriber: AgentSubscriber,\n canonicalRun?: { threadId: string; runId: string },\n ): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n }): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n loadHistory(args: {\n deliveryId: string;\n threadId: string;\n appUserId: string;\n }): Promise<Message[]>;\n },\n ) => Promise<ChannelsHandle>;\n}\n\n/**\n * Default engine: wrap the channels-intelligence Realtime Gateway launcher.\n *\n * The module is reached through an injectable importer that defaults to a\n * dynamic `import()` of a non-literal specifier, so the pure-ESM\n * `@copilotkit/channels-intelligence` never becomes a static dependency of this\n * CJS package (mirrors the runtime's other channels seams). The `import`\n * seam is a parameter purely so this function's config→opts mapping and its\n * module-not-found / generic-error branches are unit-testable WITHOUT the real\n * package installed; production always uses the default importer.\n *\n * Passes NO `org`/`channelId` — the launcher's realtime scope treats them as\n * optional.\n *\n * @param config - Resolved activation config for the Channel.\n * @param channel - The Channel to activate.\n * @param importChannelsIntelligence - Test seam; loads the channels-intelligence\n * module. Defaults to a dynamic import of the real package.\n * @param log - Optional diagnostic sink forwarded to the launcher/transport so\n * transport-level drop diagnostics are not silent in the managed path.\n * @returns The launcher's {@link ChannelsHandle}.\n */\nexport async function defaultActivateChannel(\n config: ChannelActivationConfig,\n channel: Channel,\n importChannelsIntelligence: () => Promise<ChannelsIntelligenceModule> = () =>\n import(\n CHANNELS_INTELLIGENCE_SPECIFIER\n ) as Promise<ChannelsIntelligenceModule>,\n log?: (msg: string, meta?: unknown) => void,\n services?: {\n runner: AgentRunner;\n intelligence: CopilotKitIntelligence;\n lockTtlSeconds?: number;\n lockHeartbeatIntervalSeconds?: number;\n lockKeyPrefix?: string;\n },\n): Promise<ChannelsHandle> {\n let mod: ChannelsIntelligenceModule;\n try {\n mod = await importChannelsIntelligence();\n } catch (err) {\n if (isModuleNotFound(err)) {\n throw new Error(\n \"Managed Channels require '@copilotkit/channels-intelligence' to be installed. Add it to your app's dependencies.\",\n { cause: err },\n );\n }\n throw err;\n }\n if (!services) {\n throw new Error(\n \"Managed Channels require the runtime AgentRunner and Intelligence client\",\n );\n }\n return mod.startChannelsOverRealtimeGateway([channel], {\n wsUrl: config.wsUrl,\n apiKey: config.apiKey,\n scope: { projectId: config.projectId, channelName: config.channelName },\n runtimeInstanceId: config.runtimeInstanceId,\n ...(config.showToolStatus !== undefined\n ? { showToolStatus: config.showToolStatus }\n : {}),\n ...(config.replyContinuation !== undefined\n ? { replyContinuation: config.replyContinuation }\n : {}),\n // Forward the app-api HTTP base URL so the transport wires file/history\n // (HTTP-only) on the NORMAL managed path — without this, Channels started by\n // the CopilotRuntime handler run with no history/file support (OSS-476).\n appApiBaseUrl: config.apiUrl,\n // Forward the manager's diagnostic sink down to the launcher/transport so a\n // transport-level drop (e.g. a version-skew missing-leaseToken outage) is\n // observable in the managed path, not just activation-level events.\n ...(log ? { log } : {}),\n runCanonical: (args) =>\n runCanonicalChannelAgent(\n services.runner,\n services.intelligence,\n services.lockTtlSeconds ?? 20,\n services.lockHeartbeatIntervalSeconds ?? 15,\n args,\n services.lockKeyPrefix,\n ),\n loadHistory: async ({ deliveryId, threadId, appUserId }) => {\n const history = await services.intelligence.getThreadMessages({\n threadId,\n userId: appUserId,\n channelDeliveryId: deliveryId,\n });\n return Promise.all(\n history.messages.map((message) =>\n toAgentMessage(message, services.intelligence),\n ),\n );\n },\n });\n}\n\ninterface CanonicalRunArgs {\n agent: AbstractAgent;\n deliveryId: string;\n signal?: AbortSignal;\n threadId: string;\n runId: string;\n userId: string;\n memory?: ResolvedChannelMemory;\n agentId: string;\n tools: readonly {\n name: string;\n description: string;\n parameters: Record<string, unknown>;\n }[];\n context: readonly { description: string; value: string }[];\n persistedInputMessages: Message[];\n execute(\n subscriber: AgentSubscriber,\n canonicalRun?: { threadId: string; runId: string },\n ): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n }>;\n}\n\n/** Attach grant-scoped Intelligence Memory tools to one isolated Channel agent. */\nexport function attachChannelMemory(\n agent: AbstractAgent,\n intelligence: CopilotKitIntelligence,\n memory: ResolvedChannelMemory | undefined,\n): void {\n if (!memory) return;\n const middlewareAgent = agent as AbstractAgent & {\n use?: (middleware: unknown) => void;\n };\n if (typeof middlewareAgent.use !== \"function\") {\n const error = new Error(\n \"Channel Memory requires an agent with middleware support\",\n ) as Error & { code?: string };\n error.name = \"ChannelMemoryAgentUnsupportedError\";\n error.code = \"channel_memory_agent_unsupported\";\n throw error;\n }\n middlewareAgent.use(\n new MCPMiddleware([\n {\n type: \"http\",\n url: `${intelligence.ɵgetApiUrl()}/mcp`,\n serverId: \"intelligence\",\n headers: {\n Authorization: `Bearer ${intelligence.ɵgetApiKey()}`,\n [INTELLIGENCE_MEMORY_GRANT_HEADER]: JSON.stringify(memory.grant),\n ...(memory.user\n ? { [INTELLIGENCE_USER_ID_HEADER]: memory.user.id }\n : {}),\n },\n },\n ]),\n );\n}\n\n/** One outer agent that lets the standard runner own the whole local tool loop. */\nclass ChannelOuterAgent extends AbstractAgent {\n constructor(\n private readonly inner: AbstractAgent,\n private readonly canonicalThreadId: string,\n private readonly executeLoop: CanonicalRunArgs[\"execute\"],\n ) {\n super({\n threadId: inner.threadId,\n initialMessages: inner.messages,\n initialState: inner.state,\n ...(inner.agentId ? { agentId: inner.agentId } : {}),\n });\n }\n\n run(): ReturnType<AbstractAgent[\"run\"]> {\n return EMPTY;\n }\n\n override async runAgent(\n parameters?: RunAgentParameters,\n subscriber?: AgentSubscriber,\n ): Promise<RunAgentResult> {\n if (!parameters?.runId) {\n throw new Error(\"Canonical Channel run requires a runId\");\n }\n const result = await this.executeLoop(subscriber ?? {}, {\n threadId: this.canonicalThreadId,\n runId: parameters.runId,\n });\n return { result, newMessages: [] };\n }\n\n override abortRun(): void {\n this.inner.abortRun();\n }\n}\n\n/** Drive one public Channel run through the runtime's existing AgentRunner. */\nasync function runCanonicalChannelAgent(\n runner: AgentRunner,\n intelligence: CopilotKitIntelligence,\n lockTtlSeconds: number,\n lockHeartbeatIntervalSeconds: number,\n args: CanonicalRunArgs,\n lockKeyPrefix?: string,\n): Promise<{\n iterations: number;\n interrupted: boolean;\n deliveryError?: unknown;\n}> {\n const lock = await intelligence.ɵacquireThreadLock({\n threadId: args.threadId,\n runId: args.runId,\n userId: args.userId,\n agentId: args.agentId,\n channelDeliveryId: args.deliveryId,\n ttlSeconds: lockTtlSeconds,\n ...(lockKeyPrefix !== undefined ? { lockKeyPrefix } : {}),\n });\n const canonicalThreadId = lock.threadId;\n const canonicalRunId = lock.runId;\n let result = { iterations: 0, interrupted: false };\n attachChannelMemory(args.agent, intelligence, args.memory);\n const outer = new ChannelOuterAgent(\n args.agent,\n canonicalThreadId,\n async (subscriber, canonicalRun) => {\n result = await args.execute(subscriber, canonicalRun);\n return result;\n },\n );\n let stopPromise: Promise<boolean | undefined> | undefined;\n let heartbeatError: unknown;\n let heartbeatTimer: ReturnType<typeof setInterval> | undefined;\n const stopCanonicalRun = (): void => {\n stopPromise ??= Promise.resolve()\n .then(() =>\n runner.stop({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n }),\n )\n .catch(() => false);\n };\n const abortCanonicalRun = (): void => {\n try {\n args.agent.abortRun();\n } catch {\n // The exact runner stop remains the authoritative cancellation path.\n }\n stopCanonicalRun();\n };\n args.signal?.addEventListener(\"abort\", abortCanonicalRun, { once: true });\n heartbeatTimer = setInterval(() => {\n intelligence\n .ɵrenewThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n ttlSeconds: lockTtlSeconds,\n ...(lockKeyPrefix !== undefined ? { lockKeyPrefix } : {}),\n })\n .catch((error: unknown) => {\n if (heartbeatTimer === undefined) return;\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n heartbeatError = error;\n try {\n args.agent.abortRun();\n } catch {\n // The runner stop below remains the authoritative cancellation path.\n }\n stopCanonicalRun();\n });\n }, lockHeartbeatIntervalSeconds * 1_000);\n heartbeatTimer.unref?.();\n\n try {\n await new Promise<void>((resolve, reject) => {\n let terminalError: (Error & { code?: string }) | undefined;\n const stream = runner.run({\n threadId: canonicalThreadId,\n agent: outer,\n input: {\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n messages: args.agent.messages,\n state: args.agent.state,\n tools: [...args.tools],\n context: [...args.context],\n forwardedProps: undefined,\n },\n persistedInputMessages: args.persistedInputMessages,\n });\n stream.subscribe({\n next: (event: BaseEvent) => {\n if (event.type !== EventType.RUN_ERROR || terminalError) return;\n const message =\n \"message\" in event && typeof event.message === \"string\"\n ? event.message\n : \"Canonical Channel agent run failed\";\n terminalError = new Error(message);\n terminalError.name = \"ChannelCanonicalRunError\";\n if (\n \"code\" in event &&\n typeof event.code === \"string\" &&\n event.code.length > 0\n ) {\n terminalError.code = event.code;\n }\n },\n error: reject,\n complete: () => {\n if (terminalError) {\n reject(terminalError);\n } else {\n resolve();\n }\n },\n });\n if (args.signal?.aborted) {\n abortCanonicalRun();\n }\n });\n } finally {\n args.signal?.removeEventListener(\"abort\", abortCanonicalRun);\n if (heartbeatTimer !== undefined) {\n clearInterval(heartbeatTimer);\n heartbeatTimer = undefined;\n }\n // Always release the product thread lock from the Runtime side. Gateway\n // may also release on terminal AG-UI ingestion; cleanup is idempotent and\n // covers runner paths that never stream terminal events (or lose them).\n await intelligence\n .ɵcleanupThreadLock({\n threadId: canonicalThreadId,\n runId: canonicalRunId,\n })\n .catch(() => undefined);\n }\n\n if (heartbeatError !== undefined) {\n await stopPromise;\n throw heartbeatError;\n }\n return result;\n}\n\n/** Convert canonical Intelligence history into AG-UI messages. */\nasync function toAgentMessage(\n message: {\n id: string;\n role: string;\n activityType?: string;\n content?: unknown;\n toolCalls?: Array<{ id: string; name: string; args: string }>;\n toolCallId?: string;\n },\n intelligence: CopilotKitIntelligence,\n): Promise<Message> {\n const content = await hydrateManagedContent(message.content, intelligence);\n return {\n id: message.id,\n role: message.role as Message[\"role\"],\n content: content ?? \"\",\n ...(message.activityType ? { activityType: message.activityType } : {}),\n ...(message.toolCalls\n ? {\n toolCalls: message.toolCalls.map((call) => ({\n id: call.id,\n type: \"function\" as const,\n function: { name: call.name, arguments: call.args },\n })),\n }\n : {}),\n ...(message.toolCallId ? { toolCallId: message.toolCallId } : {}),\n } as Message;\n}\n\n/** Resolves managed asset references only at the authorized Runtime boundary. */\nasync function hydrateManagedContent(\n content: unknown,\n intelligence: CopilotKitIntelligence,\n): Promise<unknown> {\n if (Array.isArray(content)) {\n return Promise.all(\n content.map(async (part) => {\n if (\n typeof part !== \"object\" ||\n part === null ||\n !(\"source\" in part) ||\n typeof part.source !== \"object\" ||\n part.source === null ||\n !(\"value\" in part.source) ||\n typeof part.source.value !== \"string\" ||\n !part.source.value.startsWith(\"cpki-asset://\")\n ) {\n return part;\n }\n const assetId = part.source.value.slice(\"cpki-asset://\".length);\n const asset = await intelligence.ɵgetManagedChannelAsset(assetId);\n return {\n ...part,\n source: {\n type: \"data\",\n value: Buffer.from(asset.bytes).toString(\"base64\"),\n mimeType:\n asset.mimeType ??\n (\"mimeType\" in part.source &&\n typeof part.source.mimeType === \"string\"\n ? part.source.mimeType\n : \"application/octet-stream\"),\n },\n };\n }),\n );\n }\n\n if (\n typeof content === \"object\" &&\n content !== null &&\n \"assetId\" in content &&\n typeof content.assetId === \"string\"\n ) {\n const asset = await intelligence.ɵgetManagedChannelAsset(content.assetId);\n return {\n ...content,\n source: {\n type: \"data\",\n value: Buffer.from(asset.bytes).toString(\"base64\"),\n mimeType:\n asset.mimeType ??\n (\"mimeType\" in content && typeof content.mimeType === \"string\"\n ? content.mimeType\n : \"application/octet-stream\"),\n },\n };\n }\n\n return content;\n}\n\n/** Whether `err` signals a missing managed provider rather than a hard failure. */\nfunction isSetupRequired(err: unknown): boolean {\n return (\n err instanceof ChannelSetupRequiredError ||\n (typeof err === \"object\" &&\n err !== null &&\n (err as { code?: unknown }).code === \"SETUP_REQUIRED\")\n );\n}\n\n/** Whether a failed initial activation can recover without new configuration. */\nfunction isRetryableActivationError(err: unknown): boolean {\n if (typeof err !== \"object\" || err === null) {\n return false;\n }\n const value = err as { code?: unknown; retryable?: unknown };\n return (\n (value.code === \"GATEWAY_UNREACHABLE\" ||\n value.code === \"GATEWAY_JOIN_FAILED\") &&\n value.retryable === true\n );\n}\n\n/**\n * Whether `err` is a Node/runtime module-resolution failure — i.e. the error\n * a dynamic `import()` throws when the target package is not installed.\n * Exported so the friendly-error path in {@link defaultActivateChannel} can be\n * unit-tested without forcing a real failing import.\n */\nexport function isModuleNotFound(err: unknown): boolean {\n if (typeof err !== \"object\" || err === null) {\n return false;\n }\n const code = (err as { code?: unknown }).code;\n return code === \"ERR_MODULE_NOT_FOUND\" || code === \"MODULE_NOT_FOUND\";\n}\n\n/** Default deadline (ms) for a single `handle.stop()` during teardown. */\nconst DEFAULT_STOP_HANDLE_TIMEOUT_MS = 5_000;\n\n/** First delay (ms) before logging that a dropped session is still down. */\nconst DEFAULT_RECONNECT_LOG_INTERVAL_MS = 30_000;\n\n/** Longest delay (ms) between reminders during one continuous outage. */\nconst DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS = 15 * 60_000;\n\n/** First delay (ms) before retrying a transient initial activation failure. */\nconst DEFAULT_ACTIVATION_RETRY_DELAY_MS = 1_000;\n\n/** Longest delay (ms) between transient initial activation attempts. */\nconst DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS = 30_000;\n\n/**\n * Reject with `timeoutMessage` after `timeoutMs` if `inner` has not settled,\n * otherwise pass `inner` through. When `timeoutMs` is undefined, `inner` is\n * returned unchanged. The timer is `unref`'d so a pending deadline never keeps\n * the process alive, and `inner` always has a settle handler attached, so a\n * timed-out promise that later settles never surfaces as unhandled.\n */\nfunction withTimeout<T>(\n inner: Promise<T>,\n timeoutMs: number | undefined,\n timeoutMessage: string,\n): Promise<T> {\n if (timeoutMs === undefined) {\n return inner;\n }\n return new Promise<T>((resolve, reject) => {\n const timer = setTimeout(\n () => reject(new Error(timeoutMessage)),\n timeoutMs,\n );\n (timer as unknown as { unref?: () => void }).unref?.();\n inner.then(\n (value) => {\n clearTimeout(timer);\n resolve(value);\n },\n (err) => {\n clearTimeout(timer);\n reject(err);\n },\n );\n });\n}\n\n/**\n * Drives Channel activation for an Intelligence runtime: lazily activates each\n * declared Channel through the managed engine, tracks per-Channel lifecycle\n * status, exposes readiness, and tears everything down. Existing direct\n * adapters remain on the Channel; the launcher attaches the one managed\n * adapter before starting the combined adapter array.\n *\n * Activation is lazy and idempotent — constructing the manager does nothing;\n * {@link activate} starts it and a second call is a no-op. Activation throws\n * SYNCHRONOUSLY (a {@link ChannelConfigError}) only for a misconfiguration it\n * can detect up front — a duplicate or missing Channel name. Every OTHER\n * permanent activation failure is recorded as the Channel's status (`error`,\n * or `setup_required` for a missing provider) and surfaced through\n * {@link status} and {@link ready} rather than thrown. A retryable initial\n * gateway outage stays unsettled and retries until it connects or the manager\n * stops.\n *\n * Established-session reconnection is delegated to the Phoenix connection\n * layer that backs the launcher. When a managed control socket drops, Phoenix's\n * `Socket` reconnects and rejoins with the same Runtime declaration. The manager\n * never re-activates an already-started Channel. It does retry a transient\n * INITIAL gateway activation failure: that happens before the launcher adds or\n * starts the managed adapter, so a later attempt is safe.\n *\n * It DOES, however, reflect real connection health through the session's\n * `onStateChange` observer so {@link ChannelManager.status} stays honest rather\n * than reporting `online` forever after a drop: a drop moves the Channel to\n * `reconnecting`, a successful rejoin restores `online`, and a bounded give-up\n * (Phoenix would otherwise retry forever) moves it to `error`.\n */\nexport class ChannelManager implements ChannelsControl {\n private readonly intelligence: CopilotKitIntelligence;\n private readonly runner?: AgentRunner;\n private readonly lockTtlSeconds: number;\n private readonly lockHeartbeatIntervalSeconds: number;\n private readonly lockKeyPrefix?: string;\n private readonly channels: Channel[];\n private readonly activateChannel: ActivateChannelEngine;\n private readonly mintRuntimeInstanceId: () => string;\n private readonly log?: (msg: string, meta?: unknown) => void;\n private readonly stopHandleTimeoutMs: number;\n private readonly reconnectLogIntervalMs: number;\n\n private readonly entries = new Map<string, ChannelEntry>();\n private activated = false;\n private stopped = false;\n\n /** @param args - See {@link ChannelManagerArgs}. */\n constructor(args: ChannelManagerArgs) {\n this.intelligence = args.intelligence;\n this.runner = args.runner;\n this.lockTtlSeconds = args.lockTtlSeconds ?? 20;\n this.lockHeartbeatIntervalSeconds = args.lockHeartbeatIntervalSeconds ?? 15;\n this.lockKeyPrefix = args.lockKeyPrefix;\n this.channels = args.channels;\n this.log = args.log;\n // When using the default engine, forward the manager's log DOWN to the\n // launcher/transport (via defaultActivateChannel's log param) so a\n // transport-level drop is observable in the managed path. `this.log` is read\n // lazily at activation time, so this closure always sees the assigned sink.\n this.activateChannel =\n args.activateChannel ??\n ((config, channel) =>\n defaultActivateChannel(\n config,\n channel,\n undefined,\n this.log,\n this.runner\n ? {\n runner: this.runner,\n intelligence: this.intelligence,\n lockTtlSeconds: this.lockTtlSeconds,\n lockHeartbeatIntervalSeconds: this.lockHeartbeatIntervalSeconds,\n ...(this.lockKeyPrefix !== undefined\n ? { lockKeyPrefix: this.lockKeyPrefix }\n : {}),\n }\n : undefined,\n ));\n this.mintRuntimeInstanceId =\n args.mintRuntimeInstanceId ??\n (() => `rti_${randomUUID().replace(/-/g, \"\")}`);\n this.stopHandleTimeoutMs =\n args.stopHandleTimeoutMs ?? DEFAULT_STOP_HANDLE_TIMEOUT_MS;\n this.reconnectLogIntervalMs =\n args.reconnectLogIntervalMs ?? DEFAULT_RECONNECT_LOG_INTERVAL_MS;\n }\n\n /**\n * Start activation of every declared Channel (lazy + idempotent). Mints a\n * distinct runtime instance id per Channel, derives its activation config,\n * and calls the engine. Transient gateway failures retry with exponential\n * backoff; other outcomes transition to `online`/`setup_required`/`error`.\n */\n activate(): void {\n // Short-circuit on BOTH latches: `activated` makes activation idempotent,\n // and `stopped` prevents a post-`stop()` activate() from opening transports\n // on a dead manager. (A late activation self-heals via the post-settle guard,\n // but never starting it is cheaper and clearer.)\n if (this.activated || this.stopped) {\n return;\n }\n // Reject duplicate Channel names BEFORE kicking off any engine call. The\n // manager keys `entries` by name, so a duplicate would let the second\n // activation's entry silently overwrite the first — leaking the first\n // Channel's control link out of status()/ready()/stop(). Fail loud here so\n // nothing is ever activated in that state.\n this.assertUniqueChannelNames();\n this.activated = true;\n\n // Every declared Channel gets the managed adapter. Any developer-supplied\n // direct adapters stay in the same adapter array and are started by the\n // launcher's single `channel.ɵruntime.start()` call.\n for (const channel of this.channels) {\n channel.ɵruntime.enableIntelligenceMemory();\n const name = channel.name!;\n const runtimeInstanceId = this.mintRuntimeInstanceId();\n\n let resolveSettled!: () => void;\n let rejectSettled!: (err: unknown) => void;\n const settled = new Promise<void>((resolve, reject) => {\n resolveSettled = resolve;\n rejectSettled = reject;\n });\n // ready() awaits `settled`; if nothing ever handles a rejection there,\n // Node reports an unhandled rejection. Attach a no-op catch so the\n // promise is always considered handled — ready() still sees the reason.\n settled.catch(() => {});\n\n // The deferred activation callbacks capture `entry` and run only after\n // the literal has fully initialized, so referencing it there is safe.\n const entry: ChannelEntry = {\n status: \"connecting\",\n handle: undefined,\n handleStopped: false,\n settled,\n };\n\n // Invoke the engine synchronously so activation is observably started the\n // moment activate() returns. Only a typed transient gateway failure is\n // retried; config errors stay on the existing terminal path.\n let activation: Promise<ChannelsHandle>;\n try {\n const config = deriveChannelActivationConfig({\n intelligence: this.intelligence,\n channel,\n runtimeInstanceId,\n });\n activation = this.activateWithRetry(config, channel, name, entry);\n } catch (err) {\n activation = Promise.reject(err);\n }\n\n // Anchor the settle handlers. Both branches route every teardown through\n // the idempotent `stopEntry`, so a late settle can never resurrect a\n // `stopped` entry and a handle is torn down at most once. The handlers\n // only mutate state (never throw), so the trailing no-op catch just keeps\n // the chain from surfacing as an unhandled rejection.\n activation\n .then(\n async (handle) => {\n entry.handle = handle;\n if (this.stopped) {\n // stop() ran before this activation settled, so it could not tear\n // down a handle that did not exist yet. Release it now (idempotent)\n // and keep the Channel `stopped`.\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n entry.status = \"online\";\n this.registerConnectionObserver(name, entry);\n resolveSettled();\n },\n async (err: unknown) => {\n if (this.stopped) {\n // A rejection that arrives AFTER stop() must NOT resurrect the\n // entry into `error`/`setup_required`: the Channel is already\n // being torn down. Keep it `stopped` and resolve `settled` so a\n // subsequent ready() does not reject on a stopped Channel.\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n if (isSetupRequired(err)) {\n const hasDirectAdapter = channel.adapters.some(\n (adapter) => !adapter.__intelligenceChannel,\n );\n if (hasDirectAdapter) {\n try {\n // Managed setup may be incomplete while a developer-owned\n // transport is fully configured. Keep that transport alive;\n // a later runtime restart can attach the managed adapter once\n // Intelligence setup is complete.\n await channel.ɵruntime.start();\n entry.handle = {\n metadata: {},\n stop: () => channel.ɵruntime.stop(),\n };\n if (this.stopped) {\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n } catch (directError) {\n if (this.stopped) {\n await this.stopEntry(entry);\n resolveSettled();\n return;\n }\n entry.status = \"error\";\n this.log?.(\n `channel \"${name}\" failed to start its direct adapters while managed setup is incomplete`,\n directError,\n );\n rejectSettled(directError);\n return;\n }\n }\n entry.status = \"setup_required\";\n this.log?.(`channel \"${name}\" requires setup`, err);\n resolveSettled();\n } else {\n entry.status = \"error\";\n this.log?.(`channel \"${name}\" failed to activate`, err);\n rejectSettled(err);\n }\n },\n )\n .catch(() => {});\n\n this.entries.set(name, entry);\n }\n }\n\n /**\n * Retry only transient failures from the pre-adapter gateway connection.\n * Permanent errors reject on the first attempt; teardown cancels a pending\n * timer while preserving the existing late-settle handling for in-flight work.\n */\n private activateWithRetry(\n config: ChannelActivationConfig,\n channel: Channel,\n name: string,\n entry: ChannelEntry,\n ): Promise<ChannelsHandle> {\n return new Promise<ChannelsHandle>((resolve, reject) => {\n const attempt = (): void => {\n let activation: Promise<ChannelsHandle>;\n try {\n activation = this.activateChannel(config, channel);\n } catch (err) {\n activation = Promise.reject(err);\n }\n activation.then(\n (handle) => {\n this.clearActivationRetry(entry);\n resolve(handle);\n },\n (err: unknown) => {\n if (this.stopped || !isRetryableActivationError(err)) {\n this.clearActivationRetry(entry);\n reject(err);\n return;\n }\n\n const delayMs =\n entry.activationRetryDelayMs ?? DEFAULT_ACTIVATION_RETRY_DELAY_MS;\n entry.status = \"reconnecting\";\n entry.activationRetryDelayMs = Math.min(\n delayMs * 2,\n DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS,\n );\n this.log?.(\n `channel \"${name}\" failed to activate; retrying in ${delayMs}ms`,\n err,\n );\n const timer = setTimeout(() => {\n entry.activationRetryTimer = undefined;\n entry.cancelActivationRetry = undefined;\n if (this.stopped || entry.status === \"stopped\") {\n reject(err);\n return;\n }\n entry.status = \"connecting\";\n attempt();\n }, delayMs);\n (timer as unknown as { unref?: () => void }).unref?.();\n entry.activationRetryTimer = timer;\n entry.cancelActivationRetry = () => {\n this.clearActivationRetry(entry);\n reject(err);\n };\n },\n );\n };\n\n attempt();\n });\n }\n\n /**\n * Throw if two declared Channels share a `name`. `entries` is keyed by name,\n * so a duplicate would overwrite the first Channel's entry and leak its live\n * session. Called at the very start of {@link activate}, before any engine\n * call, so a misconfiguration fails loud instead of silently.\n *\n * @throws {ChannelConfigError} If any Channel is missing a name, or if any\n * name appears more than once.\n */\n private assertUniqueChannelNames(): void {\n const seen = new Set<string>();\n for (const channel of this.channels) {\n const name = channel.name;\n // Check for a missing/empty name FIRST: `channel.name!` on a nameless\n // Channel keys as the string \"undefined\", which would otherwise report a\n // spurious duplicate for two nameless Channels before the accurate\n // missing-name error. Fail with the precise error instead.\n if (!name) {\n throw new ChannelConfigError(\n \"A managed Channel is missing a `name` — every declared Channel must \" +\n \"have a unique, non-empty name (pass createChannel({ name })).\",\n );\n }\n if (seen.has(name)) {\n throw new ChannelConfigError(\n `Duplicate managed Channel name \"${name}\" — every declared Channel ` +\n `must have a unique name.`,\n );\n }\n seen.add(name);\n }\n }\n\n /**\n * Resolve when every declared Channel has settled to\n * `online`/`setup_required` through its managed activation.\n *\n * Activates lazily if not already started — so a first call rejects with the\n * same {@link ChannelConfigError} as the synchronous throw from\n * {@link activate} for an up-front misconfiguration (duplicate/missing Channel\n * names). Once activation has been kicked off, all OTHER failures are surfaced\n * here instead: this rejects with an `AggregateError` if any Channel settled\n * to `error` OR — when `timeoutMs` is given — did not settle in time. The\n * `timeoutMs` deadline is applied PER CHANNEL, so the aggregate carries each\n * failed Channel's real reason AND a named timeout for each Channel still\n * hanging: a genuine activation error is never masked by a sibling that hangs\n * (a pre-fix set-wide timeout discarded the real reason in that case).\n *\n * A STOPPED manager short-circuits and resolves: a Channel that settled to\n * `error` BEFORE {@link stop} already rejected its `settled` promise, so\n * awaiting it here would throw an `AggregateError` even though\n * {@link status}.overall is `\"stopped\"` — inconsistent with the case where the\n * Channel was still online at stop() (which resolves). A stopped manager has\n * nothing left to be ready for, so resolve uniformly.\n *\n * `ready()` is ONE-SHOT: it settles on the INITIAL activation outcome. Later\n * connection-health transitions (a live Channel dropping to `reconnecting`, or\n * giving up to `error`) are reported through {@link status} — where `online`\n * means currently-sendable — but do NOT re-arm or re-reject an already-settled\n * `ready()`.\n */\n async ready(opts?: { timeoutMs?: number }): Promise<void> {\n if (this.stopped) {\n return;\n }\n this.activate();\n const entries = [...this.entries.entries()];\n // Apply `timeoutMs` PER CHANNEL rather than to the whole set. A single\n // set-wide timeout wrapping `allSettled` would, when one channel settles to\n // `error` while a sibling hangs, reject with only a generic timeout and\n // DISCARD the erroring channel's real reason. Timing out each channel's\n // `settled` independently lets `allSettled` collect BOTH a hung channel's\n // named timeout AND a failed channel's real error into one AggregateError.\n const results = await Promise.allSettled(\n entries.map(([name, e]) =>\n withTimeout(\n e.settled,\n opts?.timeoutMs,\n `channel \"${name}\" did not settle within ${opts?.timeoutMs}ms`,\n ),\n ),\n );\n const errors = results\n .filter((r): r is PromiseRejectedResult => r.status === \"rejected\")\n .map((r) => r.reason);\n if (errors.length > 0) {\n throw new AggregateError(\n errors,\n `ChannelManager.ready: ${errors.length} channel(s) failed to activate or settle in time`,\n );\n }\n }\n\n /**\n * Snapshot status. Every declared Channel appears keyed by name in\n * `channels` after its combined adapter lifecycle starts.\n *\n * `overall` is folded over ALL declared Channels (see {@link computeOverall}),\n * by precedence `error` > `reconnecting` > `setup_required` > `connecting` >\n * `online`. `online` means every Channel can currently send. `reconnecting`\n * outranks `setup_required` because a dropped-but-retrying Channel is an active\n * outage, louder than a steadily-degraded unprovisioned one. With no declared\n * Channels at all, `overall` is `online` (nothing\n * is degraded); once every Channel has been stopped, `overall` is `stopped`.\n */\n status(): {\n overall: ChannelStatus;\n channels: Record<string, ChannelStatus>;\n } {\n const channels: Record<string, ChannelStatus> = {};\n for (const [name, entry] of this.entries) {\n channels[name] = entry.status;\n }\n // A stopped manager is `stopped` regardless of whether it was ever activated.\n // stop() before activate() (e.g. SIGTERM during startup) leaves `entries`\n // empty, and the empty-set fold below returns `online` — a torn-down manager\n // must never read healthy. Short-circuit before that fold. (After a normal\n // activate→stop, every entry is already `stopped` and the fold agrees, so\n // this is also consistent with the populated case.)\n if (this.stopped) {\n return { overall: \"stopped\", channels };\n }\n // Before activate() has run, `entries` is empty. Folding an empty set gives\n // `online` — correct for a manager that declares NO channels (nothing is\n // degraded), but a LIE for one that declares channels and simply has not\n // opened its socket yet: activation is lazy (deferred to the first\n // `ready()`), so a not-yet-activated manager must never read `online`.\n // Report `connecting` (\"not started\") for that case so `status()` is honest\n // before any `ready()`.\n if (!this.activated && this.channels.length > 0) {\n return { overall: \"connecting\", channels };\n }\n return { overall: this.computeOverall(Object.values(channels)), channels };\n }\n\n /**\n * Fold per-Channel statuses into a single overall status (see {@link status}).\n *\n * Every declared Channel participates. Statuses are ranked\n * `error` > `reconnecting` > `setup_required` > `connecting` > `online`, so a\n * genuine failure still dominates a healthy sibling.\n * The empty-input case (no declared Channels at all) stays `online` (nothing is\n * degraded).\n */\n private computeOverall(values: ChannelStatus[]): ChannelStatus {\n if (values.length === 0) {\n return \"online\";\n }\n if (values.every((v) => v === \"stopped\")) {\n return \"stopped\";\n }\n if (values.includes(\"error\")) {\n return \"error\";\n }\n if (values.includes(\"reconnecting\")) {\n return \"reconnecting\";\n }\n if (values.includes(\"setup_required\")) {\n return \"setup_required\";\n }\n if (values.includes(\"connecting\")) {\n return \"connecting\";\n }\n return \"online\";\n }\n\n /**\n * Wire the Channel's connection-health observer (if the handle exposes the\n * optional `onStateChange` seam) so {@link ChannelManager.status} reflects real\n * health instead of reporting `online` forever after a drop:\n *\n * - `reconnecting` → status `reconnecting` (dropped, Phoenix retrying);\n * - `online` → status `online` (rejoined, sendable again);\n * - `gave_up` → status `error` (dead after the bounded reconnect window).\n *\n * Makes NO re-activation — reconnection is delegated to the Phoenix connection\n * layer (see {@link ChannelManager}), which auto-rejoins under the persistent\n * adapter. A STOPPED manager (or an already-stopped entry) ignores late\n * connection events, so a drop that fires after {@link ChannelManager.stop}\n * never resurrects the Channel out of `stopped`.\n *\n * @param name - The Channel name (map key).\n * @param entry - The Channel's activation entry.\n */\n private registerConnectionObserver(name: string, entry: ChannelEntry): void {\n entry.handle?.onStateChange?.((state, detail) => {\n // A stopped manager (or a stopped entry) ignores late connection events.\n if (this.stopped || entry.status === \"stopped\") {\n return;\n }\n const cause = detail?.reason ?? detail?.code;\n const because = cause !== undefined ? ` — ${cause}` : \"\";\n if (state === \"reconnecting\") {\n entry.status = \"reconnecting\";\n entry.downSince ??= Date.now();\n this.log?.(\n `channel \"${name}\" managed session dropped; reconnecting (Phoenix auto-rejoin)${because}`,\n );\n this.startReconnectLog(name, entry);\n } else if (state === \"online\") {\n entry.status = \"online\";\n this.clearReconnectLog(entry);\n entry.downSince = undefined;\n this.log?.(`channel \"${name}\" managed session back online`);\n } else if (state === \"gave_up\") {\n // `error` here means \"not sendable\", NOT \"dead\": Phoenix keeps retrying\n // underneath and a successful rejoin restores `online`. Say so, or the\n // line reads as terminal (OSS-670). The repeat keeps running.\n entry.status = \"error\";\n this.log?.(\n `channel \"${name}\" managed session gave up reconnecting after ${this.downFor(entry)}; ` +\n `marking error (still retrying — a successful rejoin restores online)${because}`,\n );\n }\n });\n }\n\n /** Rendered downtime for this outage episode (`\"45s\"`), or `\"unknown\"`. */\n private downFor(entry: ChannelEntry): string {\n return entry.downSince === undefined\n ? \"unknown\"\n : `${Math.round((Date.now() - entry.downSince) / 1000)}s`;\n }\n\n /**\n * Repeat a \"still down\" line for as long as this outage lasts, with an\n * exponential delay capped at 15 minutes. Runs THROUGH `gave_up` on purpose:\n * that transition is where the old behavior went quiet, and an operator\n * watching a silent process cannot tell a dead bot from an idle one.\n */\n private startReconnectLog(name: string, entry: ChannelEntry): void {\n if (entry.reconnectLogTimer !== undefined) return;\n\n const delayMs = entry.reconnectLogDelayMs ?? this.reconnectLogIntervalMs;\n const timer = setTimeout(() => {\n entry.reconnectLogTimer = undefined;\n if (this.stopped || entry.status === \"stopped\") {\n this.clearReconnectLog(entry);\n return;\n }\n this.log?.(\n `channel \"${name}\" managed session still down after ${this.downFor(entry)}; Phoenix is retrying`,\n );\n entry.reconnectLogDelayMs = Math.min(\n delayMs * 2,\n Math.max(\n this.reconnectLogIntervalMs,\n DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS,\n ),\n );\n this.startReconnectLog(name, entry);\n }, delayMs);\n (timer as unknown as { unref?: () => void }).unref?.();\n entry.reconnectLogTimer = timer;\n }\n\n /** Stop this entry's \"still down\" repeat, if one is running. */\n private clearReconnectLog(entry: ChannelEntry): void {\n if (entry.reconnectLogTimer !== undefined) {\n clearTimeout(entry.reconnectLogTimer);\n entry.reconnectLogTimer = undefined;\n }\n entry.reconnectLogDelayMs = undefined;\n }\n\n /** Cancel a pending transient activation retry and reset its backoff. */\n private clearActivationRetry(entry: ChannelEntry): void {\n if (entry.activationRetryTimer !== undefined) {\n clearTimeout(entry.activationRetryTimer);\n entry.activationRetryTimer = undefined;\n }\n entry.activationRetryDelayMs = undefined;\n entry.cancelActivationRetry = undefined;\n }\n\n /** Cancel a scheduled activation retry and settle its wrapper. */\n private cancelActivationRetry(entry: ChannelEntry): void {\n const cancel = entry.cancelActivationRetry;\n if (cancel) {\n cancel();\n } else {\n this.clearActivationRetry(entry);\n }\n }\n\n /**\n * Drive a single entry to its terminal `stopped` state, tearing down its\n * handle AT MOST ONCE. Idempotent: it always sets `status = \"stopped\"`, and\n * only calls `handle.stop()` on the first invocation that sees a live,\n * not-yet-stopped handle (gated by {@link ChannelEntry.handleStopped}).\n *\n * This is the ONE guarded teardown path shared by both `stop()` and the\n * post-settle guard in {@link activate}. Because the\n * guard is per-entry and idempotent, a handle assigned in the same tick as\n * `stop()` is stopped exactly once even when both callers reach the entry, and a\n * late settle can never resurrect a `stopped` entry. The activation handle\n * releases the gateway session and stops the Channel's combined adapter array.\n *\n * `handle.stop()` failures are logged (via {@link ChannelManager.log}) but NOT\n * rethrown: the real launcher's `stop()` rethrows after `session.disconnect()`,\n * and teardown must still complete for every other entry. The call is wrapped\n * in `Promise.resolve().then(...)` so a foreign/injected handle whose `stop()`\n * throws SYNCHRONOUSLY (before any promise is created) is caught by the same\n * `.catch` — otherwise the sync throw would escape, skip `resolveSettled()` in\n * the fulfilled-then-stopped branch of {@link activate}, and hang `settled`.\n *\n * An entry with no handle yet (a still-`connecting` Channel whose transport has\n * not come up) is only marked `stopped`: there is nothing to tear down, and the\n * post-settle guard releases the transport if it arrives after `stop()`.\n *\n * A WEDGED `handle.stop()` (one that never settles) is bounded by\n * {@link ChannelManagerArgs.stopHandleTimeoutMs}: after the deadline the call\n * is logged and abandoned so it can't hang `stop()` — and thus SIGTERM\n * shutdown — forever.\n *\n * @param entry - The Channel entry to stop.\n */\n private async stopEntry(entry: ChannelEntry): Promise<void> {\n entry.status = \"stopped\";\n // An unref'd interval would not hold the process open, but a stopped\n // manager must not keep logging about a session it no longer owns.\n this.clearReconnectLog(entry);\n this.cancelActivationRetry(entry);\n if (entry.handle && !entry.handleStopped) {\n entry.handleStopped = true;\n const handle = entry.handle;\n // Bound handle.stop(): a wedged stop() (e.g. a socket.disconnect that\n // never returns) must not hang teardown — and thus SIGTERM shutdown —\n // forever. On timeout, log and abandon it (the call keeps running with a\n // settle handler attached inside withTimeout, so it never surfaces as an\n // unhandled rejection) so every OTHER entry still reaches `stopped`. The\n // `Promise.resolve().then(...)` wrap also routes a SYNCHRONOUS throw from\n // a foreign handle through the same timeout+catch.\n await withTimeout(\n Promise.resolve().then(() => handle.stop()),\n this.stopHandleTimeoutMs,\n `channel handle stop() timed out after ${this.stopHandleTimeoutMs}ms during teardown`,\n ).catch((err: unknown) =>\n this.log?.(\"channel handle stop() failed during teardown\", err),\n );\n }\n }\n\n /**\n * Stop every activated Channel exactly once and mark all statuses `stopped`.\n * Idempotent — a second call is a no-op.\n *\n * Resolves promptly: {@link stopEntry} stops only the handles that already\n * exist and never blocks on activations that have not settled. A hung connect\n * (which `ready({ timeoutMs })` tolerates) has no handle to stop yet, and\n * awaiting it here would hang teardown — and thus SIGTERM shutdown — forever.\n * Any handle that arrives after this point is torn down by the post-settle\n * guard in {@link activate}, which routes through the same idempotent\n * {@link stopEntry}, so nothing leaks and nothing double-stops.\n *\n * Teardown is resilient to a throwing `handle.stop()`: `Promise.allSettled`\n * over the per-entry `stopEntry` calls guarantees one rejection can't abort\n * the rest, so every entry reaches `stopped` and `stop()` always resolves.\n * It is equally resilient to a WEDGED `handle.stop()` that never settles: each\n * is bounded by {@link ChannelManagerArgs.stopHandleTimeoutMs} inside\n * {@link stopEntry}, so a single hung handle can't hang SIGTERM shutdown.\n */\n async stop(): Promise<void> {\n if (this.stopped) {\n return;\n }\n this.stopped = true;\n\n const entries = [...this.entries.values()];\n await Promise.allSettled(entries.map((entry) => this.stopEntry(entry)));\n }\n}\n"],"mappings":"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"}
|