@copilotkit/core 1.75.0 → 1.75.1

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/index.cjs CHANGED
@@ -25,20 +25,23 @@ let zod_to_json_schema = require("zod-to-json-schema");
25
25
  *
26
26
  * `transformChunks` is still applied — message reassembly is needed either way.
27
27
  *
28
- * This mirrors the base `AbstractAgent.connectAgent` implementation exactly
29
- * apart from that omission, so callers keep the same subscriber notifications,
30
- * detach semantics, and `{ result, newMessages }` return shape.
28
+ * Connection-local replay hooks track the phase before applying events. An
29
+ * explicitly live RUN_ERROR clears busy without closing the connection;
30
+ * historical errors remain data. Connections without hooks retain the existing
31
+ * completion behavior. Subscriber, detach, and result contracts are preserved.
31
32
  *
32
33
  * TODO: Remove this in favour of the base implementation once AG-UI's
33
34
  * AbstractAgent supports opting out of `verifyEvents` for transports whose
34
- * connection life-cycle isn't a single run. As of `@ag-ui/client@0.0.57`
35
+ * connection life-cycle isn't a single run AND preserves the connection-local
36
+ * replay lifecycle and running-state behavior below. Skipping verification alone
37
+ * is insufficient. As of `@ag-ui/client@0.0.57`
35
38
  * `connectAgent(parameters?, subscriber?)` takes no such option.
36
39
  *
37
40
  * @param agent - The agent whose `connect()` stream should be consumed.
38
41
  * @param parameters - Run parameters, forwarded to `prepareRunAgentInput`.
39
42
  * @param subscriber - Optional one-shot subscriber for this connect call.
40
43
  */
