@copilotkit/core 1.73.3 → 1.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -206,9 +206,11 @@ function ɵobservePhoenixSocketHealth$(socketSignals$, maxConsecutiveErrors) {
206
206
  const globalFetch = (...args) => fetch(...args);
207
207
  const CLIENT_AG_UI_EVENT = "ag_ui_event";
208
208
  const REPLAY_COMPLETE_EVENT = "replay_complete";
209
+ const REPLAY_FAILED_EVENT = "replay_failed";
209
210
  const STREAM_IDLE_EVENT = "stream_idle";
210
211
  const STOP_RUN_EVENT = "stop_run";
211
212
  const CONNECT_STREAM_IDLE_REPLAY_FALLBACK_MS = 100;
213
+ const MAX_UNOPENED_CREDENTIAL_REFRESHES = 2;
212
214
  var AgentThreadLockedError = class extends Error {
213
215
  constructor(threadId) {
214
216
  super(threadId ? `Thread ${threadId} is locked` : "Thread is locked");
@@ -430,15 +432,27 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
430
432
  };
431
433
  }
432
434
  observeThread$(input, credentials, options) {
433
- return this.observeThreadSession$(input, credentials, options).pipe((0, rxjs_operators.catchError)((error) => {
434
- if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
435
- const replayCursor = this.getReconnectCursor(input);
436
- return this.requestJoinCredentials$("connect", input, replayCursor).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
437
- ...options,
438
- channelMode: "connect",
439
- replayCursor
440
- })));
441
- }));
435
+ const { unopenedRefreshes: previousUnopened = 0, ...sessionOptions } = options;
436
+ return (0, rxjs.defer)(() => {
437
+ let socketOpened = false;
438
+ return this.observeThreadSession$(input, credentials, {
439
+ ...sessionOptions,
440
+ onSocketOpen: () => {
441
+ socketOpened = true;
442
+ }
443
+ }).pipe((0, rxjs_operators.catchError)((error) => {
444
+ if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
445
+ const unopenedRefreshes = socketOpened ? 0 : previousUnopened + 1;
446
+ if (options.streamMode === "run" && unopenedRefreshes > MAX_UNOPENED_CREDENTIAL_REFRESHES) return (0, rxjs.throwError)(() => /* @__PURE__ */ new Error(`Realtime connection to ${credentials.realtime.clientUrl} never opened in ${unopenedRefreshes} connection attempts. The realtime endpoint is unavailable.`));
447
+ const replayCursor = this.getReconnectCursor(input);
448
+ return this.requestJoinCredentials$("connect", input, replayCursor).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
449
+ ...sessionOptions,
450
+ channelMode: "connect",
451
+ replayCursor,
452
+ unopenedRefreshes
453
+ })));
454
+ }));
455
+ });
442
456
  }
443
457
  observeThreadSession$(input, credentials, options) {
444
458
  return (0, rxjs.defer)(() => {
@@ -478,25 +492,34 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
478
492
  const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.tap)((payload) => {
479
493
  latestObservedReplayCursor = this.readEventId(payload) ?? latestObservedReplayCursor;
480
494
  }), (0, rxjs_operators.share)());
481
- const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.shareReplay)({
495
+ const controlCursor = {
496
+ applied: null,
497
+ replayFailed: false
498
+ };
499
+ const replayFailed$ = channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, REPLAY_FAILED_EVENT)), (0, rxjs_operators.tap)(() => {
500
+ controlCursor.replayFailed = true;
501
+ }));
502
+ const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT, controlCursor).pipe((0, rxjs_operators.shareReplay)({
482
503
  bufferSize: 1,
483
504
  refCount: true
484
505
  }));
485
- const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT).pipe((0, rxjs_operators.shareReplay)({
506
+ const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT, controlCursor).pipe((0, rxjs_operators.shareReplay)({
486
507
  bufferSize: 1,
487
508
  refCount: true
488
509
  }));
489
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;
490
511
  const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
491
512
  const terminal$ = (0, rxjs.merge)(threadCompleted$, streamIdleCompletion$);
492
- return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe((0, rxjs_operators.takeUntil)(terminal$)), threadEvents$.pipe((0, rxjs_operators.takeUntil)(streamIdleCompletion$)), 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)));
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)));
493
514
  });
494
515
  }
495
516
  joinThreadChannel$(channel$) {
496
517
  return ɵjoinPhoenixChannel$(channel$);
497
518
  }
498
- observeSocketHealth$(socket$) {
499
- return ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$), 5);
519
+ observeSocketHealth$(socket$, onSocketOpen) {
520
+ return ɵobservePhoenixSocketHealth$(ɵobservePhoenixSocketSignals$(socket$).pipe((0, rxjs_operators.tap)((signal) => {
521
+ if (signal.type === "open") onSocketOpen?.();
522
+ })), 5);
500
523
  }
501
524
  observeThreadEvents$(threadId, channel$, options) {
502
525
  return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
@@ -507,8 +530,8 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
507
530
  errorOnRunError: options.streamMode === "run"
508
531
  })), (0, rxjs.dematerialize)());
509
532
  }
510
- observeControlEvent$(threadId, channel$, eventName) {
511
- return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, eventName)), (0, rxjs_operators.tap)((payload) => this.updateLastSeenEventIdFromControl(threadId, payload)));
533
+ observeControlEvent$(threadId, channel$, eventName, controlCursor) {
534
+ return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, eventName)), (0, rxjs_operators.tap)((payload) => this.updateLastSeenEventIdFromControl(threadId, payload, controlCursor)));
512
535
  }
513
536
  observeChannelEvent$(channel, eventName) {
514
537
  return ɵobservePhoenixEvent$(channel, eventName);
@@ -557,9 +580,11 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
557
580
  if (!eventId) return;
558
581
  this.advanceLastSeenEventId(threadId, eventId);
559
582
  }
560
- updateLastSeenEventIdFromControl(threadId, payload) {
583
+ updateLastSeenEventIdFromControl(threadId, payload, controlCursor) {
561
584
  const eventId = this.readControlEventId(payload);
562
585
  if (!eventId) return;
586
+ if (eventId === controlCursor.applied && !controlCursor.replayFailed) return;
587
+ controlCursor.applied = eventId;
563
588
  this.advanceLastSeenEventId(threadId, eventId);
564
589
  }
565
590
  advanceLastSeenEventId(threadId, eventId) {