@copilotkit/core 1.56.1 → 1.56.2-canary.pin-to-send

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
@@ -1,8 +1,8 @@
1
1
  (function(global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@ag-ui/client'), require('@copilotkit/shared'), require('rxjs'), require('rxjs/operators'), require('phoenix'), require('zod-to-json-schema'), require('rxjs/fetch')) :
3
- typeof define === 'function' && define.amd ? define(['exports', '@ag-ui/client', '@copilotkit/shared', 'rxjs', 'rxjs/operators', 'phoenix', 'zod-to-json-schema', 'rxjs/fetch'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitCore = {}), global.AgUIClient,global.CopilotKitShared,global.rxjs,global.rxjs.operators,global.phoenix,global.zodToJsonSchema,global.rxjs_fetch));
5
- })(this, function(exports, _ag_ui_client, _copilotkit_shared, rxjs, rxjs_operators, phoenix, zod_to_json_schema, rxjs_fetch) {
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@tanstack/pacer'), require('@ag-ui/client'), require('@copilotkit/shared'), require('rxjs'), require('rxjs/operators'), require('phoenix'), require('zod-to-json-schema'), require('rxjs/fetch')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', '@tanstack/pacer', '@ag-ui/client', '@copilotkit/shared', 'rxjs', 'rxjs/operators', 'phoenix', 'zod-to-json-schema', 'rxjs/fetch'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.CopilotKitCore = {}), global._tanstack_pacer,global.AgUIClient,global.CopilotKitShared,global.rxjs,global.rxjs.operators,global.phoenix,global.zodToJsonSchema,global.rxjs_fetch));
5
+ })(this, function(exports, _tanstack_pacer, _ag_ui_client, _copilotkit_shared, rxjs, rxjs_operators, phoenix, zod_to_json_schema, rxjs_fetch) {
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
7
7
 
8
8
  //#region src/utils/phoenix-observable.ts
@@ -180,7 +180,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
180
180
  _defineProperty(this, "config", void 0);
181
181
  _defineProperty(this, "socket", null);
182
182
  _defineProperty(this, "activeChannel", null);
183
- _defineProperty(this, "runId", null);
183
+ _defineProperty(this, "canonicalRunId", null);
184
184
  _defineProperty(this, "sharedState", void 0);
185
185
  this.config = config;
186
186
  this.sharedState = sharedState;
@@ -217,7 +217,11 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
217
217
  var _this$agentId;
218
218
  this.isRunning = true;
219
219
  this.agentId = (_this$agentId = this.agentId) !== null && _this$agentId !== void 0 ? _this$agentId : (0, _ag_ui_client.randomUUID)();
220
- const input = this.prepareRunAgentInput(parameters);
220
+ const effectiveParameters = (parameters === null || parameters === void 0 ? void 0 : parameters.runId) || !this.canonicalRunId ? parameters : {
221
+ ...parameters,
222
+ runId: this.canonicalRunId
223
+ };
224
+ const input = this.prepareRunAgentInput(effectiveParameters);
221
225
  let result;
222
226
  const previousMessageIds = new Set(this.messages.map((m) => m.id));
223
227
  const subscribers = [
@@ -256,14 +260,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
256
260
  }
257
261
  }
258
262
  abortRun() {
259
- if (this.activeChannel && this.runId) {
263
+ if (this.activeChannel && this.canonicalRunId) {
260
264
  const fallback = setTimeout(() => clear(), 5e3);
261
265
  const clear = () => {
262
266
  clearTimeout(fallback);
263
267
  this.detachActiveRun();
264
268
  this.cleanup();
265
269
  };
266
- this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.runId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
270
+ this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.canonicalRunId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
267
271
  } else {
268
272
  this.detachActiveRun();
269
273
  this.cleanup();
@@ -275,7 +279,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
275
279
  */
276
280
  run(input) {
277
281
  this.threadId = input.threadId;
278
- this.runId = input.runId;
282
+ this.canonicalRunId = input.runId;
279
283
  return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => this.observeThread$(input, credentials, {
280
284
  completeOnRunError: false,
281
285
  streamMode: "run"
@@ -287,16 +291,14 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
287
291
  */
288
292
  connect(input) {
289
293
  this.threadId = input.threadId;
290
- this.runId = input.runId;
294
+ this.canonicalRunId = input.runId;
291
295
  return (0, rxjs.defer)(() => this.requestConnectPlan$(input)).pipe((0, rxjs.switchMap)((plan) => {
292
296
  if (plan === null) return rxjs.EMPTY;
293
297
  if (plan.mode === "bootstrap") {
294
298
  this.setLastSeenEventId(input.threadId, plan.latestEventId);
295
- for (const event of plan.events) this.updateRunIdFromEvent(event);
296
299
  return (0, rxjs.from)(plan.events);
297
300
  }
298
301
  this.setLastSeenEventId(input.threadId, plan.joinFromEventId);
299
- for (const event of plan.events) this.updateRunIdFromEvent(event);
300
302
  return (0, rxjs.concat)((0, rxjs.from)(plan.events), this.observeThread$(input, { joinToken: plan.joinToken }, {
301
303
  completeOnRunError: true,
302
304
  streamMode: "connect",
@@ -319,7 +321,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
319
321
  if (this.socket === ownSocket) this.socket = null;
320
322
  }
321
323
  if (this.threadId) this.sharedState.lastSeenEventIds.delete(this.threadId);
322
- this.runId = null;
324
+ this.canonicalRunId = null;
323
325
  }
324
326
  cleanup() {
325
327
  this.cleanupOwned(this.activeChannel, this.socket);
@@ -455,7 +457,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
455
457
  observeThreadEvents$(threadId, channel$, options) {
456
458
  return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
457
459
  this.updateLastSeenEventId(threadId, payload);
458
- this.updateRunIdFromEvent(payload);
459
460
  }), (0, rxjs_operators.mergeMap)((payload) => (0, rxjs.from)(this.createThreadNotifications(payload, options.completeOnRunError))), (0, rxjs.dematerialize)());
460
461
  }
461
462
  observeChannelEvent$(channel, eventName) {
@@ -507,24 +508,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
507
508
  if (!eventId) return;
508
509
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
509
510
  }
510
- /**
511
- * Keep `this.runId` in sync with the backend's actual run ID.
512
- *
513
- * During a `connect` (resume) flow the client generates a fresh `runId`
514
- * via `prepareRunAgentInput`, but the backend is running under its own
515
- * run ID. If the client later sends `STOP_RUN_EVENT` with the wrong
516
- * `runId`, the gateway's runner channel will not match it and the agent
517
- * keeps running. Extracting the run ID from live events fixes this.
518
- *
519
- * The runner normalises events to `run_id` (snake_case) before pushing
520
- * to the gateway, so we check both `runId` and `run_id`.
521
- */
522
- updateRunIdFromEvent(payload) {
523
- var _record$runId;
524
- const record = payload;
525
- const eventRunId = (_record$runId = record.runId) !== null && _record$runId !== void 0 ? _record$runId : record.run_id;
526
- if (typeof eventRunId === "string" && eventRunId.length > 0) this.runId = eventRunId;
527
- }
528
511
  readEventId(payload) {
529
512
  const metadata = payload.metadata;
530
513
  if (!metadata || typeof metadata !== "object") return null;
@@ -2473,8 +2456,21 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2473
2456
  CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
2474
2457
  CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
2475
2458
  CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
2459
+ CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
2476
2460
  return CopilotKitCoreErrorCode;
2477
2461
  }({});
2462
+ /**
2463
+ * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
2464
+ * to module scope so the Set is allocated once, not per-subscription.
2465
+ */
2466
+ const ALLOWED_KEYS = new Set([
2467
+ "onMessagesChanged",
2468
+ "onStateChanged",
2469
+ "onRunInitialized",
2470
+ "onRunFinalized",
2471
+ "onRunFailed",
2472
+ "onRunErrorEvent"
2473
+ ]);
2478
2474
  let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
2479
2475
  CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
2480
2476
  CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
@@ -2543,6 +2539,16 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2543
2539
  }, "Subscriber onError error:");
2544
2540
  }
2545
2541
  /**
2542
+ * Log a message to the console and emit an error to subscribers.
2543
+ * Catches failures from `emitError` itself to prevent unhandled rejections.
2544
+ */
2545
+ logAndEmitError(message, params, logLevel = "error") {
2546
+ console[logLevel](message, params.error);
2547
+ this.emitError(params).catch((emitErr) => {
2548
+ console.error(message + " — emitError itself failed:", emitErr);
2549
+ });
2550
+ }
2551
+ /**
2546
2552
  * Snapshot accessors
2547
2553
  */
2548
2554
  get context() {
@@ -2579,17 +2585,30 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2579
2585
  return this._properties;
2580
2586
  }
2581
2587
  /**
2582
- * Default throttle interval (ms) applied by framework hooks (e.g.
2583
- * `useAgent()`) when the hook/component does not specify an explicit
2584
- * `throttleMs`. An explicit `0` passed as `throttleMs` to `useAgent()`
2585
- * or `<CopilotChat>` overrides this default and disables throttling.
2588
+ * Default throttle interval (ms) used by `subscribeToAgentWithOptions()`
2589
+ * when the caller does not specify an explicit `throttleMs`.
2590
+ * `undefined` means no default is configured; `0` means no throttling.
2586
2591
  */
2587
2592
  get defaultThrottleMs() {
2588
2593
  return this._defaultThrottleMs;
2589
2594
  }
2595
+ /**
2596
+ * Set the default throttle interval (ms) for `subscribeToAgentWithOptions()`.
2597
+ *
2598
+ * Accepts a non-negative finite number or `undefined` (to clear the
2599
+ * default). Invalid values (NaN, Infinity, negative) are logged as
2600
+ * errors and ignored — the previous valid value is preserved.
2601
+ */
2590
2602
  setDefaultThrottleMs(value) {
2591
2603
  if (value !== void 0 && (!Number.isFinite(value) || value < 0)) {
2592
- this._defaultThrottleMs = void 0;
2604
+ this.logAndEmitError(`CopilotKitCore.setDefaultThrottleMs: value must be a non-negative finite number or undefined, got ${value}. Keeping current value (${this._defaultThrottleMs}).`, {
2605
+ error: /* @__PURE__ */ new Error(`setDefaultThrottleMs: invalid value (${value}), keeping current value (${this._defaultThrottleMs})`),
2606
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2607
+ context: {
2608
+ value,
2609
+ currentValue: this._defaultThrottleMs
2610
+ }
2611
+ });
2593
2612
  return;
2594
2613
  }
2595
2614
  this._defaultThrottleMs = value;
@@ -2716,6 +2735,138 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2716
2735
  } };
2717
2736
  }
2718
2737
  /**
2738
+ * Subscribe to an agent's notification and lifecycle events with
2739
+ * optional configuration (e.g. throttling).
2740
+ *
2741
+ * Wraps every callback with error protection (`safeCall`) and applies
2742
+ * the options before delegating to `agent.subscribe()`.
2743
+ *
2744
+ * See {@link SubscribeToAgentSubscriber} for the accepted callback subset
2745
+ * and the rationale for excluding AG-UI event handlers.
2746
+ */
2747
+ subscribeToAgentWithOptions(agent, subscriber, options) {
2748
+ var _ref, _options$throttleMs;
2749
+ const resolved = (_ref = (_options$throttleMs = options === null || options === void 0 ? void 0 : options.throttleMs) !== null && _options$throttleMs !== void 0 ? _options$throttleMs : this._defaultThrottleMs) !== null && _ref !== void 0 ? _ref : 0;
2750
+ let effectiveMs = 0;
2751
+ if (!Number.isFinite(resolved) || resolved < 0) {
2752
+ const source = (options === null || options === void 0 ? void 0 : options.throttleMs) !== void 0 ? "throttleMs" : "defaultThrottleMs";
2753
+ this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`, {
2754
+ error: /* @__PURE__ */ new Error(`subscribeToAgentWithOptions: invalid ${source} (${resolved}), falling back to unthrottled`),
2755
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2756
+ context: {
2757
+ agentId: agent.agentId,
2758
+ source,
2759
+ value: resolved
2760
+ }
2761
+ });
2762
+ } else effectiveMs = resolved;
2763
+ const agentLabel = agent.agentId || "(unknown agent)";
2764
+ const safeCall = (label, fn, ...args) => {
2765
+ const reportError = (err, verb) => {
2766
+ this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions[${agentLabel}]: ${label} callback ${verb}:`, {
2767
+ error: err instanceof Error ? err : new Error(String(err)),
2768
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2769
+ context: {
2770
+ agentId: agent.agentId,
2771
+ callback: label
2772
+ }
2773
+ });
2774
+ };
2775
+ try {
2776
+ const result = fn(...args);
2777
+ if (result instanceof Promise) return result.catch((err) => {
2778
+ reportError(err, "rejected");
2779
+ });
2780
+ return result;
2781
+ } catch (err) {
2782
+ reportError(err, "threw");
2783
+ }
2784
+ };
2785
+ const guardAll = (sub) => {
2786
+ const guarded = {};
2787
+ if (sub.onMessagesChanged) {
2788
+ const fn = sub.onMessagesChanged;
2789
+ guarded.onMessagesChanged = (params) => safeCall("onMessagesChanged", fn, params);
2790
+ }
2791
+ if (sub.onStateChanged) {
2792
+ const fn = sub.onStateChanged;
2793
+ guarded.onStateChanged = (params) => safeCall("onStateChanged", fn, params);
2794
+ }
2795
+ if (sub.onRunInitialized) {
2796
+ const fn = sub.onRunInitialized;
2797
+ guarded.onRunInitialized = (params) => safeCall("onRunInitialized", fn, params);
2798
+ }
2799
+ if (sub.onRunFinalized) {
2800
+ const fn = sub.onRunFinalized;
2801
+ guarded.onRunFinalized = (params) => safeCall("onRunFinalized", fn, params);
2802
+ }
2803
+ if (sub.onRunFailed) {
2804
+ const fn = sub.onRunFailed;
2805
+ guarded.onRunFailed = (params) => safeCall("onRunFailed", fn, params);
2806
+ }
2807
+ if (sub.onRunErrorEvent) {
2808
+ const fn = sub.onRunErrorEvent;
2809
+ guarded.onRunErrorEvent = (params) => safeCall("onRunErrorEvent", fn, params);
2810
+ }
2811
+ return guarded;
2812
+ };
2813
+ for (const key of Object.keys(subscriber)) if (typeof subscriber[key] === "function" && !ALLOWED_KEYS.has(key)) {
2814
+ const message = `CopilotKitCore.subscribeToAgentWithOptions[${agentLabel}]: callback "${key}" is not supported and was dropped. Supported callbacks: ${Array.from(ALLOWED_KEYS).join(", ")}. Use agent.subscribe() directly for event handlers and per-item notifications.`;
2815
+ this.logAndEmitError(message, {
2816
+ error: new Error(message),
2817
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2818
+ context: {
2819
+ agentId: agent.agentId,
2820
+ droppedCallback: key
2821
+ }
2822
+ }, "warn");
2823
+ }
2824
+ if (effectiveMs <= 0) {
2825
+ const subscription = agent.subscribe(guardAll(subscriber));
2826
+ return { unsubscribe: () => subscription.unsubscribe() };
2827
+ }
2828
+ let active = true;
2829
+ let latestMessagesParams = null;
2830
+ let latestStateParams = null;
2831
+ const flushPending = () => {
2832
+ if (active && subscriber.onMessagesChanged && latestMessagesParams) {
2833
+ const params = latestMessagesParams;
2834
+ latestMessagesParams = null;
2835
+ safeCall("onMessagesChanged", subscriber.onMessagesChanged, params);
2836
+ }
2837
+ if (active && subscriber.onStateChanged && latestStateParams) {
2838
+ const params = latestStateParams;
2839
+ latestStateParams = null;
2840
+ safeCall("onStateChanged", subscriber.onStateChanged, params);
2841
+ }
2842
+ };
2843
+ const throttler = new _tanstack_pacer.Throttler(flushPending, {
2844
+ wait: effectiveMs,
2845
+ leading: true,
2846
+ trailing: true
2847
+ });
2848
+ const lifecycleOnly = {};
2849
+ if (subscriber.onRunInitialized) lifecycleOnly.onRunInitialized = subscriber.onRunInitialized;
2850
+ if (subscriber.onRunFinalized) lifecycleOnly.onRunFinalized = subscriber.onRunFinalized;
2851
+ if (subscriber.onRunFailed) lifecycleOnly.onRunFailed = subscriber.onRunFailed;
2852
+ if (subscriber.onRunErrorEvent) lifecycleOnly.onRunErrorEvent = subscriber.onRunErrorEvent;
2853
+ const wrappedSubscriber = guardAll(lifecycleOnly);
2854
+ if (subscriber.onMessagesChanged) wrappedSubscriber.onMessagesChanged = (params) => {
2855
+ latestMessagesParams = params;
2856
+ throttler.maybeExecute();
2857
+ };
2858
+ if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
2859
+ latestStateParams = params;
2860
+ throttler.maybeExecute();
2861
+ };
2862
+ const subscription = agent.subscribe(wrappedSubscriber);
2863
+ return { unsubscribe: () => {
2864
+ active = false;
2865
+ throttler.cancel();
2866
+ subscription.unsubscribe();
2867
+ } };
2868
+ }
2869
+ /**
2719
2870
  * Agent connectivity (delegated to RunHandler)
2720
2871
  */
2721
2872
  async connectAgent(params) {
@@ -3264,15 +3415,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3264
3415
  threadUpserted: props(),
3265
3416
  threadDeleted: props()
3266
3417
  });
3267
- function sortThreadsByUpdatedAt(threads) {
3268
- return [...threads].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
3418
+ function sortThreadsByRecency(threads) {
3419
+ return [...threads].sort((left, right) => {
3420
+ var _ref, _left$lastRunAt, _ref2, _right$lastRunAt;
3421
+ const leftKey = (_ref = (_left$lastRunAt = left.lastRunAt) !== null && _left$lastRunAt !== void 0 ? _left$lastRunAt : left.updatedAt) !== null && _ref !== void 0 ? _ref : left.createdAt;
3422
+ return ((_ref2 = (_right$lastRunAt = right.lastRunAt) !== null && _right$lastRunAt !== void 0 ? _right$lastRunAt : right.updatedAt) !== null && _ref2 !== void 0 ? _ref2 : right.createdAt).localeCompare(leftKey);
3423
+ });
3269
3424
  }
3270
3425
  function upsertThread(threads, thread) {
3271
3426
  const existingIndex = threads.findIndex((item) => item.id === thread.id);
3272
- if (existingIndex === -1) return sortThreadsByUpdatedAt([...threads, thread]);
3427
+ if (existingIndex === -1) return sortThreadsByRecency([...threads, thread]);
3273
3428
  const next = [...threads];
3274
3429
  next[existingIndex] = thread;
3275
- return sortThreadsByUpdatedAt(next);
3430
+ return sortThreadsByRecency(next);
3276
3431
  }
3277
3432
  const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
3278
3433
  ...state,
@@ -3305,7 +3460,7 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
3305
3460
  if (sessionId !== state.sessionId) return state;
3306
3461
  return {
3307
3462
  ...state,
3308
- threads: sortThreadsByUpdatedAt(threads),
3463
+ threads: sortThreadsByRecency(threads),
3309
3464
  isLoading: false,
3310
3465
  error: null,
3311
3466
  metadataJoinCode: joinCode,