@copilotkit/react-core 1.66.2 → 1.66.3

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.
@@ -4936,6 +4936,8 @@ function useInterrupt(config) {
4936
4936
  pendingRef.current = pending;
4937
4937
  const [handlerResult, setHandlerResult] = (0, react.useState)(null);
4938
4938
  const interruptStateRef = (0, react.useRef)(new _copilotkit_core.ɵInterruptState());
4939
+ const interruptRunIdsRef = (0, react.useRef)(/* @__PURE__ */ new Map());
4940
+ const legacyRunIdRef = (0, react.useRef)(void 0);
4939
4941
  (0, react.useEffect)(() => {
4940
4942
  const interruptState = interruptStateRef.current;
4941
4943
  let localLegacy = null;
@@ -4948,19 +4950,26 @@ function useInterrupt(config) {
4948
4950
  };
4949
4951
  },
4950
4952
  onRunFinishedEvent: (params) => {
4951
- if (params.outcome === "interrupt") localStandard = params.interrupts;
4953
+ if (params.outcome === "interrupt") {
4954
+ const runId = params.input.runId;
4955
+ for (const interrupt of params.interrupts) interruptRunIdsRef.current.set(interrupt.id, runId);
4956
+ localStandard = params.interrupts;
4957
+ }
4952
4958
  },
4953
4959
  onRunStartedEvent: () => {
4954
4960
  localLegacy = null;
4955
4961
  localStandard = null;
4962
+ interruptRunIdsRef.current.clear();
4963
+ legacyRunIdRef.current = void 0;
4956
4964
  interruptState.clear();
4957
4965
  setPending(null);
4958
4966
  },
4959
- onRunFinalized: () => {
4967
+ onRunFinalized: (params) => {
4960
4968
  if (localStandard && localStandard.length > 0) {
4961
4969
  interruptState.setStandard(localStandard);
4962
4970
  setPending(interruptState.pending);
4963
4971
  } else if (localLegacy) {
4972
+ legacyRunIdRef.current = params.input.runId;
4964
4973
  interruptState.setLegacy(localLegacy);
4965
4974
  setPending(interruptState.pending);
4966
4975
  }
@@ -4970,6 +4979,8 @@ function useInterrupt(config) {
4970
4979
  onRunFailed: () => {
4971
4980
  localLegacy = null;
4972
4981
  localStandard = null;
4982
+ interruptRunIdsRef.current.clear();
4983
+ legacyRunIdRef.current = void 0;
4973
4984
  interruptState.clear();
4974
4985
  setPending(null);
4975
4986
  }
@@ -4984,18 +4995,22 @@ function useInterrupt(config) {
4984
4995
  if (!current) return;
4985
4996
  if (current.kind === "standard" && current.interrupts.length > 1 && interruptId === void 0) console.warn(`[CopilotKit] useInterrupt: resolve()/cancel() called without an interruptId while ${current.interrupts.length} interrupts are open; defaulting to the first. Pass an interruptId to address a specific interrupt.`);
4986
4997
  const decision = interruptStateRef.current.resolve(payload, interruptId);
4987
- if (decision.kind === "legacy-resume") try {
4988
- return await copilotkit.runAgent({
4989
- agent,
4990
- forwardedProps: { command: {
4991
- resume: decision.payload,
4992
- interruptEvent: decision.interruptValue
4993
- } }
4994
- });
4995
- } catch (err) {
4996
- console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
4997
- setPending(null);
4998
- throw err;
4998
+ if (decision.kind === "legacy-resume") {
4999
+ const runId = legacyRunIdRef.current;
5000
+ try {
5001
+ return await copilotkit.runAgent({
5002
+ agent,
5003
+ ...runId !== void 0 ? { runId } : {},
5004
+ forwardedProps: { command: {
5005
+ resume: decision.payload,
5006
+ interruptEvent: decision.interruptValue
5007
+ } }
5008
+ });
5009
+ } catch (err) {
5010
+ console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
5011
+ setPending(null);
5012
+ throw err;
5013
+ }
4999
5014
  }
5000
5015
  if (decision.kind === "expired") {
5001
5016
  console.error(`[CopilotKit] useInterrupt: interrupt ${decision.interrupt.id} expired at ${decision.interrupt.expiresAt}; not resuming.`);
@@ -5004,6 +5019,7 @@ function useInterrupt(config) {
5004
5019
  return;
5005
5020
  }
5006
5021
  if (decision.kind !== "resume") return;
5022
+ const runId = decision.resume.map((entry) => interruptRunIdsRef.current.get(entry.interruptId)).find((candidate) => candidate !== void 0);
5007
5023
  for (const toolResult of decision.toolResults) agent.addMessage({
5008
5024
  id: (0, _ag_ui_client.randomUUID)(),
5009
5025
  role: "tool",
@@ -5013,7 +5029,8 @@ function useInterrupt(config) {
5013
5029
  try {
5014
5030
  return await copilotkit.runAgent({
5015
5031
  agent,
5016
- resume: decision.resume
5032
+ resume: decision.resume,
5033
+ ...runId !== void 0 ? { runId } : {}
5017
5034
  });
5018
5035
  } catch (err) {
5019
5036
  console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
@@ -5040,6 +5057,7 @@ function useInterrupt(config) {
5040
5057
  return;
5041
5058
  }
5042
5059
  if (decision.kind !== "resume") return;
5060
+ const runId = decision.resume.map((entry) => interruptRunIdsRef.current.get(entry.interruptId)).find((candidate) => candidate !== void 0);
5043
5061
  for (const toolResult of decision.toolResults) agent.addMessage({
5044
5062
  id: (0, _ag_ui_client.randomUUID)(),
5045
5063
  role: "tool",
@@ -5049,7 +5067,8 @@ function useInterrupt(config) {
5049
5067
  try {
5050
5068
  return await copilotkit.runAgent({
5051
5069
  agent,
5052
- resume: decision.resume
5070
+ resume: decision.resume,
5071
+ ...runId !== void 0 ? { runId } : {}
5053
5072
  });
5054
5073
  } catch (err) {
5055
5074
  console.error("[CopilotKit] useInterrupt resolve: runAgent rejected; clearing pending + rethrowing", err);
@@ -7064,6 +7083,37 @@ const MemoizedCustomMessage = react.default.memo(function MemoizedCustomMessage(
7064
7083
  *
7065
7084
  * @internal Exported for unit testing only — not part of the public API.
7066
7085
  */
7086
+ /**
7087
+ * Collapse tool calls that share an id, keeping first-seen order.
7088
+ *
7089
+ * AG-UI's TOOL_CALL_START handler appends to the parent message's `toolCalls`
7090
+ * without checking whether that id is already present. So whenever a start
7091
+ * event is applied twice — which the human-in-the-loop flow triggers when the
7092
+ * run syncs after `respond()` — the message ends up carrying the same call
7093
+ * twice. The second copy has EMPTY `arguments`, because a start event carries
7094
+ * none; the args arrive later as TOOL_CALL_ARGS deltas addressed to the first
7095
+ * copy.
7096
+ *
7097
+ * Left alone that renders the same tool call twice: once populated and once
7098
+ * blank (an approval card with no transaction id, offering live buttons for an
7099
+ * action already taken), and React warns "Encountered two children with the
7100
+ * same key" because the call id is the render key.
7101
+ *
7102
+ * The empty copy is the redundant one, so prefer whichever entry actually
7103
+ * carries arguments rather than blindly taking the first.
7104
+ */
7105
+ function dedupeToolCalls(toolCalls) {
7106
+ const byId = /* @__PURE__ */ new Map();
7107
+ for (const toolCall of toolCalls) {
7108
+ const existing = byId.get(toolCall.id);
7109
+ if (!existing) {
7110
+ byId.set(toolCall.id, toolCall);
7111
+ continue;
7112
+ }
7113
+ if (!existing.function?.arguments && toolCall.function?.arguments) byId.set(toolCall.id, toolCall);
7114
+ }
7115
+ return byId.size === toolCalls.length ? toolCalls : [...byId.values()];
7116
+ }
7067
7117
  function deduplicateMessages(messages) {
7068
7118
  const acc = /* @__PURE__ */ new Map();
7069
7119
  for (const message of messages) {
@@ -7075,9 +7125,13 @@ function deduplicateMessages(messages) {
7075
7125
  ...existing,
7076
7126
  ...message,
7077
7127
  content,
7078
- toolCalls
7128
+ toolCalls: toolCalls ? dedupeToolCalls(toolCalls) : toolCalls
7079
7129
  });
7080
- } else acc.set(message.id, message);
7130
+ } else if (message.role === "assistant" && message.toolCalls) acc.set(message.id, {
7131
+ ...message,
7132
+ toolCalls: dedupeToolCalls(message.toolCalls)
7133
+ });
7134
+ else acc.set(message.id, message);
7081
7135
  }
7082
7136
  return [...acc.values()];
7083
7137
  }
@@ -12267,4 +12321,4 @@ Object.defineProperty(exports, 'ɵrunMcpFollowUp', {
12267
12321
  return ɵrunMcpFollowUp;
12268
12322
  }
12269
12323
  });
12270
- //# sourceMappingURL=copilotkit-2v7ami2b.cjs.map
12324
+ //# sourceMappingURL=copilotkit-sitn7Oe8.cjs.map