@copilotkit/core 1.57.0 → 1.57.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
@@ -502,6 +502,7 @@ function withAbortErrorHandling(observable) {
502
502
  var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui_client.HttpAgent {
503
503
  runtimeUrl;
504
504
  credentials;
505
+ runtimeAgentId;
505
506
  transport;
506
507
  singleEndpointUrl;
507
508
  runtimeMode;
@@ -512,7 +513,8 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
512
513
  constructor(config) {
513
514
  const normalizedRuntimeUrl = config.runtimeUrl ? config.runtimeUrl.replace(/\/$/, "") : void 0;
514
515
  const transport = config.transport ?? "auto";
515
- const runUrl = transport === "single" ? normalizedRuntimeUrl ?? config.runtimeUrl ?? "" : `${normalizedRuntimeUrl ?? config.runtimeUrl}/agent/${encodeURIComponent(config.agentId ?? "")}/run`;
516
+ const routedId = config.runtimeAgentId ?? config.agentId ?? "";
517
+ const runUrl = transport === "single" ? normalizedRuntimeUrl ?? config.runtimeUrl ?? "" : `${normalizedRuntimeUrl ?? config.runtimeUrl}/agent/${encodeURIComponent(routedId)}/run`;
516
518
  if (!runUrl) throw new Error("ProxiedCopilotRuntimeAgent requires a runtimeUrl when transport is set to 'single'.");
517
519
  super({
518
520
  ...config,
@@ -520,6 +522,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
520
522
  });
521
523
  this.runtimeUrl = normalizedRuntimeUrl ?? config.runtimeUrl;
522
524
  this.credentials = config.credentials;
525
+ this.runtimeAgentId = config.runtimeAgentId;
523
526
  this.transport = transport;
524
527
  this.runtimeMode = config.runtimeMode ?? _copilotkit_shared.RUNTIME_MODE_SSE;
525
528
  this.intelligence = config.intelligence;
@@ -527,6 +530,21 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
527
530
  if (config.debug) this.debug = config.debug;
528
531
  if (this.transport === "single") this.singleEndpointUrl = this.runtimeUrl;
529
532
  }
533
+ /**
534
+ * The agent id used for outbound runtime requests — `runtimeAgentId` when
535
+ * set (manually-registered proxy), otherwise `agentId` (registry id
536
+ * matches runtime id). Subscriber bookkeeping keeps using `agentId`
537
+ * directly.
538
+ *
539
+ * Throws when both are unset: a proxy reaching an HTTP path with no
540
+ * routable id is a bug, and a missing id would otherwise produce a
541
+ * malformed `/agent//run` or `/agent/undefined/connect` URL silently.
542
+ */
543
+ routedAgentId() {
544
+ const id = this.runtimeAgentId ?? this.agentId;
545
+ if (!id) throw new Error("ProxiedCopilotRuntimeAgent: cannot make a runtime request without an agentId or runtimeAgentId.");
546
+ return id;
547
+ }
530
548
  get capabilities() {
531
549
  return this._capabilities;
532
550
  }
@@ -546,6 +564,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
546
564
  }
547
565
  if (!this.agentId || !this.threadId) return;
548
566
  if (typeof fetch === "undefined") return;
567
+ const routedId = this.routedAgentId();
549
568
  if (this.transport === "single") {
550
569
  if (!this.singleEndpointUrl) return;
551
570
  const headers = new Headers({
@@ -558,7 +577,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
558
577
  body: JSON.stringify({
559
578
  method: "agent/stop",
560
579
  params: {
561
- agentId: this.agentId,
580
+ agentId: routedId,
562
581
  threadId: this.threadId
563
582
  }
564
583
  }),
@@ -569,7 +588,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
569
588
  return;
570
589
  }
571
590
  if (!this.runtimeUrl) return;
572
- const stopPath = `${this.runtimeUrl}/agent/${encodeURIComponent(this.agentId)}/stop/${encodeURIComponent(this.threadId)}`;
591
+ const stopPath = `${this.runtimeUrl}/agent/${encodeURIComponent(routedId)}/stop/${encodeURIComponent(this.threadId)}`;
573
592
  const origin = typeof window !== "undefined" && window.location ? window.location.origin : "http://localhost";
574
593
  const base = new URL(this.runtimeUrl, origin);
575
594
  const stopUrl = new URL(stopPath, base);
@@ -633,12 +652,13 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
633
652
  return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.connect(input))));
