@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.umd.js CHANGED
@@ -708,6 +708,12 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
708
708
  get capabilities() {
709
709
  return this._capabilities;
710
710
  }
711
+ requestInit(input) {
712
+ return {
713
+ ...super.requestInit(input),
714
+ ...this.credentials ? { credentials: this.credentials } : {}
715
+ };
716
+ }
711
717
  async getCapabilities() {
712
718
  var _this$_capabilities;
713
719
  return (_this$_capabilities = this._capabilities) !== null && _this$_capabilities !== void 0 ? _this$_capabilities : {};
@@ -1885,6 +1891,19 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
1885
1891
  //#endregion
1886
1892
  //#region src/core/run-handler.ts
1887
1893
  /**
1894
+ * Absolute safety cap on the depth of recursive follow-up runs triggered by
1895
+ * `processAgentResult`. Without this, any scenario that keeps
1896
+ * `needsFollowUp = true` (e.g. the LLM repeatedly calling the same tool, a
1897
+ * backend that errors after receiving tool results, or input processors that
1898
+ * reprocess tool messages) would loop indefinitely, silently consuming API
1899
+ * quota and potentially DOS'ing the backend.
1900
+ *
1901
+ * The cap is deliberately high so that legitimate multi-step agent workflows
1902
+ * (search → fill form → confirm → update → send email, etc.) are never
1903
+ * affected; it only trips on runaway recursion.
1904
+ */
1905
+ const MAX_FOLLOW_UP_DEPTH = 100;
1906
+ /**
1888
1907
  * Handles agent execution, tool calling, and agent connectivity for CopilotKitCore.
1889
1908
  * Manages the complete lifecycle of agent runs including tool execution and follow-ups.
1890
1909
  */
@@ -2101,33 +2120,64 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2101
2120
  const agentId = agent.agentId;
2102
2121
  let needsFollowUp = false;
2103
2122
  if (executeFrontendTools) {
2104
- for (const message of newMessages) if (message.role === "assistant") {
2105
- for (const toolCall of message.toolCalls || []) if (newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id) === -1) {
2106
- const tool = this.getTool({
2107
- toolName: toolCall.function.name,
2123
+ for (const message of newMessages) if (message.role === "assistant") for (const toolCall of message.toolCalls || []) {
2124
+ const tool = this.getTool({
2125
+ toolName: toolCall.function.name,
2126
+ agentId: agent.agentId
2127
+ });
2128
+ let wildcardTool;
2129
+ const getWildcardTool = () => {
2130
+ if (tool || wildcardTool) return wildcardTool;
2131
+ wildcardTool = this.getTool({
2132
+ toolName: "*",
2108
2133
  agentId: agent.agentId
2109
2134
  });
2110
- if (tool) {
2111
- if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
2112
- } else {
2113
- const wildcardTool = this.getTool({
2114
- toolName: "*",
2115
- agentId: agent.agentId
2116
- });
2117
- if (wildcardTool) {
2118
- if (await this.executeWildcardTool(wildcardTool, toolCall, message, agent, agentId)) needsFollowUp = true;
2119
- }
2135
+ return wildcardTool;
2136
+ };
2137
+ let existingResultIndex = newMessages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
2138
+ const existingResult = existingResultIndex === -1 ? void 0 : newMessages[existingResultIndex];
2139
+ const executableTool = tool !== null && tool !== void 0 ? tool : getWildcardTool();
2140
+ if (existingResult && (executableTool === null || executableTool === void 0 ? void 0 : executableTool.handler) && this.isFrontendPlaceholderResult(existingResult)) {
2141
+ newMessages.splice(existingResultIndex, 1);
2142
+ existingResultIndex = -1;
2143
+ const agentMsgIdx = agent.messages.findIndex((m) => m.role === "tool" && m.toolCallId === toolCall.id);
2144
+ if (agentMsgIdx !== -1) agent.messages.splice(agentMsgIdx, 1);
2145
+ }
2146
+ if (existingResultIndex === -1) if (tool) {
2147
+ if (await this.executeSpecificTool(tool, toolCall, message, agent, agentId)) needsFollowUp = true;
2148
+ } else {
2149
+ const fallbackTool = getWildcardTool();
2150
+ if (fallbackTool) {
2151
+ if (await this.executeWildcardTool(fallbackTool, toolCall, message, agent, agentId)) needsFollowUp = true;
2120
2152
  }
2121
2153
  }
2122
2154
  }
2123
2155
  }
2124
- if (needsFollowUp && !((_this$_runAbortContro2 = this._runAbortController) === null || _this$_runAbortContro2 === void 0 ? void 0 : _this$_runAbortContro2.signal.aborted)) {
2156
+ if (needsFollowUp && !((_this$_runAbortContro2 = this._runAbortController) === null || _this$_runAbortContro2 === void 0 ? void 0 : _this$_runAbortContro2.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.`);
2157
+ else {
2125
2158
  await this._internal.waitForPendingFrameworkUpdates();
2126
2159
  return await this.runAgent({ agent });
2127
2160
  }
2128
2161
  this._internal.suggestionEngine.reloadSuggestions(agentId);
2129
2162
  return runAgentResult;
2130
2163
  }
2164
+ isFrontendPlaceholderResult(message) {
2165
+ if (message.role !== "tool") return false;
2166
+ return this.normalizeToolResultContent(message.content) === "Forwarded to client";
2167
+ }
2168
+ normalizeToolResultContent(content) {
2169
+ if (typeof content === "string") return content.trim();
2170
+ if (Array.isArray(content)) {
2171
+ const text = content.flatMap((part) => {
2172
+ if (typeof part === "string") return [part];
2173
+ if (part && typeof part === "object" && "text" in part && typeof part.text === "string") return [part.text];
2174
+ return [];
2175
+ }).join("").trim();
2176
+ return text.length > 0 ? text : null;
2177
+ }
2178
+ if (content && typeof content === "object" && "text" in content && typeof content.text === "string") return content.text.trim();
2179
+ return null;
2180
+ }
2131
2181
  /**
2132
2182
  * Shared handler execution logic used by executeSpecificTool, executeWildcardTool, and runTool.
2133
2183
  * Handles arg parsing, subscriber notifications, handler invocation, result stringification,
@@ -2231,15 +2281,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2231
2281
  messageId: message.id
2232
2282
  });
2233
2283
  {
2284
+ var _agent$messages$inser;
2234
2285
  const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
2235
2286
  if (messageIndex === -1) return false;
2287
+ let insertAt = messageIndex + 1;
2288
+ while (insertAt < agent.messages.length && ((_agent$messages$inser = agent.messages[insertAt]) === null || _agent$messages$inser === void 0 ? void 0 : _agent$messages$inser.role) === "tool") insertAt++;
2236
2289
  const toolMessage = {
2237
2290
  id: (0, _copilotkit_shared.randomUUID)(),
2238
2291
  role: "tool",
2239
2292
  toolCallId: toolCall.id,
2240
2293
  content: handlerResult.result
2241
2294
  };
2242
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
2295
+ agent.messages.splice(insertAt, 0, toolMessage);
2243
2296
  if (!handlerResult.error && (tool === null || tool === void 0 ? void 0 : tool.followUp) !== false) return true;
2244
2297
  }
2245
2298
  return false;
@@ -2326,15 +2379,18 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2326
2379
  }, "Subscriber onToolExecutionEnd error:");
2327
2380
  }
2328
2381
  {
2382
+ var _agent$messages$inser2;
2329
2383
  const messageIndex = agent.messages.findIndex((m) => m.id === message.id);
2330
2384
  if (messageIndex === -1) return false;
2385
+ let insertAt = messageIndex + 1;
2386
+ while (insertAt < agent.messages.length && ((_agent$messages$inser2 = agent.messages[insertAt]) === null || _agent$messages$inser2 === void 0 ? void 0 : _agent$messages$inser2.role) === "tool") insertAt++;
2331
2387
  const toolMessage = {
2332
2388
  id: (0, _copilotkit_shared.randomUUID)(),
2333
2389
  role: "tool",
2334
2390
  toolCallId: toolCall.id,
2335
2391
  content: toolCallResult
2336
2392
  };
2337
- agent.messages.splice(messageIndex + 1, 0, toolMessage);
2393
+ agent.messages.splice(insertAt, 0, toolMessage);
2338
2394
  if (!errorMessage && (wildcardTool === null || wildcardTool === void 0 ? void 0 : wildcardTool.followUp) !== false) return true;
2339
2395
  }
2340
2396
  return false;
@@ -2460,7 +2516,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2460
2516
  await emitAgentError(error, error instanceof AgentThreadLockedError ? CopilotKitCoreErrorCode.AGENT_THREAD_LOCKED : CopilotKitCoreErrorCode.AGENT_RUN_FAILED_EVENT, { source: "onRunFailed" });
2461
2517
  },
2462
2518
  onRunErrorEvent: async ({ event }) => {
2463
- var _event$rawEvent, _event$rawEvent2, _event$message;
2519
+ var _this$_runAbortContro4, _event$rawEvent, _event$rawEvent2, _event$message;
2520
+ if (((_this$_runAbortContro4 = this._runAbortController) === null || _this$_runAbortContro4 === void 0 ? void 0 : _this$_runAbortContro4.signal.aborted) === true || (event === null || event === void 0 ? void 0 : event.code) === "abort") return;
2464
2521
  const eventError = (event === null || event === void 0 ? void 0 : event.rawEvent) instanceof Error ? event.rawEvent : (event === null || event === void 0 || (_event$rawEvent = event.rawEvent) === null || _event$rawEvent === void 0 ? void 0 : _event$rawEvent.error) instanceof Error ? event.rawEvent.error : void 0;
2465
2522
  const errorMessage = typeof (event === null || event === void 0 || (_event$rawEvent2 = event.rawEvent) === null || _event$rawEvent2 === void 0 ? void 0 : _event$rawEvent2.error) === "string" ? event.rawEvent.error : (_event$message = event === null || event === void 0 ? void 0 : event.message) !== null && _event$message !== void 0 ? _event$message : "Agent run error";
2466
2523
  const rawError = eventError !== null && eventError !== void 0 ? eventError : new Error(errorMessage);