@copilotkit/core 1.55.0-next.8 → 1.55.0-next.9

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
@@ -1123,10 +1123,16 @@ var SuggestionEngine = class {
1123
1123
  /**
1124
1124
  * Reload suggestions for a specific agent
1125
1125
  * This triggers generation of new suggestions based on current configs
1126
+ *
1127
+ * @param agentId - The consumer agent ID
1128
+ * @param consumerAgent - Optional: the specific agent instance whose messages should be used
1129
+ * for availability filtering and context. When running with per-thread clones, the thread
1130
+ * clone holds the conversation messages; passing it here ensures dynamic suggestions fire
1131
+ * after the first message even though the registry agent has an empty message list.
1126
1132
  */
1127
- reloadSuggestions(agentId) {
1133
+ reloadSuggestions(agentId, consumerAgent) {
1128
1134
  this.clearSuggestions(agentId);
1129
- const agent = this.core.getAgent(agentId);
1135
+ const agent = consumerAgent ?? this.core.getAgent(agentId);
1130
1136
  if (!agent) return;
1131
1137
  const messageCount = agent.messages?.length ?? 0;
1132
1138
  let hasAnySuggestions = false;
@@ -1139,7 +1145,7 @@ var SuggestionEngine = class {
1139
1145
  hasAnySuggestions = true;
1140
1146
  this.notifySuggestionsStartedLoading(agentId);
1141
1147
  }
1142
- this.generateSuggestions(suggestionId, config, agentId);
1148
+ this.generateSuggestions(suggestionId, config, agentId, agent);
1143
1149
  } else if (isStaticSuggestionsConfig(config)) this.addStaticSuggestions(suggestionId, config, agentId);
1144
1150
  }
1145
1151
  }