41
- async function ɵconnectWithoutEventVerification(agent, parameters, subscriber) {
44
+ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber, connect) {
42
45
  const self = agent;
43
46
  try {
44
47
  agent.isRunning = true;
@@ -46,10 +49,20 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber)
46
49
  const input = self.prepareRunAgentInput(parameters);
47
50
  let result;
48
51
  const previousMessageIds = new Set(agent.messages.map((m) => m.id));
52
+ let isReplaying = true;
53
+ const liveErrors = /* @__PURE__ */ new WeakSet();
49
54
  const subscribers = [
50
- { onRunFinishedEvent: (event) => {
51
- if (event.outcome === "success") result = event.result;
52
- } },
55
+ {
56
+ onRunStartedEvent: () => {
57
+ agent.isRunning = true;
58
+ },
59
+ onRunErrorEvent: ({ event }) => {
60
+ if (liveErrors.has(event)) agent.isRunning = false;
61
+ },
62
+ onRunFinishedEvent: (event) => {
63
+ if (event.outcome === "success") result = event.result;
64
+ }
65
+ },
53
66
  ...agent.subscribers,
54
67
  subscriber ?? {}
55
68
  ];
@@ -59,7 +72,18 @@ async function ɵconnectWithoutEventVerification(agent, parameters, subscriber)
59
72
  self.activeRunCompletionPromise = new Promise((resolve) => {
60
73
  resolveCompletion = resolve;
61
74
  });
62
- const source$ = (0, rxjs.defer)(() => self.connect(input)).pipe((0, _ag_ui_client.transformChunks)(self.debugLogger), (0, rxjs_operators.takeUntil)(self.activeRunDetach$));
75
+ const lifecycle = {
76
+ onReplayStarted: () => {
77
+ isReplaying = true;
78
+ agent.isRunning = true;
79
+ },
80
+ onReplayFinished: () => {
81
+ isReplaying = false;
82
+ }
83
+ };
84
+ const source$ = (0, rxjs.defer)(() => connect ? connect(input, lifecycle) : self.connect(input)).pipe((0, rxjs_operators.tap)((event) => {
85
+ if (!isReplaying && event.type === _ag_ui_client.EventType.RUN_ERROR) liveErrors.add(event);
86
+ }), (0, _ag_ui_client.transformChunks)(self.debugLogger), (0, rxjs_operators.takeUntil)(self.activeRunDetach$));
63
87
  const applied$ = self.apply(input, source$, subscribers);
64
88
  await (0, rxjs.lastValueFrom)(self.processApplyEvents(input, applied$, subscribers).pipe((0, rxjs_operators.catchError)((error) => {
65
89
  agent.isRunning = false;
@@ -210,6 +234,7 @@ const REPLAY_FAILED_EVENT = "replay_failed";
210
234
  const STREAM_IDLE_EVENT = "stream_idle";
211
235
  const STOP_RUN_EVENT = "stop_run";
212
236
  const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
237
+ const CONNECT_IDLE_WARNING_MS = 3e4;
213
238
  const MAX_UNOPENED_CREDENTIAL_REFRESHES = 2;
214
239
  var AgentThreadLockedError = class extends Error {
215
240
  constructor(threadId) {
@@ -297,7 +322,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
297
322
  ...parameters,
298
323
  runId: this.canonicalRunId
299
324
  };
300
- return ɵconnectWithoutEventVerification(this, effectiveParameters, subscriber);
325
+ return ɵconnectWithoutEventVerification(this, effectiveParameters, subscriber, (input, lifecycle) => this.connect(input, lifecycle));
301
326
  }
302
327
  abortRun() {
303
328
  if (this.activeChannel && this.canonicalRunId) {
@@ -346,17 +371,22 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
346
371
  * gateway only streams events past it instead of replaying the
347
372
  * entire history every time the chat re-opens a socket.
348
373
  */
349
- connect(input) {
374
+ connect(input, lifecycle) {
350
375
  this.threadId = input.threadId;
351
376
  this.canonicalRunId = null;
352
377
  const replayCursor = this.getReconnectCursor(input);
353
378
  return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input, replayCursor)).pipe((0, rxjs.switchMap)((credentials) => {
354
- if (credentials === null) return rxjs.EMPTY;
379
+ if (credentials === null) {
380
+ lifecycle?.onReplayStarted?.();
381
+ lifecycle?.onReplayFinished?.();
382
+ return rxjs.EMPTY;
383
+ }
355
384
  const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: false });
356
385
  return this.observeThread$(canonicalInput, credentials, {
357
386
  completeOnRunError: false,
358
387
  streamMode: "connect",
359
- replayCursor
388
+ replayCursor,
389
+ lifecycle
360
390
  });
361
391
  }));
362
392
  }
@@ -456,8 +486,24 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
456
486
  }
457
487
  observeThreadSession$(input, credentials, options) {
458
488
  return (0, rxjs.defer)(() => {
489
+ options.lifecycle?.onReplayStarted?.();
459
490
  let ownSocket = null;
460
491
  let ownChannel = null;
492
+ let replayFinished = false;
493
+ let warnedAboutIdle = false;
494
+ let idleWarning;
495
+ const clearIdleWarning = () => {
496
+ clearTimeout(idleWarning);
497
+ idleWarning = void 0;
498
+ };
499
+ const scheduleIdleWarning = () => {
500
+ clearIdleWarning();
501
+ if (options.streamMode !== "connect" || !replayFinished || warnedAboutIdle) return;
502
+ idleWarning = setTimeout(() => {
503
+ warnedAboutIdle = true;
504
+ this.debugLogger?.lifecycle("INTELLIGENCE", "No progress or stream_idle for 30 seconds after replay_complete; the run may still be active or its status unavailable.", { threadId: input.threadId });
505
+ }, CONNECT_IDLE_WARNING_MS);
506
+ };
461
507
  const socket$ = ɵphoenixSocket$({
462
508
  url: credentials.realtime.clientUrl,
463
509
  options: {
@@ -491,6 +537,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
491
537
  let latestObservedReplayCursor = null;
492
538
  const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.tap)((payload) => {
493
539
  latestObservedReplayCursor = this.readEventId(payload) ?? latestObservedReplayCursor;
540
+ scheduleIdleWarning();
494
541
  }), (0, rxjs_operators.share)());
495
542
  const controlCursor = {
496
543
  applied: null,
@@ -499,18 +546,33 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
499
546
  const replayFailed$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, REPLAY_FAILED_EVENT)), (0, rxjs_operators.tap)(() => {
500
547
  controlCursor.replayFailed = true;
501
548
  }));
502
- const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT, controlCursor).pipe((0, rxjs_operators.shareReplay)({
503
- bufferSize: 1,
504
- refCount: true
505
- }));
506
- const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT, controlCursor).pipe((0, rxjs_operators.shareReplay)({
549
+ const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT, controlCursor).pipe((0, rxjs_operators.tap)(() => {
550
+ replayFinished = true;
551
+ scheduleIdleWarning();
552
+ options.lifecycle?.onReplayFinished?.();
553
+ }), (0, rxjs_operators.share)());
554
+ const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT, controlCursor).pipe((0, rxjs_operators.share)());
555
+ const replayRestart$ = (0, rxjs.merge)(this.observeControlEvent$(input.threadId, channel$, "phx_error", controlCursor), ɵobservePhoenixSocketSignals$(socket$).pipe((0, rxjs_operators.filter)((signal) => signal.type === "error"))).pipe((0, rxjs_operators.tap)(() => {
556
+ replayFinished = false;
557
+ warnedAboutIdle = false;
558
+ clearIdleWarning();
559
+ options.lifecycle?.onReplayStarted?.();
560
+ }), (0, rxjs_operators.share)());
561
+ const streamIdleCompletion$ = options.streamMode === "connect" ? replayRestart$.pipe((0, rxjs_operators.startWith)(null), (0, rxjs.switchMap)(() => (0, rxjs.merge)((0, rxjs.combineLatest)([replayComplete$.pipe((0, rxjs_operators.take)(1)), streamIdle$.pipe((0, rxjs_operators.take)(1))]), streamIdle$.pipe((0, rxjs_operators.take)(1), (0, rxjs_operators.filter)((payload) => this.canFallbackCompleteConnect(payload, reconnectCursor, latestObservedReplayCursor)), (0, rxjs_operators.delay)(CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS), (0, rxjs_operators.tap)(() => {
562
+ this.debugLogger?.lifecycle("INTELLIGENCE", "Completing connection on stream_idle fallback without replay_complete.", {
563
+ threadId: input.threadId,
564
+ fallbackMs: CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS
565
+ });
566
+ })))), (0, rxjs_operators.take)(1), (0, rxjs_operators.shareReplay)({
507
567
  bufferSize: 1,
508
568
  refCount: true
509
- }));
510
- const streamIdleCompletion$ = options.streamMode === "connect" ? (0, rxjs.merge)((0, rxjs.combineLatest)([replayComplete$.pipe((0, rxjs_operators.take)(1)), streamIdle$.pipe((0, rxjs_operators.take)(1))]), streamIdle$.pipe((0, rxjs_operators.take)(1), (0, rxjs_operators.filter)((payload) => this.canFallbackCompleteConnect(payload, reconnectCursor, latestObservedReplayCursor)), (0, rxjs_operators.delay)(CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS))).pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
569
+ })) : rxjs.EMPTY;
511
570
  const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
512
571
  const terminal$ = (0, rxjs.merge)(threadCompleted$, streamIdleCompletion$);
513
- return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$, options.onSocketOpen).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), replayFailed$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), replayComplete$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(threadCompleted$))).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
572
+ return (0, rxjs.merge)(replayFailed$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), replayComplete$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(terminal$)), this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$, options.onSocketOpen).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.takeUntil)(threadCompleted$))).pipe((0, rxjs_operators.finalize)(() => {
573
+ clearIdleWarning();
574
+ this.cleanupOwned(ownChannel, ownSocket);
575
+ }));
514
576
  });