634
653
  }
635
654
  #connectViaHttp(input) {
655
+ const routedId = this.routedAgentId();
636
656
  if (this.transport === "single") {
637
657
  if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
638
- const requestInit = this.createSingleRouteRequestInit(input, "agent/connect", { agentId: this.agentId });
658
+ const requestInit = this.createSingleRouteRequestInit(input, "agent/connect", { agentId: routedId });
639
659
  return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(this.singleEndpointUrl, requestInit)));
640
660
  }
641
- return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(`${this.runtimeUrl}/agent/${this.agentId}/connect`, this.requestInit(input))));
661
+ return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(`${this.runtimeUrl}/agent/${routedId}/connect`, this.requestInit(input))));
642
662
  }
643
663
  #runViaDelegate(input) {
644
664
  return (0, rxjs.defer)(() => (0, rxjs.from)(this.resolveDelegate())).pipe((0, rxjs_operators.switchMap)((delegate) => withAbortErrorHandling(delegate.run(input))));
@@ -646,7 +666,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
646
666
  #runViaHttp(input) {
647
667
  if (this.transport === "single") {
648
668
  if (!this.singleEndpointUrl) throw new Error("Single endpoint transport requires a runtimeUrl");
649
- const requestInit = this.createSingleRouteRequestInit(input, "agent/run", { agentId: this.agentId });
669
+ const requestInit = this.createSingleRouteRequestInit(input, "agent/run", { agentId: this.routedAgentId() });
650
670
  return withAbortErrorHandling((0, _ag_ui_client.transformHttpEventStream)((0, _ag_ui_client.runHttpRequest)(this.singleEndpointUrl, requestInit)));
651
671
  }
652
672
  return withAbortErrorHandling(super.run(input));
@@ -655,6 +675,7 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
655
675
  const cloned = new ProxiedCopilotRuntimeAgent({
656
676
  runtimeUrl: this.runtimeUrl,
657
677
  agentId: this.agentId,
678
+ runtimeAgentId: this.runtimeAgentId,
658
679
  description: this.description,
659
680
  headers: { ...this.headers },
660
681
  credentials: this.credentials,
@@ -763,17 +784,18 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
763
784
  };
764
785
  }
765
786
  createIntelligenceDelegate() {
766
- if (!this.runtimeUrl || !this.agentId || !this.intelligence?.wsUrl) throw new Error("Intelligence mode requires runtimeUrl, agentId, and intelligence websocket metadata");
787
+ const routedId = this.routedAgentId();
788
+ if (!this.runtimeUrl || !routedId || !this.intelligence?.wsUrl) throw new Error("Intelligence mode requires runtimeUrl, agentId, and intelligence websocket metadata");
767
789
  return new IntelligenceAgent({
768
790
  url: this.intelligence.wsUrl,
769
791
  runtimeUrl: this.runtimeUrl,
770
- agentId: this.agentId,
792
+ agentId: routedId,
771
793
  headers: { ...this.headers },
772
794
  credentials: this.credentials
773
795
  });
774
796
  }