@@ -1167,12 +1173,12 @@ var SuggestionEngine = class {
1167
1173
  /**
1168
1174
  * Generate suggestions using a provider agent
1169
1175
  */
1170
- async generateSuggestions(suggestionId, config, consumerAgentId) {
1176
+ async generateSuggestions(suggestionId, config, consumerAgentId, consumerAgent) {
1171
1177
  let agent = void 0;
1172
1178
  try {
1173
1179
  const suggestionsProviderAgent = this.core.getAgent(config.providerAgentId ?? "default");
1174
1180
  if (!suggestionsProviderAgent) throw new Error(`Suggestions provider agent not found: ${config.providerAgentId}`);
1175
- const suggestionsConsumerAgent = this.core.getAgent(consumerAgentId);
1181
+ const suggestionsConsumerAgent = consumerAgent ?? this.core.getAgent(consumerAgentId);
1176
1182
  if (!suggestionsConsumerAgent) throw new Error(`Suggestions consumer agent not found: ${consumerAgentId}`);
1177
1183
  agent = suggestionsProviderAgent.clone();
1178
1184
  agent.threadId = suggestionId;
@@ -1505,6 +1511,7 @@ var RunHandler = class {
1505
1511
  if (agent.agentId) this._internal.suggestionEngine.clearSuggestions(agent.agentId);
1506
1512
  if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...this._internal.headers };
1507
1513
  if (agent.detachActiveRun) await agent.detachActiveRun();
1514
+ this._internal.subscribeAgentToStateManager(agent);
1508
1515
  const isTopLevel = this._runDepth === 0;
1509
1516
  let originalAbortRun;
1510
1517
  if (isTopLevel) {
@@ -1575,7 +1582,7 @@ var RunHandler = class {
1575
1582
  await this._internal.waitForPendingFrameworkUpdates();
1576
1583
  return await this.runAgent({ agent });
1577
1584
  }
1578
- this._internal.suggestionEngine.reloadSuggestions(agentId);
1585
+ this._internal.suggestionEngine.reloadSuggestions(agentId, agent);
1579
1586
  return runAgentResult;
1580
1587
  }
1581
1588
  /**
@@ -1976,6 +1983,7 @@ function parseToolArguments(rawArgs, toolName) {
1976
1983
  var StateManager = class {
1977
1984
  stateByRun = /* @__PURE__ */ new Map();
1978
1985
  messageToRun = /* @__PURE__ */ new Map();
1986
+ activeRun = /* @__PURE__ */ new Map();
1979
1987
  agentSubscriptions = /* @__PURE__ */ new Map();
1980
1988
  constructor(core) {
1981
1989
  this.core = core;
@@ -1985,36 +1993,70 @@ var StateManager = class {
1985
1993
  */
1986
1994
  initialize() {}
1987
1995
  /**
1988
- * Subscribe to an agent's events to track state and messages
1996
+ * Subscribe to an agent's events to track state and messages.
1997
+ *
1998
+ * Registry agents (subscribed via `onAgentsChanged`) use the bare `agentId`
1999
+ * key so that `unsubscribeFromAgent(agentId)` can remove them when they
2000
+ * are replaced. Per-thread clones (subscribed via `subscribeAgentToStateManager`)
2001
+ * pass `{ isClone: true }` to use a composite `agentId:threadId` key, keeping
2002
+ * their subscription independent of the registry agent's.
1989
2003
  */
1990
- subscribeToAgent(agent) {
2004
+ subscribeToAgent(agent, { isClone = false } = {}) {
1991
2005
  if (!agent.agentId) return;
1992
2006
  const agentId = agent.agentId;
1993
- this.unsubscribeFromAgent(agentId);
2007
+ const subscriptionKey = isClone && agent.threadId ? `${agentId}:${agent.threadId}` : agentId;
2008
+ const existingUnsubscribe = this.agentSubscriptions.get(subscriptionKey);
2009
+ if (existingUnsubscribe) {
2010
+ existingUnsubscribe();
2011
+ this.agentSubscriptions.delete(subscriptionKey);
2012
+ }
2013
+ let revoked = false;
2014
+ let subRunId;
2015
+ let runFinished = false;
2016
+ const effectiveInput = (input) => ({
2017
+ ...input,
2018
+ runId: subRunId ?? input.runId
2019
+ });
1994
2020
  const { unsubscribe } = agent.subscribe({
1995
- onRunStartedEvent: ({ event, state }) => {
1996
- this.handleRunStarted(agent, event, state);
2021
+ onRunStartedEvent: ({ input, state }) => {
2022
+ if (revoked) return;
2023
+ if (runFinished && input.runId === subRunId) subRunId = (0, _ag_ui_client.randomUUID)();
2024
+ else subRunId = input.runId;
2025
+ runFinished = false;
2026
+ this.handleRunStarted(agent, effectiveInput(input), state);
1997
2027
  },
1998
- onRunFinishedEvent: ({ event, state }) => {
1999
- this.handleRunFinished(agent, event, state);
2028
+ onRunFinishedEvent: ({ input, state }) => {
2029
+ if (revoked) return;
2030
+ runFinished = true;
2031
+ this.handleRunFinished(agent, effectiveInput(input), state);
2000
2032
  },
2001
2033
  onStateSnapshotEvent: ({ event, input, state }) => {
2002
- this.handleStateSnapshot(agent, event, input, state);
2034
+ if (revoked) return;
2035
+ this.handleStateSnapshot(agent, event, effectiveInput(input), state);
2003
2036
  },
2004
2037
  onStateDeltaEvent: ({ event, input, state }) => {
2005
- this.handleStateDelta(agent, event, input, state);
2038
+ if (revoked) return;
2039
+ this.handleStateDelta(agent, event, effectiveInput(input), state);
2006
2040
  },
2007
2041
  onMessagesSnapshotEvent: ({ event, input, messages }) => {
2008
- this.handleMessagesSnapshot(agent, event, input, messages);
2042
+ if (revoked) return;
2043
+ this.handleMessagesSnapshot(agent, event, effectiveInput(input), messages);
2009
2044
  },
2010
2045
  onNewMessage: ({ message, input }) => {
2011
- this.handleNewMessage(agent, message, input);
2046
+ if (revoked) return;
2047
+ this.handleNewMessage(agent, message, input ? effectiveInput(input) : void 0);
2012
2048
  }
2013
2049
  });
2014
- this.agentSubscriptions.set(agentId, unsubscribe);
2050
+ this.agentSubscriptions.set(subscriptionKey, () => {
2051
+ revoked = true;
2052
+ unsubscribe();
2053
+ });
2015
2054
  }
2016
2055
  /**
2017
- * Unsubscribe from an agent's events
2056
+ * Unsubscribe a registry agent's subscription (bare `agentId` key).
2057
+ * Per-thread clone subscriptions use composite `agentId:threadId` keys and
2058
+ * are replaced (not removed) by subsequent subscribeToAgent(agent, { isClone: true })
2059
+ * calls for the same (agentId, threadId) pair.
2018
2060
  */
2019
2061
  unsubscribeFromAgent(agentId) {
2020
2062
  const unsubscribe = this.agentSubscriptions.get(agentId);
@@ -2054,18 +2096,20 @@ var StateManager = class {
2054
2096
  /**
2055
2097
  * Handle run started event
2056
2098
  */
2057
- handleRunStarted(agent, event, state) {
2099
+ handleRunStarted(agent, input, state) {
2058
2100
  if (!agent.agentId) return;
2059
- const { threadId, runId } = event;
2060
- this.saveState(agent.agentId, threadId, runId, state);
2101
+ const { threadId, runId } = input;
2102
+ this.activeRun.set(`${agent.agentId}:${threadId}`, runId);
2103
+ if (state && Object.keys(state).length > 0) this.saveState(agent.agentId, threadId, runId, state);
2061
2104
  }
2062
2105
  /**
2063
2106
  * Handle run finished event
2064
2107
  */
2065
- handleRunFinished(agent, event, state) {
2108
+ handleRunFinished(agent, input, state) {
2066
2109
  if (!agent.agentId) return;
2067
- const { threadId, runId } = event;
2068
- this.saveState(agent.agentId, threadId, runId, state);
2110
+ const { threadId, runId } = input;
2111
+ this.activeRun.delete(`${agent.agentId}:${threadId}`);
2112
+ if (state && Object.keys(state).length > 0) this.saveState(agent.agentId, threadId, runId, state);
2069
2113
  }
2070
2114
  /**
2071
2115
  * Handle state snapshot event
@@ -2099,7 +2143,13 @@ var StateManager = class {
2099
2143
  * Handle new message event
2100
2144
  */
2101
2145
  handleNewMessage(agent, message, input) {
2102
- if (!agent.agentId || !input) return;
2146
+ if (!agent.agentId) return;
2147
+ if (!input) {
2148
+ const threadId = agent.threadId ?? "";
2149
+ const runId = this.activeRun.get(`${agent.agentId}:${threadId}`);
2150
+ if (runId) this.associateMessageWithRun(agent.agentId, threadId, message.id, runId);
2151
+ return;
2152
+ }
2103
2153
  const { threadId, runId } = input;
2104
2154
  this.associateMessageWithRun(agent.agentId, threadId, message.id, runId);
2105
2155
  }
@@ -2409,6 +2459,9 @@ var CopilotKitCore = class {
2409
2459
  getRunIdsForThread(agentId, threadId) {
2410
2460
  return this.stateManager.getRunIdsForThread(agentId, threadId);
2411
2461
  }
2462
+ subscribeAgentToStateManager(agent) {
2463
+ this.stateManager.subscribeToAgent(agent, { isClone: true });
2464
+ }
2412
2465
  /**
2413
2466
  * Internal method used by RunHandler to build frontend tools
2414
2467
  */