515
577
  }
516
578
  joinThreadChannel$(channel$) {
@@ -992,7 +1054,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
992
1054
  });
993
1055
  }
994
1056
  async connectAgent(parameters, subscriber) {
995
- if (this.runtimeMode !== _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return ɵconnectWithoutEventVerification(this, parameters, subscriber);
1057
+ if (this.runtimeMode !== _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return ɵconnectWithoutEventVerification(this, parameters, subscriber, (input, lifecycle) => this.connect(input, lifecycle));
996
1058
  if (this.delegate) await this.delegate.detachActiveRun();
997
1059
  await this.resolveDelegate();
998
1060
  const delegate = this.delegate;
@@ -1013,7 +1075,10 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1013
1075
  this.isRunning = false;
1014
1076
  },
1015
1077
  onRunErrorEvent: () => {
1016
- this.isRunning = false;
1078
+ this.isRunning = delegate.isRunning;
1079
+ },
1080
+ onRunStartedEvent: () => {
1081
+ this.isRunning = delegate.isRunning;
1017
1082
  }
1018
1083
  });
1019
1084
  const forwardedSubs = this.subscribers.map((s) => delegate.subscribe(s));
@@ -1028,9 +1093,9 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1028
1093
  for (const sub of forwardedSubs) sub.unsubscribe();
