@copilotkit/runtime 1.66.1 → 1.66.2-canary.1785878925
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 +141 -29
- package/dist/v2/runtime/core/channel-manager.cjs.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.cts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.d.mts.map +1 -1
- package/dist/v2/runtime/core/channel-manager.mjs +141 -29
- 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.1785878925",
|
|
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.1785878925",
|
|
9
9
|
"private": false,
|
|
10
10
|
"keywords": [
|
|
11
11
|
"ai",
|
|
@@ -209,9 +209,21 @@ async function runCanonicalChannelAgent(runner, intelligence, lockTtlSeconds, lo
|
|
|
209
209
|
next: (event) => {
|
|
210
210
|
if (event.type !== _ag_ui_client.EventType.RUN_ERROR || terminalError) return;
|
|
211
211
|
const message = "message" in event && typeof event.message === "string" ? event.message : "Canonical Channel agent run failed";
|
|
212
|
-
|
|
212
|
+
const details = safeChannelRunErrorDetails(event);
|
|
213
|
+
terminalError = new Error(message, details ? { cause: details } : void 0);
|
|
213
214
|
terminalError.name = "ChannelCanonicalRunError";
|
|
214
215
|
if ("code" in event && typeof event.code === "string" && event.code.length > 0) terminalError.code = event.code;
|
|
216
|
+
if (details) {
|
|
217
|
+
terminalError.category = details.category;
|
|
218
|
+
terminalError.provider = details.provider;
|
|
219
|
+
terminalError.operation = details.operation;
|
|
220
|
+
terminalError.effectKind = details.effectKind;
|
|
221
|
+
terminalError.providerCode = details.providerCode;
|
|
222
|
+
terminalError.validationMessages = details.validationMessages;
|
|
223
|
+
terminalError.retryable = details.retryable;
|
|
224
|
+
terminalError.deliveryId = details.deliveryId;
|
|
225
|
+
terminalError.details = details;
|
|
226
|
+
}
|
|
215
227
|
},
|
|
216
228
|
error: reject,
|
|
217
229
|
complete: () => {
|
|
@@ -238,6 +250,25 @@ async function runCanonicalChannelAgent(runner, intelligence, lockTtlSeconds, lo
|
|
|
238
250
|
}
|
|
239
251
|
return result;
|
|
240
252
|
}
|
|
253
|
+
function safeChannelRunErrorDetails(event) {
|
|
254
|
+
if (!("details" in event) || typeof event.details !== "object" || event.details === null || Array.isArray(event.details)) return;
|
|
255
|
+
const details = event.details;
|
|
256
|
+
const allowed = new Set([
|
|
257
|
+
"category",
|
|
258
|
+
"provider",
|
|
259
|
+
"operation",
|
|
260
|
+
"effectKind",
|
|
261
|
+
"providerCode",
|
|
262
|
+
"validationMessages",
|
|
263
|
+
"retryable",
|
|
264
|
+
"deliveryId"
|
|
265
|
+
]);
|
|
266
|
+
if (!Object.keys(details).every((field) => allowed.has(field)) || details.category !== "validation" || details.provider !== "slack" && details.provider !== "teams" || !boundedString(details.operation, 80) || !boundedString(details.effectKind, 80) || details.providerCode !== "invalid_arguments" && details.providerCode !== "invalid_blocks" || details.retryable !== false || !boundedString(details.deliveryId, 512) || !Array.isArray(details.validationMessages) || details.validationMessages.length > 5 || !details.validationMessages.every((validationMessage) => typeof validationMessage === "string" && validationMessage.length <= 256 && validationMessage.startsWith("invalid field at /"))) return;
|
|
267
|
+
return details;
|
|
268
|
+
}
|
|
269
|
+
function boundedString(value, maxLength) {
|
|
270
|
+
return typeof value === "string" && value.length > 0 && value.length <= maxLength;
|
|
271
|
+
}
|
|
241
272
|
/** Convert canonical Intelligence history into AG-UI messages. */
|
|
242
273
|
async function toAgentMessage(message, intelligence) {
|
|
243
274
|
const content = await hydrateManagedContent(message.content, intelligence);
|
|
@@ -289,6 +320,12 @@ async function hydrateManagedContent(content, intelligence) {
|
|
|
289
320
|
function isSetupRequired(err) {
|
|
290
321
|
return err instanceof ChannelSetupRequiredError || typeof err === "object" && err !== null && err.code === "SETUP_REQUIRED";
|
|
291
322
|
}
|
|
323
|
+
/** Whether a failed initial activation can recover without new configuration. */
|
|
324
|
+
function isRetryableActivationError(err) {
|
|
325
|
+
if (typeof err !== "object" || err === null) return false;
|
|
326
|
+
const value = err;
|
|
327
|
+
return (value.code === "GATEWAY_UNREACHABLE" || value.code === "GATEWAY_JOIN_FAILED") && value.retryable === true;
|
|
328
|
+
}
|
|
292
329
|
/**
|
|
293
330
|
* Whether `err` is a Node/runtime module-resolution failure — i.e. the error
|
|
294
331
|
* a dynamic `import()` throws when the target package is not installed.
|
|
@@ -302,8 +339,14 @@ function isModuleNotFound(err) {
|
|
|
302
339
|
}
|
|
303
340
|
/** Default deadline (ms) for a single `handle.stop()` during teardown. */
|
|
304
341
|
const DEFAULT_STOP_HANDLE_TIMEOUT_MS = 5e3;
|
|
305
|
-
/**
|
|
342
|
+
/** First delay (ms) before logging that a dropped session is still down. */
|
|
306
343
|
const DEFAULT_RECONNECT_LOG_INTERVAL_MS = 3e4;
|
|
344
|
+
/** Longest delay (ms) between reminders during one continuous outage. */
|
|
345
|
+
const DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS = 15 * 6e4;
|
|
346
|
+
/** First delay (ms) before retrying a transient initial activation failure. */
|
|
347
|
+
const DEFAULT_ACTIVATION_RETRY_DELAY_MS = 1e3;
|
|
348
|
+
/** Longest delay (ms) between transient initial activation attempts. */
|
|
349
|
+
const DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS = 3e4;
|
|
307
350
|
/**
|
|
308
351
|
* Reject with `timeoutMessage` after `timeoutMs` if `inner` has not settled,
|
|
309
352
|
* otherwise pass `inner` through. When `timeoutMs` is undefined, `inner` is
|
|
@@ -336,17 +379,18 @@ function withTimeout(inner, timeoutMs, timeoutMessage) {
|
|
|
336
379
|
* {@link activate} starts it and a second call is a no-op. Activation throws
|
|
337
380
|
* SYNCHRONOUSLY (a {@link ChannelConfigError}) only for a misconfiguration it
|
|
338
381
|
* 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.
|
|
382
|
+
* permanent activation failure is recorded as the Channel's status (`error`,
|
|
383
|
+
* or `setup_required` for a missing provider) and surfaced through
|
|
384
|
+
* {@link status} and {@link ready} rather than thrown. A retryable initial
|
|
385
|
+
* gateway outage stays unsettled and retries until it connects or the manager
|
|
386
|
+
* stops.
|
|
342
387
|
*
|
|
343
|
-
*
|
|
388
|
+
* Established-session reconnection is delegated to the Phoenix connection
|
|
344
389
|
* 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.
|
|
390
|
+
* `Socket` reconnects and rejoins with the same Runtime declaration. The manager
|
|
391
|
+
* never re-activates an already-started Channel. It does retry a transient
|
|
392
|
+
* INITIAL gateway activation failure: that happens before the launcher adds or
|
|
393
|
+
* starts the managed adapter, so a later attempt is safe.
|
|
350
394
|
*
|
|
351
395
|
* It DOES, however, reflect real connection health through the session's
|
|
352
396
|
* `onStateChange` observer so {@link ChannelManager.status} stays honest rather
|
|
@@ -381,8 +425,8 @@ var ChannelManager = class {
|
|
|
381
425
|
/**
|
|
382
426
|
* Start activation of every declared Channel (lazy + idempotent). Mints a
|
|
383
427
|
* distinct runtime instance id per Channel, derives its activation config,
|
|
384
|
-
* and calls the engine.
|
|
385
|
-
* to `online`/`setup_required`/`error
|
|
428
|
+
* and calls the engine. Transient gateway failures retry with exponential
|
|
429
|
+
* backoff; other outcomes transition to `online`/`setup_required`/`error`.
|
|
386
430
|
*/
|
|
387
431
|
activate() {
|
|
388
432
|
if (this.activated || this.stopped) return;
|
|
@@ -399,24 +443,23 @@ var ChannelManager = class {
|
|
|
399
443
|
rejectSettled = reject;
|
|
400
444
|
});
|
|
401
445
|
settled.catch(() => {});
|
|
446
|
+
const entry = {
|
|
447
|
+
status: "connecting",
|
|
448
|
+
handle: void 0,
|
|
449
|
+
handleStopped: false,
|
|
450
|
+
settled
|
|
451
|
+
};
|
|
402
452
|
let activation;
|
|
403
|
-
let config;
|
|
404
453
|
try {
|
|
405
|
-
config = require_channel_activation_config.deriveChannelActivationConfig({
|
|
454
|
+
const config = require_channel_activation_config.deriveChannelActivationConfig({
|
|
406
455
|
intelligence: this.intelligence,
|
|
407
456
|
channel,
|
|
408
457
|
runtimeInstanceId
|
|
409
458
|
});
|
|
410
|
-
activation = this.
|
|
459
|
+
activation = this.activateWithRetry(config, channel, name, entry);
|
|
411
460
|
} catch (err) {
|
|
412
461
|
activation = Promise.reject(err);
|
|
413
462
|
}
|
|
414
|
-
const entry = {
|
|
415
|
-
status: "connecting",
|
|
416
|
-
handle: void 0,
|
|
417
|
-
handleStopped: false,
|
|
418
|
-
settled
|
|
419
|
-
};
|
|
420
463
|
activation.then(async (handle) => {
|
|
421
464
|
entry.handle = handle;
|
|
422
465
|
if (this.stopped) {
|
|
@@ -469,6 +512,54 @@ var ChannelManager = class {
|
|
|
469
512
|
}
|
|
470
513
|
}
|
|
471
514
|
/**
|
|
515
|
+
* Retry only transient failures from the pre-adapter gateway connection.
|
|
516
|
+
* Permanent errors reject on the first attempt; teardown cancels a pending
|
|
517
|
+
* timer while preserving the existing late-settle handling for in-flight work.
|
|
518
|
+
*/
|
|
519
|
+
activateWithRetry(config, channel, name, entry) {
|
|
520
|
+
return new Promise((resolve, reject) => {
|
|
521
|
+
const attempt = () => {
|
|
522
|
+
let activation;
|
|
523
|
+
try {
|
|
524
|
+
activation = this.activateChannel(config, channel);
|
|
525
|
+
} catch (err) {
|
|
526
|
+
activation = Promise.reject(err);
|
|
527
|
+
}
|
|
528
|
+
activation.then((handle) => {
|
|
529
|
+
this.clearActivationRetry(entry);
|
|
530
|
+
resolve(handle);
|
|
531
|
+
}, (err) => {
|
|
532
|
+
if (this.stopped || !isRetryableActivationError(err)) {
|
|
533
|
+
this.clearActivationRetry(entry);
|
|
534
|
+
reject(err);
|
|
535
|
+
return;
|
|
536
|
+
}
|
|
537
|
+
const delayMs = entry.activationRetryDelayMs ?? DEFAULT_ACTIVATION_RETRY_DELAY_MS;
|
|
538
|
+
entry.status = "reconnecting";
|
|
539
|
+
entry.activationRetryDelayMs = Math.min(delayMs * 2, DEFAULT_ACTIVATION_RETRY_MAX_DELAY_MS);
|
|
540
|
+
this.log?.(`channel "${name}" failed to activate; retrying in ${delayMs}ms`, err);
|
|
541
|
+
const timer = setTimeout(() => {
|
|
542
|
+
entry.activationRetryTimer = void 0;
|
|
543
|
+
entry.cancelActivationRetry = void 0;
|
|
544
|
+
if (this.stopped || entry.status === "stopped") {
|
|
545
|
+
reject(err);
|
|
546
|
+
return;
|
|
547
|
+
}
|
|
548
|
+
entry.status = "connecting";
|
|
549
|
+
attempt();
|
|
550
|
+
}, delayMs);
|
|
551
|
+
timer.unref?.();
|
|
552
|
+
entry.activationRetryTimer = timer;
|
|
553
|
+
entry.cancelActivationRetry = () => {
|
|
554
|
+
this.clearActivationRetry(entry);
|
|
555
|
+
reject(err);
|
|
556
|
+
};
|
|
557
|
+
});
|
|
558
|
+
};
|
|
559
|
+
attempt();
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
472
563
|
* Throw if two declared Channels share a `name`. `entries` is keyed by name,
|
|
473
564
|
* so a duplicate would overwrite the first Channel's entry and leak its live
|
|
474
565
|
* session. Called at the very start of {@link activate}, before any engine
|
|
@@ -611,29 +702,49 @@ var ChannelManager = class {
|
|
|
611
702
|
return entry.downSince === void 0 ? "unknown" : `${Math.round((Date.now() - entry.downSince) / 1e3)}s`;
|
|
612
703
|
}
|
|
613
704
|
/**
|
|
614
|
-
* Repeat a "still down" line for as long as this outage lasts
|
|
615
|
-
*
|
|
616
|
-
*
|
|
617
|
-
* idle one.
|
|
705
|
+
* Repeat a "still down" line for as long as this outage lasts, with an
|
|
706
|
+
* exponential delay capped at 15 minutes. Runs THROUGH `gave_up` on purpose:
|
|
707
|
+
* that transition is where the old behavior went quiet, and an operator
|
|
708
|
+
* watching a silent process cannot tell a dead bot from an idle one.
|
|
618
709
|
*/
|
|
619
710
|
startReconnectLog(name, entry) {
|
|
620
711
|
if (entry.reconnectLogTimer !== void 0) return;
|
|
621
|
-
const
|
|
712
|
+
const delayMs = entry.reconnectLogDelayMs ?? this.reconnectLogIntervalMs;
|
|
713
|
+
const timer = setTimeout(() => {
|
|
714
|
+
entry.reconnectLogTimer = void 0;
|
|
622
715
|
if (this.stopped || entry.status === "stopped") {
|
|
623
716
|
this.clearReconnectLog(entry);
|
|
624
717
|
return;
|
|
625
718
|
}
|
|
626
719
|
this.log?.(`channel "${name}" managed session still down after ${this.downFor(entry)}; Phoenix is retrying`);
|
|
627
|
-
|
|
720
|
+
entry.reconnectLogDelayMs = Math.min(delayMs * 2, Math.max(this.reconnectLogIntervalMs, DEFAULT_RECONNECT_LOG_MAX_INTERVAL_MS));
|
|
721
|
+
this.startReconnectLog(name, entry);
|
|
722
|
+
}, delayMs);
|
|
628
723
|
timer.unref?.();
|
|
629
724
|
entry.reconnectLogTimer = timer;
|
|
630
725
|
}
|
|
631
726
|
/** Stop this entry's "still down" repeat, if one is running. */
|
|
632
727
|
clearReconnectLog(entry) {
|
|
633
728
|
if (entry.reconnectLogTimer !== void 0) {
|
|
634
|
-
|
|
729
|
+
clearTimeout(entry.reconnectLogTimer);
|
|
635
730
|
entry.reconnectLogTimer = void 0;
|
|
636
731
|
}
|
|
732
|
+
entry.reconnectLogDelayMs = void 0;
|
|
733
|
+
}
|
|
734
|
+
/** Cancel a pending transient activation retry and reset its backoff. */
|
|
735
|
+
clearActivationRetry(entry) {
|
|
736
|
+
if (entry.activationRetryTimer !== void 0) {
|
|
737
|
+
clearTimeout(entry.activationRetryTimer);
|
|
738
|
+
entry.activationRetryTimer = void 0;
|
|
739
|
+
}
|
|
740
|
+
entry.activationRetryDelayMs = void 0;
|
|
741
|
+
entry.cancelActivationRetry = void 0;
|
|
742
|
+
}
|
|
743
|
+
/** Cancel a scheduled activation retry and settle its wrapper. */
|
|
744
|
+
cancelActivationRetry(entry) {
|
|
745
|
+
const cancel = entry.cancelActivationRetry;
|
|
746
|
+
if (cancel) cancel();
|
|
747
|
+
else this.clearActivationRetry(entry);
|
|
637
748
|
}
|
|
638
749
|
/**
|
|
639
750
|
* Drive a single entry to its terminal `stopped` state, tearing down its
|
|
@@ -670,6 +781,7 @@ var ChannelManager = class {
|
|
|
670
781
|
async stopEntry(entry) {
|
|
671
782
|
entry.status = "stopped";
|
|
672
783
|
this.clearReconnectLog(entry);
|
|
784
|
+
this.cancelActivationRetry(entry);
|
|
673
785
|
if (entry.handle && !entry.handleStopped) {
|
|
674
786
|
entry.handleStopped = true;
|
|
675
787
|
const handle = entry.handle;
|