@copilotkit/core 1.63.2 → 1.64.0

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
@@ -602,6 +602,12 @@ var ProxiedCopilotRuntimeAgent = class ProxiedCopilotRuntimeAgent extends _ag_ui
602
602
  get capabilities() {
603
603
  return this._capabilities;
604
604
  }
605
+ requestInit(input) {
606
+ return {
607
+ ...super.requestInit(input),
608
+ ...this.credentials ? { credentials: this.credentials } : {}
609
+ };
610
+ }
605
611
  async getCapabilities() {
606
612
  return this._capabilities ?? {};
607
613
  }
@@ -1747,6 +1753,19 @@ const SUGGEST_TOOL = {
1747
1753
  //#endregion
1748
1754
  //#region src/core/run-handler.ts
1749
1755
  /**
1756
+ * Absolute safety cap on the depth of recursive follow-up runs triggered by
1757
+ * `processAgentResult`. Without this, any scenario that keeps
1758
+ * `needsFollowUp = true` (e.g. the LLM repeatedly calling the same tool, a
1759
+ * backend that errors after receiving tool results, or input processors that
1760
+ * reprocess tool messages) would loop indefinitely, silently consuming API
1761
+ * quota and potentially DOS'ing the backend.
1762
+ *
1763
+ * The cap is deliberately high so that legitimate multi-step agent workflows
1764
+ * (search → fill form → confirm → update → send email, etc.) are never
1765
+ * affected; it only trips on runaway recursion.
1766
+ */
1767
+ const MAX_FOLLOW_UP_DEPTH = 100;
1768
+ /**
1750
1769
  * Handles agent execution, tool calling, and agent connectivity for CopilotKitCore.
1751
1770
  * Manages the complete lifecycle of agent runs including tool execution and follow-ups.
1752
1771
  */
@@ -1981,33 +2000,64 @@ var RunHandler = class {
1981
2000
  const agentId = agent.agentId;
1982
2001
  let needsFollowUp = false;
1983
2002
  if (executeFrontendTools) {
1984
- for (const message of newMessages) if (message.role === "assistant") {
1985
- for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
1986
- const tool = this.getTool({
1987
- toolName: toolCall.function.name,
2003
+ for (const message of newMessages) if (message.role === "assistant") for (const toolCall of message.toolCalls || []) {
2004
+ const tool = this.getTool({
2005
+ toolName: toolCall.function.name,
2006
+ agentId: agent.agentId
2007
+ });
2008
+ let wildcardTool;
2009
+ const getWildcardTool = () => {
2010
+ if (tool || wildcardTool) return wildcardTool;
2011
+ wildcardTool = this.getTool({
2012
+ toolName: "*",
1988
2013
  agentId: agent.agentId
1989
2014
  });
1990
- if (tool) {
1991
- if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
1992
- } else {
1993
- const wildcardTool = this.getTool({
1994
- toolName: "*",
1995
- agentId: agent.agentId
1996
- });
1997
- if (wildcardTool) {
1998
- if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
1999
- }
2015
+ return wildcardTool;
2016
+ };
2017
+ let existingResultIndex = newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
2018
+ const existingResult = existingResultIndex === -1 ? void 0 : newMessages[existingResultIndex];
2019
+ const executableTool = tool ?? getWildcardTool();
2020
+ if (existingResult && executableTool?.handler && this.isFrontendPlaceholderResult(existingResult)) {
2021
+ newMessages.splice(existingResultIndex, 1);
2022
+ existingResultIndex = -1;
2023
+ const agentMsgIdx = agent.messages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
2024
+ if (agentMsgIdx !== -1) agent.messages.splice(agentMsgIdx, 1);
2025
+ }
2026
+ if (existingResultIndex === -1) if (tool) {
2027
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
2028
+ } else {
2029
+ const fallbackTool = getWildcardTool();
2030
+ if (fallbackTool) {
2031
+ if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId)) needsFollowUp = true;
2000
2032
  }
2001
2033
  }
2002
2034
  }
2003
2035
  }
2004
- if (needsFollowUp && !this._runAbortController?.signal.aborted) {
2036
+ if (needsFollowUp && !this._runAbortController?.signal.aborted) if (this._runDepth >= MAX_FOLLOW_UP_DEPTH) _copilotkit_shared.logger.warn(`[CopilotKit] Follow-up depth limit (${MAX_FOLLOW_UP_DEPTH}) reached for agent "${agentId}". Stopping recursive follow-up runs to prevent an infinite loop. This usually indicates a tool that keeps requesting a follow-up (e.g. the LLM repeatedly calling the same tool). Consider setting "followUp: false" on the offending tool.`);
2037
+ else {
2005
2038
  await this._internal.waitForPendingFrameworkUpdates();
2006
2039
  return await this.runAgent({ agent });
2007
2040
  }
2008
2041
  this._internal.suggestionEngine.reloadSuggestions(agentId);
2009
2042
  return runAgentResult;
2010
2043
  }
2044
+ isFrontendPlaceholderResult(message) {
2045
+ if (message.role !== "tool") return false;
2046
+ return this.normalizeToolResultContent(message.content) === "Forwarded to client";
2047
+ }
2048
+ normalizeToolResultContent(content) {
2049
+ if (typeof content === "string") return content.trim();
2050
+ if (Array.isArray(content)) {
2051
+ const text = content.flatMap((part) => {
2052
+ if (typeof part === "string") return [part];
2053
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") return [part.text];
2054
+ return [];
2055
+ }).join("").trim();
2056
+ return text.length > 0 ? text : null;
2057
+ }
2058
+ if (content && typeof content === "object" && "text" in content && typeof content.text === "string") return content.text.trim();
2059
+ return null;
2060
+ }
2011
2061
  /**
2012
2062
  * Shared handler execution logic used by executeSpecificTool, executeWildcardTool, and runTool.
2013
2063
  * Handles arg parsing, subscriber notifications, handler invocation, result stringification,
@@ -2106,13 +2156,15 @@ var RunHandler = class {
2106
2156
  {
2107
2157
  const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
2108
2158
  if (messageIndex === -1) return false;
2159
+ let insertAt = messageIndex + 1;
2160
+ while (insertAt < agent.messages.length && agent.messages[insertAt]?.role === "tool") insertAt++;
2109
2161
  const toolMessage = {
2110
2162
  id: (0, _copilotkit_shared.randomUUID)(),
2111
2163
  role: "tool",
2112
2164
  toolCallId: toolCall.id,
2113
2165
  content: handlerResult.result
2114
2166
  };
2115
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
2167
+ agent.messages.splice(insertAt, 0, toolMessage);
2116
2168
  if (!handlerResult.error && tool?.followUp !== false) return true;
2117
2169
  }
2118
2170
  return false;
@@ -2195,13 +2247,15 @@ var RunHandler = class {
2195
2247
  {
2196
2248
  const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
2197
2249
  if (messageIndex === -1) return false;
2250
+ let insertAt = messageIndex + 1;
2251
+ while (insertAt < agent.messages.length && agent.messages[insertAt]?.role === "tool") insertAt++;
2198
2252
  const toolMessage = {
2199
2253
  id: (0, _copilotkit_shared.randomUUID)(),
2200
2254
  role: "tool",
2201
2255
  toolCallId: toolCall.id,
2202
2256
  content: toolCallResult
2203
2257
  };
2204
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
2258
+ agent.messages.splice(insertAt, 0, toolMessage);
2205
2259
  if (!errorMessage && wildcardTool?.followUp !== false) return true;
2206
2260
  }
2207
2261
  return false;
@@ -2324,6 +2378,7 @@ var RunHandler = class {
2324
2378
  await emitAgentError(error, error instanceof AgentThreadLockedError ? CopilotKitCoreErrorCode.AGENT_THREAD_LOCKED : CopilotKitCoreErrorCode.AGENT_RUN_FAILED_EVENT, { source: "onRunFailed" });
2325
2379
  },
2326
2380
  onRunErrorEvent: async ({ event }) => {
2381
+ if (this._runAbortController?.signal.aborted === true || event?.code === "abort") return;
2327
2382
  const eventError = event?.rawEvent instanceof Error ? event.rawEvent : event?.rawEvent?.error instanceof Error ? event.rawEvent.error : void 0;
2328
2383
  const errorMessage = typeof event?.rawEvent?.error === "string" ? event.rawEvent.error : event?.message ?? "Agent run error";
2329
2384
  const rawError = eventError ?? new Error(errorMessage);