@copilotkit/core 1.56.3 → 1.56.4-canary.1777529757

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.umd.js CHANGED
@@ -167,6 +167,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
167
167
  //#endregion
168
168
  //#region src/intelligence-agent.ts
169
169
  const CLIENT_AG_UI_EVENT = "ag_ui_event";
170
+ const REPLAY_COMPLETE_EVENT = "replay_complete";
171
+ const STREAM_IDLE_EVENT = "stream_idle";
170
172
  const STOP_RUN_EVENT = "stop_run";
171
173
  var AgentThreadLockedError = class extends Error {
172
174
  constructor(threadId) {
@@ -280,10 +282,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
280
282
  run(input) {
281
283
  this.threadId = input.threadId;
282
284
  this.canonicalRunId = input.runId;
283
- return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => this.observeThread$(input, credentials, {
284
- completeOnRunError: false,
285
- streamMode: "run"
286
- })));
285
+ return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => {
286
+ if (credentials === null) return (0, rxjs.throwError)(() => /* @__PURE__ */ new Error("REST run request returned no credentials"));
287
+ const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: true });
288
+ return this.observeThread$(canonicalInput, credentials, {
289
+ completeOnRunError: false,
290
+ streamMode: "run"
291
+ });
292
+ }));
287
293
  }
288
294
  /**
289
295
  * Reconnect to an existing thread by fetching websocket credentials and
@@ -291,19 +297,15 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
291
297
  */
