@copilotkit/core 1.56.0 → 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.cjs CHANGED
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ let _tanstack_pacer = require("@tanstack/pacer");
2
3
  let _ag_ui_client = require("@ag-ui/client");
3
4
  let _copilotkit_shared = require("@copilotkit/shared");
4
5
  let rxjs = require("rxjs");
@@ -138,7 +139,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
138
139
  config;
139
140
  socket = null;
140
141
  activeChannel = null;
141
- runId = null;
142
+ canonicalRunId = null;
142
143
  sharedState;
143
144
  constructor(config, sharedState = { lastSeenEventIds: /* @__PURE__ */ new Map() }) {
144
145
  super();
@@ -176,7 +177,11 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
176
177
  try {
177
178
  this.isRunning = true;
178
179
  this.agentId = this.agentId ?? (0, _ag_ui_client.randomUUID)();
179
- const input = this.prepareRunAgentInput(parameters);
180
+ const effectiveParameters = parameters?.runId || !this.canonicalRunId ? parameters : {
181
+ ...parameters,
182
+ runId: this.canonicalRunId
183
+ };
184
+ const input = this.prepareRunAgentInput(effectiveParameters);
180
185
  let result;
181
186
  const previousMessageIds = new Set(this.messages.map((m) => m.id));
182
187
  const subscribers = [
@@ -215,14 +220,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
215
220
  }
216
221
  }
217
222
  abortRun() {
218
- if (this.activeChannel && this.runId) {
223
+ if (this.activeChannel && this.canonicalRunId) {
219
224
  const fallback = setTimeout(() => clear(), 5e3);
220
225
  const clear = () => {
221
226
  clearTimeout(fallback);
222
227
  this.detachActiveRun();
223
228
  this.cleanup();
224
229
  };
225
- this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.runId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
230
+ this.activeChannel.push(STOP_RUN_EVENT, { run_id: this.canonicalRunId }).receive("ok", clear).receive("error", clear).receive("timeout", clear);
226
231
  } else {
227
232
  this.detachActiveRun();
228
233
  this.cleanup();
@@ -234,7 +239,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
234
239
  */
235
240
  run(input) {
236
241
  this.threadId = input.threadId;
237
- this.runId = input.runId;
242
+ this.canonicalRunId = input.runId;
238
243
  return (0, rxjs.defer)(() => this.requestJoinCredentials$("run", input)).pipe((0, rxjs.switchMap)((credentials) => this.observeThread$(input, credentials, {
239
244
  completeOnRunError: false,
240
245
  streamMode: "run"
@@ -246,16 +251,14 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
246
251
  */
247
252
  connect(input) {
248
253
  this.threadId = input.threadId;
249
- this.runId = input.runId;
254
+ this.canonicalRunId = input.runId;
250
255
  return (0, rxjs.defer)(() => this.requestConnectPlan$(input)).pipe((0, rxjs.switchMap)((plan) => {
251
256
  if (plan === null) return rxjs.EMPTY;
252
257
  if (plan.mode === "bootstrap") {
253
258
  this.setLastSeenEventId(input.threadId, plan.latestEventId);
254
- for (const event of plan.events) this.updateRunIdFromEvent(event);
255
259
  return (0, rxjs.from)(plan.events);
256
260
  }
257
261
  this.setLastSeenEventId(input.threadId, plan.joinFromEventId);
258
- for (const event of plan.events) this.updateRunIdFromEvent(event);
259
262
  return (0, rxjs.concat)((0, rxjs.from)(plan.events), this.observeThread$(input, { joinToken: plan.joinToken }, {
260
263
  completeOnRunError: true,
261
264
  streamMode: "connect",
@@ -278,7 +281,7 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
278
281
  if (this.socket === ownSocket) this.socket = null;
279
282
  }
280
283
  if (this.threadId) this.sharedState.lastSeenEventIds.delete(this.threadId);
281
- this.runId = null;
284
+ this.canonicalRunId = null;
282
285
  }
283
286
  cleanup() {
284
287
  this.cleanupOwned(this.activeChannel, this.socket);
@@ -414,7 +417,6 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
414
417
  observeThreadEvents$(threadId, channel$, options) {
415
418
  return channel$.pipe((0, rxjs_operators.switchMap)(({ channel }) => this.observeChannelEvent$(channel, CLIENT_AG_UI_EVENT)), (0, rxjs_operators.tap)((payload) => {
416
419
  this.updateLastSeenEventId(threadId, payload);
417
- this.updateRunIdFromEvent(payload);
418
420
  }), (0, rxjs_operators.mergeMap)((payload) => (0, rxjs.from)(this.createThreadNotifications(payload, options.completeOnRunError))), (0, rxjs.dematerialize)());
419
421
  }
420
422
  observeChannelEvent$(channel, eventName) {
@@ -464,23 +466,6 @@ var IntelligenceAgent = class IntelligenceAgent extends _ag_ui_client.AbstractAg
464
466
  if (!eventId) return;
465
467
  this.sharedState.lastSeenEventIds.set(threadId, eventId);
466
468
  }
467
- /**
468
- * Keep `this.runId` in sync with the backend's actual run ID.
469
- *
470
- * During a `connect` (resume) flow the client generates a fresh `runId`
471
- * via `prepareRunAgentInput`, but the backend is running under its own
472
- * run ID. If the client later sends `STOP_RUN_EVENT` with the wrong
473
- * `runId`, the gateway's runner channel will not match it and the agent
474
- * keeps running. Extracting the run ID from live events fixes this.
475
- *
476
- * The runner normalises events to `run_id` (snake_case) before pushing
477
- * to the gateway, so we check both `runId` and `run_id`.
478
- */
479
- updateRunIdFromEvent(payload) {
480
- const record = payload;
481
- const eventRunId = record.runId ?? record.run_id;
482
- if (typeof eventRunId === "string" && eventRunId.length > 0) this.runId = eventRunId;
483
- }
484
469
  readEventId(payload) {
485
470
  const metadata = payload.metadata;
486
471
  if (!metadata || typeof metadata !== "object") return null;
@@ -858,6 +843,7 @@ var AgentRegistry = class {
858
843
  initialize(agents) {
859
844
  this.localAgents = this.assignAgentIds(agents);
860
845
  this.applyHeadersToAgents(this.localAgents);
846
+ this.applyCredentialsToAgents(this.localAgents);
861
847
  this._agents = this.localAgents;
862
848
  }
863
849
  /**
@@ -887,6 +873,7 @@ var AgentRegistry = class {
887
873
  ...this.remoteAgents
888
874
  };
889
875
  this.applyHeadersToAgents(this._agents);
876
+ this.applyCredentialsToAgents(this._agents);
890
877
  this.notifyAgentsChanged();
891
878
  }
892
879
  /**
@@ -896,6 +883,7 @@ var AgentRegistry = class {
896
883
  this.validateAndAssignAgentId(id, agent);
897
884
  this.localAgents[id] = agent;
898
885
  this.applyHeadersToAgent(agent);
886
+ this.applyCredentialsToAgent(agent);
899
887
  this._agents = {
900
888
  ...this.localAgents,
901
889
  ...this.remoteAgents
@@ -1956,7 +1944,7 @@ var RunHandler = class {
1956
1944
  * Build frontend tools for an agent
1957
1945
  */
1958
1946
  buildFrontendTools(agentId) {
1959
- return this._tools.filter((tool) => tool.available !== false && (!tool.agentId || tool.agentId === agentId)).map((tool) => ({
1947
+ return this._tools.filter((tool) => tool.available !== false && tool.available !== "disabled" && (!tool.agentId || tool.agentId === agentId)).map((tool) => ({
1960
1948
  name: tool.name,
1961
1949
  description: tool.description ?? "",
1962
1950
  parameters: createToolSchema(tool)
@@ -2306,8 +2294,21 @@ let CopilotKitCoreErrorCode = /* @__PURE__ */ function(CopilotKitCoreErrorCode)
2306
2294
  CopilotKitCoreErrorCode["TRANSCRIPTION_RATE_LIMITED"] = "transcription_rate_limited";
2307
2295
  CopilotKitCoreErrorCode["TRANSCRIPTION_AUTH_FAILED"] = "transcription_auth_failed";
2308
2296
  CopilotKitCoreErrorCode["TRANSCRIPTION_NETWORK_ERROR"] = "transcription_network_error";
2297
+ CopilotKitCoreErrorCode["SUBSCRIBER_CALLBACK_FAILED"] = "subscriber_callback_failed";
2309
2298
  return CopilotKitCoreErrorCode;
2310
2299
  }({});
2300
+ /**
2301
+ * Runtime allowlist derived from {@link SUBSCRIBE_TO_AGENT_KEYS}. Hoisted
2302
+ * to module scope so the Set is allocated once, not per-subscription.
2303
+ */
2304
+ const ALLOWED_KEYS = new Set([
2305
+ "onMessagesChanged",
2306
+ "onStateChanged",
2307
+ "onRunInitialized",
2308
+ "onRunFinalized",
2309
+ "onRunFailed",
2310
+ "onRunErrorEvent"
2311
+ ]);
2311
2312
  let CopilotKitCoreRuntimeConnectionStatus = /* @__PURE__ */ function(CopilotKitCoreRuntimeConnectionStatus) {
2312
2313
  CopilotKitCoreRuntimeConnectionStatus["Disconnected"] = "disconnected";
2313
2314
  CopilotKitCoreRuntimeConnectionStatus["Connected"] = "connected";
@@ -2373,6 +2374,16 @@ var CopilotKitCore = class {
2373
2374
  }), "Subscriber onError error:");
2374
2375
  }
2375
2376
  /**
2377
+ * Log a message to the console and emit an error to subscribers.
2378
+ * Catches failures from `emitError` itself to prevent unhandled rejections.
2379
+ */
2380
+ logAndEmitError(message, params, logLevel = "error") {
2381
+ console[logLevel](message, params.error);
2382
+ this.emitError(params).catch((emitErr) => {
2383
+ console.error(message + " — emitError itself failed:", emitErr);
2384
+ });
2385
+ }
2386
+ /**
2376
2387
  * Snapshot accessors
2377
2388
  */
2378
2389
  get context() {
@@ -2409,17 +2420,30 @@ var CopilotKitCore = class {
2409
2420
  return this._properties;
2410
2421
  }
2411
2422
  /**
2412
- * Default throttle interval (ms) applied by framework hooks (e.g.
2413
- * `useAgent()`) when the hook/component does not specify an explicit
2414
- * `throttleMs`. An explicit `0` passed as `throttleMs` to `useAgent()`
2415
- * or `<CopilotChat>` overrides this default and disables throttling.
2423
+ * Default throttle interval (ms) used by `subscribeToAgentWithOptions()`
2424
+ * when the caller does not specify an explicit `throttleMs`.
2425
+ * `undefined` means no default is configured; `0` means no throttling.
2416
2426
  */
2417
2427
  get defaultThrottleMs() {
2418
2428
  return this._defaultThrottleMs;
2419
2429
  }
2430
+ /**
2431
+ * Set the default throttle interval (ms) for `subscribeToAgentWithOptions()`.
2432
+ *
2433
+ * Accepts a non-negative finite number or `undefined` (to clear the
2434
+ * default). Invalid values (NaN, Infinity, negative) are logged as
2435
+ * errors and ignored — the previous valid value is preserved.
2436
+ */
2420
2437
  setDefaultThrottleMs(value) {
2421
2438
  if (value !== void 0 && (!Number.isFinite(value) || value < 0)) {
2422
- this._defaultThrottleMs = void 0;
2439
+ this.logAndEmitError(`CopilotKitCore.setDefaultThrottleMs: value must be a non-negative finite number or undefined, got ${value}. Keeping current value (${this._defaultThrottleMs}).`, {
2440
+ error: /* @__PURE__ */ new Error(`setDefaultThrottleMs: invalid value (${value}), keeping current value (${this._defaultThrottleMs})`),
2441
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2442
+ context: {
2443
+ value,
2444
+ currentValue: this._defaultThrottleMs
2445
+ }
2446
+ });
2423
2447
  return;
2424
2448
  }
2425
2449
  this._defaultThrottleMs = value;
@@ -2540,6 +2564,137 @@ var CopilotKitCore = class {
2540
2564
  } };
2541
2565
  }
2542
2566
  /**
2567
+ * Subscribe to an agent's notification and lifecycle events with
2568
+ * optional configuration (e.g. throttling).
2569
+ *
2570
+ * Wraps every callback with error protection (`safeCall`) and applies
2571
+ * the options before delegating to `agent.subscribe()`.
2572
+ *
2573
+ * See {@link SubscribeToAgentSubscriber} for the accepted callback subset
2574
+ * and the rationale for excluding AG-UI event handlers.
2575
+ */
2576
+ subscribeToAgentWithOptions(agent, subscriber, options) {
2577
+ const resolved = options?.throttleMs ?? this._defaultThrottleMs ?? 0;
2578
+ let effectiveMs = 0;
2579
+ if (!Number.isFinite(resolved) || resolved < 0) {
2580
+ const source = options?.throttleMs !== void 0 ? "throttleMs" : "defaultThrottleMs";
2581
+ this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`, {
2582
+ error: /* @__PURE__ */ new Error(`subscribeToAgentWithOptions: invalid ${source} (${resolved}), falling back to unthrottled`),
2583
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2584
+ context: {
2585
+ agentId: agent.agentId,
2586
+ source,
2587
+ value: resolved
2588
+ }
2589
+ });
2590
+ } else effectiveMs = resolved;
2591
+ const agentLabel = agent.agentId || "(unknown agent)";
2592
+ const safeCall = (label, fn, ...args) => {
2593
+ const reportError = (err, verb) => {
2594
+ this.logAndEmitError(`CopilotKitCore.subscribeToAgentWithOptions[${agentLabel}]: ${label} callback ${verb}:`, {
2595
+ error: err instanceof Error ? err : new Error(String(err)),
2596
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2597
+ context: {
2598
+ agentId: agent.agentId,
2599
+ callback: label
2600
+ }
2601
+ });
2602
+ };
2603
+ try {
2604
+ const result = fn(...args);
2605
+ if (result instanceof Promise) return result.catch((err) => {
2606
+ reportError(err, "rejected");
2607
+ });
2608
+ return result;
2609
+ } catch (err) {
2610
+ reportError(err, "threw");
2611
+ }
2612
+ };
2613
+ const guardAll = (sub) => {
2614
+ const guarded = {};
2615
+ if (sub.onMessagesChanged) {
2616
+ const fn = sub.onMessagesChanged;
2617
+ guarded.onMessagesChanged = (params) => safeCall("onMessagesChanged", fn, params);
2618
+ }
2619
+ if (sub.onStateChanged) {
2620
+ const fn = sub.onStateChanged;
2621
+ guarded.onStateChanged = (params) => safeCall("onStateChanged", fn, params);
2622
+ }
2623
+ if (sub.onRunInitialized) {
2624
+ const fn = sub.onRunInitialized;
2625
+ guarded.onRunInitialized = (params) => safeCall("onRunInitialized", fn, params);
2626
+ }
2627
+ if (sub.onRunFinalized) {
2628
+ const fn = sub.onRunFinalized;
2629
+ guarded.onRunFinalized = (params) => safeCall("onRunFinalized", fn, params);
2630
+ }
2631
+ if (sub.onRunFailed) {
2632
+ const fn = sub.onRunFailed;
2633
+ guarded.onRunFailed = (params) => safeCall("onRunFailed", fn, params);
2634
+ }
2635
+ if (sub.onRunErrorEvent) {
2636
+ const fn = sub.onRunErrorEvent;
2637
+ guarded.onRunErrorEvent = (params) => safeCall("onRunErrorEvent", fn, params);
2638
+ }
2639
+ return guarded;
2640
+ };
2641
+ for (const key of Object.keys(subscriber)) if (typeof subscriber[key] === "function" && !ALLOWED_KEYS.has(key)) {
2642
+ 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.`;
2643
+ this.logAndEmitError(message, {
2644
+ error: new Error(message),
2645
+ code: CopilotKitCoreErrorCode.SUBSCRIBER_CALLBACK_FAILED,
2646
+ context: {
2647
+ agentId: agent.agentId,
2648
+ droppedCallback: key
2649
+ }
2650
+ }, "warn");
2651
+ }
2652
+ if (effectiveMs <= 0) {
2653
+ const subscription = agent.subscribe(guardAll(subscriber));
2654
+ return { unsubscribe: () => subscription.unsubscribe() };
2655
+ }
2656
+ let active = true;
2657
+ let latestMessagesParams = null;
2658
+ let latestStateParams = null;
2659
+ const flushPending = () => {
2660
+ if (active && subscriber.onMessagesChanged && latestMessagesParams) {
2661
+ const params = latestMessagesParams;
2662
+ latestMessagesParams = null;
2663
+ safeCall("onMessagesChanged", subscriber.onMessagesChanged, params);
2664
+ }
2665
+ if (active && subscriber.onStateChanged && latestStateParams) {
2666
+ const params = latestStateParams;
2667
+ latestStateParams = null;
2668
+ safeCall("onStateChanged", subscriber.onStateChanged, params);
2669
+ }
2670
+ };
2671
+ const throttler = new _tanstack_pacer.Throttler(flushPending, {
2672
+ wait: effectiveMs,
2673
+ leading: true,
2674
+ trailing: true
2675
+ });
2676
+ const lifecycleOnly = {};
2677
+ if (subscriber.onRunInitialized) lifecycleOnly.onRunInitialized = subscriber.onRunInitialized;
2678
+ if (subscriber.onRunFinalized) lifecycleOnly.onRunFinalized = subscriber.onRunFinalized;
2679
+ if (subscriber.onRunFailed) lifecycleOnly.onRunFailed = subscriber.onRunFailed;
2680
+ if (subscriber.onRunErrorEvent) lifecycleOnly.onRunErrorEvent = subscriber.onRunErrorEvent;
2681
+ const wrappedSubscriber = guardAll(lifecycleOnly);
2682
+ if (subscriber.onMessagesChanged) wrappedSubscriber.onMessagesChanged = (params) => {
2683
+ latestMessagesParams = params;
2684
+ throttler.maybeExecute();
2685
+ };
2686
+ if (subscriber.onStateChanged) wrappedSubscriber.onStateChanged = (params) => {
2687
+ latestStateParams = params;
2688
+ throttler.maybeExecute();
2689
+ };
2690
+ const subscription = agent.subscribe(wrappedSubscriber);
2691
+ return { unsubscribe: () => {
2692
+ active = false;
2693
+ throttler.cancel();
2694
+ subscription.unsubscribe();
2695
+ } };
2696
+ }
2697
+ /**
2543
2698
  * Agent connectivity (delegated to RunHandler)
2544
2699
  */
2545
2700
  async connectAgent(params) {
@@ -3086,15 +3241,18 @@ const threadDomainEvents = createActionGroup("Thread Domain", {
3086
3241
  threadUpserted: props(),
3087
3242
  threadDeleted: props()
3088
3243
  });
3089
- function sortThreadsByUpdatedAt(threads) {
3090
- return [...threads].sort((left, right) => right.updatedAt.localeCompare(left.updatedAt));
3244
+ function sortThreadsByRecency(threads) {
3245
+ return [...threads].sort((left, right) => {
3246
+ const leftKey = left.lastRunAt ?? left.updatedAt ?? left.createdAt;
3247
+ return (right.lastRunAt ?? right.updatedAt ?? right.createdAt).localeCompare(leftKey);
3248
+ });
3091
3249
  }
3092
3250
  function upsertThread(threads, thread) {
3093
3251
  const existingIndex = threads.findIndex((item) => item.id === thread.id);
3094
- if (existingIndex === -1) return sortThreadsByUpdatedAt([...threads, thread]);
3252
+ if (existingIndex === -1) return sortThreadsByRecency([...threads, thread]);
3095
3253
  const next = [...threads];
3096
3254
  next[existingIndex] = thread;
3097
- return sortThreadsByUpdatedAt(next);
3255
+ return sortThreadsByRecency(next);
3098
3256
  }
3099
3257
  const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.contextChanged, (state, { context }) => ({
3100
3258
  ...state,
@@ -3127,7 +3285,7 @@ const threadReducer = createReducer(initialThreadState, on(threadAdapterEvents.c
3127
3285
  if (sessionId !== state.sessionId) return state;
3128
3286
  return {
3129
3287
  ...state,
3130
- threads: sortThreadsByUpdatedAt(threads),
3288
+ threads: sortThreadsByRecency(threads),
3131
3289
  isLoading: false,
3132
3290
  error: null,
3133
3291
  metadataJoinCode: joinCode,