1029
1094
  }
1030
1095
  }
1031
- connect(input) {
1032
- if (this.runtimeMode === "pending" || this.transport === "auto" && this.runtimeMode !== _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return (0, rxjs.defer)(() => (0, rxjs.from)(this.ensureRuntimeConfiguration())).pipe((0, rxjs_operators.switchMap)(() => this.connect(input)));
1033
- if (this.runtimeMode === _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return this.#connectViaDelegate(input);
1096
+ connect(input, lifecycle) {
1097
+ if (this.runtimeMode === "pending" || this.transport === "auto" && this.runtimeMode !== _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return (0, rxjs.defer)(() => (0, rxjs.from)(this.ensureRuntimeConfiguration())).pipe((0, rxjs_operators.switchMap)(() => this.connect(input, lifecycle)));
1098
+ if (this.runtimeMode === _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return this.#connectViaDelegate(input, lifecycle);
1034
1099
  return this.#connectViaHttp(input);
1035
1100
  }
1036
1101
  run(input) {
@@ -1038,8 +1103,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1038
1103
  if (this.runtimeMode === _copilotkit_shared.RUNTIME_MODE_INTELLIGENCE) return this.#runViaDelegate(input);
1039
1104
  return this.#runViaHttp(input);
1040
1105
  }
1041
- #connectViaDelegate(input) {
1042
- return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.connect(input))));
1106
+ #connectViaDelegate(input, lifecycle) {
1107
+ return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.connect(input, lifecycle))));
1043
1108
  }
1044
1109
  #connectViaHttp(unfiltered) {
1045
1110
  const input = this.#applyMessageFilter(unfiltered);
@@ -1233,6 +1298,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
1233
1298
  delegate.agentId = this.routedAgentId();
1234
1299
  delegate.description = this.description;
1235
1300
  delegate.threadId = this.threadId;
1301
+ delegate.debugLogger = this.debugLogger;
1236
1302
  delegate.setMessages(this.messages);
1237
1303
  delegate.setState(this.state);
1238
1304
  if (hasHeaders(delegate)) delegate.headers = { ...this.headers };
@@ -5404,6 +5470,7 @@ const ALLOWED_KEYS = new Set([
5404
5470
  "onMessagesChanged",
5405
5471
  "onStateChanged",
5406
5472
  "onRunInitialized",
5473
+ "onRunStartedEvent",
5407
5474
  "onRunFinalized",
5408
5475
  "onRunFailed",
5409
5476
  "onRunErrorEvent"
@@ -6005,6 +6072,10 @@ var CopilotKitCore = class {
6005
6072
  const fn = sub.onRunInitialized;
6006
6073
  guarded.onRunInitialized = (params) => safeCall("onRunInitialized", fn, params);
6007
6074
  }
6075
+ if (sub.onRunStartedEvent) {
6076
+ const fn = sub.onRunStartedEvent;
6077
+ guarded.onRunStartedEvent = (params) => safeCall("onRunStartedEvent", fn, params);
6078
+ }
6008
6079
  if (sub.onRunFinalized) {
6009
6080
  const fn = sub.onRunFinalized;
6010
6081
  guarded.onRunFinalized = (params) => safeCall("onRunFinalized", fn, params);
@@ -6056,6 +6127,7 @@ var CopilotKitCore = class {
6056
6127
  });
6057
6128
  const lifecycleOnly = {};
6058
6129
  if (subscriber.onRunInitialized) lifecycleOnly.onRunInitialized = subscriber.onRunInitialized;
6130
+ if (subscriber.onRunStartedEvent) lifecycleOnly.onRunStartedEvent = subscriber.onRunStartedEvent;
6059
6131
  if (subscriber.onRunFinalized) lifecycleOnly.onRunFinalized = subscriber.onRunFinalized;
6060
6132
  if (subscriber.onRunFailed) lifecycleOnly.onRunFailed = subscriber.onRunFailed;
6061
6133
  if (subscriber.onRunErrorEvent) lifecycleOnly.onRunErrorEvent = subscriber.onRunErrorEvent;