292
298
  connect(input) {
293
299
  this.threadId = input.threadId;
294
- this.canonicalRunId = input.runId;
295
- return (0, rxjs.defer)(() => this.requestConnectPlan$(input)).pipe((0, rxjs.switchMap)((plan) => {
296
- if (plan === null) return rxjs.EMPTY;
297
- if (plan.mode === "bootstrap") {
298
- this.setLastSeenEventId(input.threadId, plan.latestEventId);
299
- return (0, rxjs.from)(plan.events);
300
- }
301
- this.setLastSeenEventId(input.threadId, plan.joinFromEventId);
302
- return (0, rxjs.concat)((0, rxjs.from)(plan.events), this.observeThread$(input, { joinToken: plan.joinToken }, {
303
- completeOnRunError: true,
304
- streamMode: "connect",
305
- replayCursor: plan.joinFromEventId
306
- }));
300
+ this.canonicalRunId = null;
301
+ this.clearReconnectCursor(input.threadId);
302
+ return (0, rxjs.defer)(() => this.requestJoinCredentials$("connect", input)).pipe((0, rxjs.switchMap)((credentials) => {
303
+ if (credentials === null) return rxjs.EMPTY;
304
+ const canonicalInput = this.applyCanonicalRunIdentity(input, credentials, { fallbackToInputRunId: false });
305
+ return this.observeThread$(canonicalInput, credentials, {
306
+ completeOnRunError: false,
307
+ streamMode: "connect"
308
+ });
307
309
  }));
308
310
  }
309
311
  /**
@@ -320,7 +322,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
320
322
  ownSocket.disconnect();
321
323
  if (this.socket === ownSocket) this.socket = null;
322
324
  }
323
- if (this.threadId) this.sharedState.lastSeenEventIds.delete(this.threadId);
324
325
  this.canonicalRunId = null;
325
326
  }
326
327
  cleanup() {
@@ -342,80 +343,57 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
342
343
  tools: input.tools,
343
344
  context: input.context,
344
345
  state: input.state,
345
- forwardedProps: input.forwardedProps
346
+ forwardedProps: input.forwardedProps,
347
+ ...mode === "connect" ? { lastSeenEventId: this.getReconnectCursor(input) } : {}
346
348
  }),
347
349
  ...this.config.credentials ? { credentials: this.config.credentials } : {}
348
350
  });
349
- if (response.status === 409) throw new AgentThreadLockedError(input.threadId);
351
+ if (response.status === 204 && mode === "connect") return null;
352
+ if (response.status === 409 && mode === "run") throw new AgentThreadLockedError(input.threadId);
350
353
  if (!response.ok) {
351
354
  const text = await response.text().catch(() => "");
352
355
  throw new Error(text || response.statusText || String(response.status));
353
356
  }
354
- const payload = await response.json();
355
- if (!payload.joinToken) throw new Error("missing joinToken");
356
- return { joinToken: payload.joinToken };
357
+ return this.normalizeJoinCredentials(await response.json(), input);
357
358
  } catch (error) {
358
359
  if (error instanceof AgentThreadLockedError) throw error;
359
360
  throw new Error(`REST ${mode} request failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
360
361
  }
361
362
  });
362
363
  }
363
- requestConnectPlan$(input) {
364
- return (0, rxjs.defer)(async () => {
365
- try {
366
- const response = await fetch(this.buildRuntimeUrl("connect"), {
367
- method: "POST",
368
- headers: {
369
- "Content-Type": "application/json",
370
- ...this.config.headers
371
- },
372
- body: JSON.stringify({
373
- threadId: input.threadId,
374
- runId: input.runId,
375
- messages: input.messages,
376
- tools: input.tools,
377
- context: input.context,
378
- state: input.state,
379
- forwardedProps: input.forwardedProps,
380
- lastSeenEventId: this.getReconnectCursor(input)
381
- }),
382
- ...this.config.credentials ? { credentials: this.config.credentials } : {}
383
- });
384
- if (response.status === 204) return null;
385
- if (!response.ok) {
386
- const text = await response.text().catch(() => "");
387
- throw new Error(text || response.statusText || String(response.status));
388
- }
389
- return this.normalizeConnectPlan(await response.json());
390
- } catch (error) {
391
- throw new Error(`REST connect request failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
392
- }
393
- });
394
- }
395
- normalizeConnectPlan(payload) {
364
+ normalizeJoinCredentials(payload, input) {
396
365
  const envelope = payload && typeof payload === "object" ? payload : null;
397
- if ((envelope === null || envelope === void 0 ? void 0 : envelope.mode) === "bootstrap") return {
398
- mode: "bootstrap",
399
- latestEventId: typeof envelope.latestEventId === "string" ? envelope.latestEventId : null,
400
- events: Array.isArray(envelope.events) ? envelope.events : []
366
+ const realtime = (envelope === null || envelope === void 0 ? void 0 : envelope.realtime) && typeof envelope.realtime === "object" ? envelope.realtime : null;
367
+ if (typeof (envelope === null || envelope === void 0 ? void 0 : envelope.joinToken) !== "string" || !envelope.joinToken) throw new Error("missing joinToken");
368
+ if (typeof (realtime === null || realtime === void 0 ? void 0 : realtime.clientUrl) !== "string" || !realtime.clientUrl) throw new Error("missing realtime.clientUrl");
369
+ if (typeof realtime.topic !== "string" || !realtime.topic) throw new Error("missing realtime.topic");
370
+ return {
371
+ threadId: typeof envelope.threadId === "string" && envelope.threadId ? envelope.threadId : input.threadId,
372
+ runId: typeof envelope.runId === "string" && envelope.runId ? envelope.runId : null,
373
+ joinToken: envelope.joinToken,
374
+ realtime: {
375
+ clientUrl: realtime.clientUrl,
376
+ topic: realtime.topic
377
+ }
401
378
  };
402
- if ((envelope === null || envelope === void 0 ? void 0 : envelope.mode) === "live") {
403
- if (typeof envelope.joinToken !== "string" || envelope.joinToken.length === 0) throw new Error("missing joinToken");
404
- return {
405
- mode: "live",
406
- joinToken: envelope.joinToken,
407
- joinFromEventId: typeof envelope.joinFromEventId === "string" ? envelope.joinFromEventId : null,
408
- events: Array.isArray(envelope.events) ? envelope.events : []
409
- };
410
- }
411
- throw new Error("invalid connect plan");
412
379
  }
413
380
  observeThread$(input, credentials, options) {
381
+ return this.observeThreadSession$(input, credentials, options).pipe((0, rxjs_operators.catchError)((error) => {
382
+ if (!this.isSocketReconnectExhaustedError(error)) return (0, rxjs.throwError)(() => error);
383
+ return this.requestJoinCredentials$("connect", input).pipe((0, rxjs.switchMap)((refreshedCredentials) => refreshedCredentials === null ? rxjs.EMPTY : this.observeThread$(this.applyCanonicalRunIdentity(input, refreshedCredentials, { fallbackToInputRunId: options.streamMode === "run" }), refreshedCredentials, {
384
+ ...options,
385
+ channelMode: "connect",
386
+ replayCursor: this.getReconnectCursor(input)
387
+ })));
388
+ }));
389
+ }
390
+ observeThreadSession$(input, credentials, options) {
414
391
  return (0, rxjs.defer)(() => {
392
+ var _options$channelMode;
415
393
  let ownSocket = null;
416
394
  let ownChannel = null;
417
395
  const socket$ = ɵphoenixSocket$({
418
- url: this.config.url,
396
+ url: credentials.realtime.clientUrl,
419
397
  options: {
420
398
  params: {
421
399
  ...this.config.socketParams,
@@ -431,10 +409,10 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
431
409
  bufferSize: 1,
432
410
  refCount: true
433
411
  }));
434
- const { topic, params } = this.createThreadChannelDescriptor(input, options.streamMode, options.replayCursor);
412
+ const params = this.createThreadChannelParams(input, (_options$channelMode = options.channelMode) !== null && _options$channelMode !== void 0 ? _options$channelMode : options.streamMode, options.replayCursor);
435
413
  const channel$ = ɵphoenixChannel$({
436
414
  socket$,
437
- topic,
415
+ topic: credentials.realtime.topic,
438
416
  params
439
417
  }).pipe((0, rxjs_operators.tap)(({ channel }) => {
440
418
  ownChannel = channel;
@@ -444,8 +422,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
444
422
  refCount: true
445
423
  }));
446
424
  const threadEvents$ = this.observeThreadEvents$(input.threadId, channel$, options).pipe((0, rxjs_operators.share)());
447
- const threadCompleted$ = threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1));
448
- return (0, rxjs.merge)(this.joinThreadChannel$(channel$), this.observeSocketHealth$(socket$).pipe((0, rxjs_operators.takeUntil)(threadCompleted$)), threadEvents$).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
425
+ const replayComplete$ = this.observeControlEvent$(input.threadId, channel$, REPLAY_COMPLETE_EVENT).pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.share)());
426
+ const streamIdle$ = this.observeControlEvent$(input.threadId, channel$, STREAM_IDLE_EVENT).pipe((0, rxjs_operators.shareReplay)({
427
+ bufferSize: 1,
428
+ refCount: true
429
+ }));
430
+ const streamIdleCompletion$ = options.streamMode === "connect" ? streamIdle$.pipe((0, rxjs_operators.take)(1)) : rxjs.EMPTY;
431
+ const terminal$ = (0, rxjs.merge)(threadEvents$.pipe((0, rxjs_operators.ignoreElements)(), (0, rxjs_operators.endWith)(null), (0, rxjs_operators.take)(1)), streamIdleCompletion$);
432
+ 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.takeUntil)(terminal$)), streamIdleCompletion$.pipe((0, rxjs_operators.ignoreElements)())).pipe((0, rxjs_operators.finalize)(() => this.cleanupOwned(ownChannel, ownSocket)));
449
433
  });
450
434
  }
451
435
  joinThreadChannel$(channel$) {
@@ -457,17 +441,24 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
457
441
  observeThreadEvents$(threadId, channel$, options) {
458
442
  return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
459
443
  this.updateLastSeenEventId(threadId, payload);
460
- }), (0, rxjs_operators.mergeMap)((payload) => (0, rxjs.from)(this.createThreadNotifications(payload, options.completeOnRunError))), (0, rxjs.dematerialize)());
444
+ }), (0, rxjs_operators.mergeMap)((payload) => this.createThreadNotifications(payload, {
445
+ completeOnRunError: options.completeOnRunError,
446
+ completeOnRunFinished: options.streamMode === "run",
447
+ errorOnRunError: options.streamMode === "run"
448
+ })), (0, rxjs.dematerialize)());
449
+ }
450
+ observeControlEvent$(threadId, channel$, eventName) {
451
+ return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, eventName)), (0, rxjs_operators.tap)((payload) => this.updateLastSeenEventIdFromControl(threadId, payload)));
461
452
  }
462
453
  observeChannelEvent$(channel, eventName) {
463
454
  return ɵobservePhoenixEvent$(channel, eventName);
464
455
  }
465
- createThreadNotifications(payload, completeOnRunError) {
466
- if (payload.type === _ag_ui_client.EventType.RUN_FINISHED) return [rxjs.Notification.createNext(payload), rxjs.Notification.createComplete()];
456
+ createThreadNotifications(payload, options) {
457
+ if (payload.type === _ag_ui_client.EventType.RUN_FINISHED) return options.completeOnRunFinished ? [rxjs.Notification.createNext(payload), rxjs.Notification.createComplete()] : [rxjs.Notification.createNext(payload)];
467
458
  if (payload.type === _ag_ui_client.EventType.RUN_ERROR) {
468
459
  var _message;
469
460
  const errorMessage = (_message = payload.message) !== null && _message !== void 0 ? _message : "Run error";
470
- return completeOnRunError ? [rxjs.Notification.createNext(payload), rxjs.Notification.createComplete()] : [rxjs.Notification.createNext(payload), rxjs.Notification.createError(new Error(errorMessage))];
461
+ return options.completeOnRunError ? [rxjs.Notification.createNext(payload), rxjs.Notification.createComplete()] : options.errorOnRunError ? [rxjs.Notification.createNext(payload), rxjs.Notification.createError(new Error(errorMessage))] : [rxjs.Notification.createNext(payload)];
471
462
  }
472
463
  return [rxjs.Notification.createNext(payload)];
473
464
  }
@@ -476,35 +467,32 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
476
467
  const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
477
468
  return new URL(path, new URL(this.config.runtimeUrl, origin)).toString();
478
469
  }
479
- createThreadChannelDescriptor(input, streamMode, replayCursor) {
480
- const params = streamMode === "run" ? {
470
+ createThreadChannelParams(input, streamMode, replayCursor) {
471
+ return streamMode === "run" ? {
481
472
  stream_mode: "run",
482
473
  run_id: input.runId
483
474
  } : {
484
475
  stream_mode: "connect",
485
476
  last_seen_event_id: replayCursor === void 0 ? this.getReconnectCursor(input) : replayCursor
486
477
  };
487
- return {
488
- topic: `thread:${input.threadId}`,
489
- params
490
- };
491
478
  }
492
479
  getLastSeenEventId(threadId) {
493
480
  var _this$sharedState$las;
494
481
  return (_this$sharedState$las = this.sharedState.lastSeenEventIds.get(threadId)) !== null && _this$sharedState$las !== void 0 ? _this$sharedState$las : null;
495
482
  }
496
483
  getReconnectCursor(input) {
497
- return this.hasLocalThreadMessages(input) ? this.getLastSeenEventId(input.threadId) : null;
484
+ return this.getLastSeenEventId(input.threadId);
498
485
  }
499
- hasLocalThreadMessages(input) {
500
- return Array.isArray(input.messages) && input.messages.length > 0;
486
+ clearReconnectCursor(threadId) {
487
+ this.sharedState.lastSeenEventIds.delete(threadId);
501
488
  }
502
489
  updateLastSeenEventId(threadId, payload) {
503
490
  const eventId = this.readEventId(payload);
504
491
  if (!eventId) return;
505
492
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
506
493
  }
507
- setLastSeenEventId(threadId, eventId) {
494
+ updateLastSeenEventIdFromControl(threadId, payload) {
495
+ const eventId = this.readControlEventId(payload);
508
496
  if (!eventId) return;
509
497
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
510
498
  }
@@ -514,6 +502,25 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
514
502
  const runnerEventId = metadata.cpki_event_id;
515
503
  return typeof runnerEventId === "string" ? runnerEventId : null;
516
504
  }
505
+ readControlEventId(payload) {
506
+ if (!payload || typeof payload !== "object") return null;
507
+ const latestEventId = payload.latestEventId;
508
+ return typeof latestEventId === "string" ? latestEventId : null;
509
+ }
510
+ applyCanonicalRunIdentity(input, credentials, options) {
511
+ var _credentials$runId;
512
+ this.threadId = credentials.threadId;
513
+ const runId = (_credentials$runId = credentials.runId) !== null && _credentials$runId !== void 0 ? _credentials$runId : options.fallbackToInputRunId ? input.runId : null;
514
+ this.canonicalRunId = runId;
515
+ return {
516
+ ...input,
517
+ threadId: credentials.threadId,
518
+ ...runId === null ? {} : { runId }
519
+ };
520
+ }
521
+ isSocketReconnectExhaustedError(error) {
522
+ return error instanceof Error && error.message.includes("WebSocket connection failed after");
523
+ }
517
524
  };
518
525
 
519
526
  //#endregion
@@ -1339,6 +1346,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1339
1346
  this.notifySuggestionsChanged(agentId, []);
1340
1347
  }
1341
1348
  /**
1349
+ * Clear suggestions at the start of a run, but immediately restore static
1350
+ * suggestions that have `available: "always"` so they remain visible
1351
+ * throughout the run.
1352
+ */
1353
+ clearSuggestionsForRun(agentId) {
1354
+ this.clearSuggestions(agentId);
1355
+ for (const config of Object.values(this._suggestionsConfig)) {
1356
+ if (config.consumerAgentId !== void 0 && config.consumerAgentId !== "*" && config.consumerAgentId !== agentId) continue;
1357
+ if (config.available !== "always") continue;
1358
+ if (isStaticSuggestionsConfig(config)) this.addStaticSuggestions((0, _copilotkit_shared.randomUUID)(), config, agentId);
1359
+ }
1360
+ }
1361
+ /**
1342
1362
  * Get current suggestions for an agent
1343
1363
  */
1344
1364
  getSuggestions(agentId) {
@@ -1704,7 +1724,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1704
1724
  * Run an agent
1705
1725
  */
1706
1726
  async runAgent({ agent, forwardedProps }) {
1707
- if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1727
+ if (agent.agentId) this._internal.suggestionEngine.clearSuggestionsForRun(agent.agentId);
1708
1728
  if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...this._internal.headers };
1709
1729
  if (agent.detachActiveRun) await agent.detachActiveRun();
1710
1730
  this._internal.subscribeAgentToStateManager(agent);