775
797
  syncDelegate(delegate) {
776
- delegate.agentId = this.agentId;
798
+ delegate.agentId = this.routedAgentId();
777
799
  delegate.description = this.description;
778
800
  delegate.threadId = this.threadId;
779
801
  delegate.setMessages(this.messages);
@@ -907,6 +929,52 @@ var AgentRegistry = class {
907
929
  this.notifyAgentsChanged();
908
930
  }
909
931
  /**
932
+ * Register a proxied agent that routes outbound runtime requests to an
933
+ * existing runtime agent (`runtimeAgentId`) while exposing a distinct local
934
+ * registry id (`agentId`). Throws if `agentId` is already taken by either a
935
+ * local or runtime-discovered agent.
936
+ *
937
+ * Use this to mount multiple frontend agents against a single runtime
938
+ * agent (e.g. a chat-1 / chat-2 pair both proxying to "default") without
939
+ * implicit per-thread cloning. The returned `unregister` removes the proxy
940
+ * from the registry and emits `onAgentsChanged`.
941
+ */
942
+ registerProxiedAgent({ agentId, runtimeAgentId }) {
943
+ if (Object.prototype.hasOwnProperty.call(this._agents, agentId)) throw new Error(`CopilotKitCore.registerProxiedAgent: agentId "${agentId}" is already registered. Pick a different agentId, or unregister the existing agent first.`);
944
+ const friends = this.core;
945
+ const debug = friends.debug;
946
+ const agent = new ProxiedCopilotRuntimeAgent({
947
+ runtimeUrl: this._runtimeUrl,
948
+ agentId,
949
+ runtimeAgentId,
950
+ transport: this._runtimeTransport,
951
+ credentials: friends.credentials,
952
+ runtimeMode: this._runtimeUrl ? this._runtimeConnectionStatus === CopilotKitCoreRuntimeConnectionStatus.Connected ? this._runtimeMode : "pending" : _copilotkit_shared.RUNTIME_MODE_SSE,
953
+ intelligence: this._intelligence,
954
+ debug: debug ? (0, _copilotkit_shared.resolveDebugConfig)(debug) : void 0
955
+ });
956
+ this.applyHeadersToAgent(agent);
957
+ this.localAgents[agentId] = agent;
958
+ this._agents = {
959
+ ...this.localAgents,
960
+ ...this.remoteAgents
961
+ };
962
+ this.notifyAgentsChanged();
963
+ return {
964
+ agent,
965
+ unregister: () => {
966
+ if (this.localAgents[agentId] === agent) {
967
+ delete this.localAgents[agentId];
968
+ this._agents = {
969
+ ...this.localAgents,
970
+ ...this.remoteAgents
971
+ };
972
+ this.notifyAgentsChanged();
973
+ }
974
+ }
975
+ };
976
+ }
977
+ /**
910
978
  * Get an agent by ID
911
979
  */
912
980
  getAgent(id) {
@@ -1186,16 +1254,10 @@ var SuggestionEngine = class {
1186
1254
  /**
1187
1255
  * Reload suggestions for a specific agent
1188
1256
  * This triggers generation of new suggestions based on current configs
1189
- *
1190
- * @param agentId - The consumer agent ID
1191
- * @param consumerAgent - Optional: the specific agent instance whose messages should be used
1192
- * for availability filtering and context. When running with per-thread clones, the thread
1193
- * clone holds the conversation messages; passing it here ensures dynamic suggestions fire
1194
- * after the first message even though the registry agent has an empty message list.
1195
1257
  */
1196
- reloadSuggestions(agentId, consumerAgent) {
1258
+ reloadSuggestions(agentId) {
1197
1259
  this.clearSuggestions(agentId);
1198
- const agent = consumerAgent ?? this.core.getAgent(agentId);
1260
+ const agent = this.core.getAgent(agentId);
1199
1261
  const messageCount = agent?.messages?.length ?? 0;
1200
1262
  let hasAnySuggestions = false;
1201
1263
  for (const config of Object.values(this._suggestionsConfig)) {
@@ -1208,7 +1270,7 @@ var SuggestionEngine = class {
1208
1270
  hasAnySuggestions = true;
1209
1271
  this.notifySuggestionsStartedLoading(agentId);
1210
1272
  }
1211
- this.generateSuggestions(suggestionId, config, agentId, agent);
1273
+ this.generateSuggestions(suggestionId, config, agentId);
1212
1274
  } else if (isStaticSuggestionsConfig(config)) this.addStaticSuggestions(suggestionId, config, agentId);
1213
1275
  }
1214
1276
  }
@@ -1236,12 +1298,12 @@ var SuggestionEngine = class {
1236
1298
  /**
1237
1299
  * Generate suggestions using a provider agent
1238
1300
  */
1239
- async generateSuggestions(suggestionId, config, consumerAgentId, consumerAgent) {
1301
+ async generateSuggestions(suggestionId, config, consumerAgentId) {
1240
1302
  let agent = void 0;
1241
1303
  try {
1242
1304
  const suggestionsProviderAgent = this.core.getAgent(config.providerAgentId ?? "default");
1243
1305
  if (!suggestionsProviderAgent) throw new Error(`Suggestions provider agent not found: ${config.providerAgentId}`);
1244
- const suggestionsConsumerAgent = consumerAgent ?? this.core.getAgent(consumerAgentId);
1306
+ const suggestionsConsumerAgent = this.core.getAgent(consumerAgentId);
1245
1307
  if (!suggestionsConsumerAgent) throw new Error(`Suggestions consumer agent not found: ${consumerAgentId}`);
1246
1308
  agent = suggestionsProviderAgent.clone();
1247
1309
  agent.threadId = suggestionId;
@@ -1546,10 +1608,6 @@ var RunHandler = class {
1546
1608
  agent.setMessages([]);
1547
1609
  agent.setState({});
1548
1610
  if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...this._internal.headers };
1549
- await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
1550
- copilotkit: this.core,
1551
- agent
1552
- }), "Subscriber onAgentRunStarted error:");
1553
1611
  const runAgentResult = await agent.connectAgent({
1554
1612
  forwardedProps: this._internal.properties,
1555
1613
  tools: this.buildFrontendTools(agent.agentId),
@@ -1580,11 +1638,6 @@ var RunHandler = class {
1580
1638
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1581
1639
  if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...this._internal.headers };
1582
1640
  if (agent.detachActiveRun) await agent.detachActiveRun();
1583
- this._internal.subscribeAgentToStateManager(agent);
1584
- await this._internal.notifySubscribers((subscriber) => subscriber.onAgentRunStarted?.({
1585
- copilotkit: this.core,
1586
- agent
1587
- }), "Subscriber onAgentRunStarted error:");
1588
1641
  const isTopLevel = this._runDepth === 0;
1589
1642
  let originalAbortRun;
1590
1643
  if (isTopLevel) {
@@ -1655,7 +1708,7 @@ var RunHandler = class {
1655
1708
  await this._internal.waitForPendingFrameworkUpdates();
1656
1709
  return await this.runAgent({ agent });
1657
1710
  }
1658
- this._internal.suggestionEngine.reloadSuggestions(agentId, agent);
1711
+ this._internal.suggestionEngine.reloadSuggestions(agentId);
1659
1712
  return runAgentResult;
1660
1713
  }
1661
1714
  /**
@@ -2067,21 +2120,14 @@ var StateManager = class {
2067
2120
  initialize() {}
2068
2121
  /**
2069
2122
  * Subscribe to an agent's events to track state and messages.
2070
- *
2071
- * Registry agents (subscribed via `onAgentsChanged`) use the bare `agentId`
2072
- * key so that `unsubscribeFromAgent(agentId)` can remove them when they
2073
- * are replaced. Per-thread clones (subscribed via `subscribeAgentToStateManager`)
2074
- * pass `{ isClone: true }` to use a composite `agentId:threadId` key, keeping
2075
- * their subscription independent of the registry agent's.
2076
2123
  */
2077
- subscribeToAgent(agent, { isClone = false } = {}) {
2124
+ subscribeToAgent(agent) {
2078
2125
  if (!agent.agentId) return;
2079
2126
  const agentId = agent.agentId;
2080
- const subscriptionKey = isClone && agent.threadId ? `${agentId}:${agent.threadId}` : agentId;
2081
- const existingUnsubscribe = this.agentSubscriptions.get(subscriptionKey);
2127
+ const existingUnsubscribe = this.agentSubscriptions.get(agentId);
2082
2128
  if (existingUnsubscribe) {
2083
2129
  existingUnsubscribe();
2084
- this.agentSubscriptions.delete(subscriptionKey);
2130
+ this.agentSubscriptions.delete(agentId);
2085
2131
  }
2086
2132
  let revoked = false;
2087
2133
  let subRunId;
@@ -2125,16 +2171,13 @@ var StateManager = class {
2125
2171
  this.handleNewMessage(agent, message, input ? effectiveInput(input) : void 0);
2126
2172
  }
2127
2173
  });
2128
- this.agentSubscriptions.set(subscriptionKey, () => {
2174
+ this.agentSubscriptions.set(agentId, () => {
2129
2175
  revoked = true;
2130
2176
  unsubscribe();
2131
2177
  });
2132
2178
  }
2133
2179
  /**
2134
- * Unsubscribe a registry agent's subscription (bare `agentId` key).
2135
- * Per-thread clone subscriptions use composite `agentId:threadId` keys and
2136
- * are replaced (not removed) by subsequent subscribeToAgent(agent, { isClone: true })
2137
- * calls for the same (agentId, threadId) pair.
2180
+ * Unsubscribe an agent's subscription.
2138
2181
  */
2139
2182
  unsubscribeFromAgent(agentId) {
2140
2183
  const unsubscribe = this.agentSubscriptions.get(agentId);
@@ -2419,7 +2462,16 @@ var CopilotKitCore = class {
2419
2462
  if (agent.agentId) this.stateManager.subscribeToAgent(agent);
2420
2463
  });
2421
2464
  const currentAgentIds = new Set(Object.keys(agents));
2422
- for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) this.threadStoreRegistry.unregister(agentId);
2465
+ for (const agentId of Object.keys(this.threadStoreRegistry.getAll())) if (this.previousAgentIds.has(agentId) && !currentAgentIds.has(agentId)) try {
2466
+ this.threadStoreRegistry.unregister(agentId);
2467
+ } catch (err) {
2468
+ console.error(`CopilotKitCore.onAgentsChanged: threadStoreRegistry.unregister failed for "${agentId}":`, err);
2469
+ }
2470
+ for (const agentId of this.previousAgentIds) if (!currentAgentIds.has(agentId)) try {
2471
+ this.stateManager.unsubscribeFromAgent(agentId);
2472
+ } catch (err) {
2473
+ console.error(`CopilotKitCore.onAgentsChanged: stateManager.unsubscribeFromAgent failed for "${agentId}":`, err);
2474
+ }
2423
2475
  this.previousAgentIds = currentAgentIds;
2424
2476
  } });
2425
2477
  }
@@ -2582,6 +2634,28 @@ var CopilotKitCore = class {
2582
2634
  removeAgent__unsafe_dev_only(id) {
2583
2635
  this.agentRegistry.removeAgent__unsafe_dev_only(id);
2584
2636
  }
2637
+ /**
2638
+ * Register a proxied agent against an existing runtime agent. The proxy is
2639
+ * exposed under `agentId` (local registry id) and routes outbound runtime
2640
+ * requests to `runtimeAgentId`. Throws if `agentId` is already taken.
2641
+ *
2642
+ * Returns the minted proxy and an `unregister` handle for cleanup.
2643
+ *
2644
+ * Use this to mount multiple frontend agents against a single runtime
2645
+ * agent (e.g. one per chat window) without implicit per-thread cloning.
2646
+ *
2647
+ * @example
2648
+ * const { agent, unregister } = copilotkit.registerProxiedAgent({
2649
+ * agentId: "chat-1",
2650
+ * runtimeAgentId: "default",
2651
+ * });
2652
+ * // ... <CopilotChat agentId="chat-1" />
2653
+ * // on cleanup:
2654
+ * unregister();
2655
+ */
2656
+ registerProxiedAgent(params) {
2657
+ return this.agentRegistry.registerProxiedAgent(params);
2658
+ }
2585
2659
  getAgent(id) {
2586
2660
  return this.agentRegistry.getAgent(id);
2587
2661
  }
@@ -2815,9 +2889,6 @@ var CopilotKitCore = class {
2815
2889
  getRunIdsForThread(agentId, threadId) {
2816
2890
  return this.stateManager.getRunIdsForThread(agentId, threadId);
2817
2891
  }
2818
- subscribeAgentToStateManager(agent) {
2819
- this.stateManager.subscribeToAgent(agent, { isClone: true });
2820
- }
2821
2892
  /**
2822
2893
  * Internal method used by RunHandler to build frontend tools
2823
2894
  */