@copilotkit/react-core 1.9.2-next.9 → 1.9.3-next.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.
Files changed (147) hide show
  1. package/CHANGELOG.md +191 -0
  2. package/dist/{chunk-ERXWDCY6.mjs → chunk-36MGCCPZ.mjs} +2 -2
  3. package/dist/{chunk-UBNRUXEK.mjs → chunk-5BSUSFHM.mjs} +2 -2
  4. package/dist/{chunk-G7LYGERN.mjs → chunk-6ZLSC4KB.mjs} +124 -73
  5. package/dist/chunk-6ZLSC4KB.mjs.map +1 -0
  6. package/dist/{chunk-JDEWNLNP.mjs → chunk-BSAVFYRQ.mjs} +11 -11
  7. package/dist/{chunk-JDEWNLNP.mjs.map → chunk-BSAVFYRQ.mjs.map} +1 -1
  8. package/dist/{chunk-JPMIAGI6.mjs → chunk-BVK7PLK6.mjs} +2 -2
  9. package/dist/{chunk-FXK6RQIN.mjs → chunk-CUAFWKTQ.mjs} +4 -4
  10. package/dist/{chunk-XFOTNHYA.mjs → chunk-DKZTPL66.mjs} +2 -2
  11. package/dist/{chunk-XFOTNHYA.mjs.map → chunk-DKZTPL66.mjs.map} +1 -1
  12. package/dist/{chunk-EF5BNM34.mjs → chunk-FN3UA2ZE.mjs} +3 -3
  13. package/dist/{chunk-EXU7GWLC.mjs → chunk-GEE5AMYL.mjs} +9 -9
  14. package/dist/{chunk-WOGURSAL.mjs → chunk-GIMSRCVW.mjs} +64 -23
  15. package/dist/chunk-GIMSRCVW.mjs.map +1 -0
  16. package/dist/{chunk-55QZ2SVJ.mjs → chunk-JWAXDYOW.mjs} +8 -8
  17. package/dist/chunk-JWAXDYOW.mjs.map +1 -0
  18. package/dist/{chunk-3YHYWAHK.mjs → chunk-KIXKBJUV.mjs} +2 -2
  19. package/dist/{chunk-ADIITPD2.mjs → chunk-KLENTCQV.mjs} +34 -8
  20. package/dist/{chunk-ADIITPD2.mjs.map → chunk-KLENTCQV.mjs.map} +1 -1
  21. package/dist/{chunk-OF4SZTLL.mjs → chunk-NGQN3JRJ.mjs} +3 -3
  22. package/dist/{chunk-NQVCZQ5T.mjs → chunk-NJA5ZLAZ.mjs} +27 -8
  23. package/dist/chunk-NJA5ZLAZ.mjs.map +1 -0
  24. package/dist/{chunk-SJJNFYGQ.mjs → chunk-SGF6C7I6.mjs} +4 -4
  25. package/dist/{chunk-CMQV4XNY.mjs → chunk-VDADWRS3.mjs} +2 -2
  26. package/dist/components/copilot-provider/copilot-messages.js +7 -7
  27. package/dist/components/copilot-provider/copilot-messages.js.map +1 -1
  28. package/dist/components/copilot-provider/copilot-messages.mjs +3 -3
  29. package/dist/components/copilot-provider/copilotkit-props.d.ts +14 -9
  30. package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
  31. package/dist/components/copilot-provider/copilotkit.d.ts +1 -1
  32. package/dist/components/copilot-provider/copilotkit.js +70 -29
  33. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  34. package/dist/components/copilot-provider/copilotkit.mjs +9 -9
  35. package/dist/components/copilot-provider/index.d.ts +1 -1
  36. package/dist/components/copilot-provider/index.js +70 -29
  37. package/dist/components/copilot-provider/index.js.map +1 -1
  38. package/dist/components/copilot-provider/index.mjs +9 -9
  39. package/dist/components/error-boundary/error-boundary.mjs +2 -2
  40. package/dist/components/index.d.ts +1 -1
  41. package/dist/components/index.js +70 -29
  42. package/dist/components/index.js.map +1 -1
  43. package/dist/components/index.mjs +9 -9
  44. package/dist/context/copilot-context.d.ts +1 -1
  45. package/dist/context/copilot-context.js +1 -1
  46. package/dist/context/copilot-context.js.map +1 -1
  47. package/dist/context/copilot-context.mjs +1 -1
  48. package/dist/context/index.d.ts +1 -1
  49. package/dist/context/index.js +1 -1
  50. package/dist/context/index.js.map +1 -1
  51. package/dist/context/index.mjs +4 -4
  52. package/dist/{copilot-context-3da805ab.d.ts → copilot-context-3ab4fdf5.d.ts} +3 -3
  53. package/dist/hooks/index.d.ts +1 -1
  54. package/dist/hooks/index.js +179 -83
  55. package/dist/hooks/index.js.map +1 -1
  56. package/dist/hooks/index.mjs +23 -23
  57. package/dist/hooks/use-chat.d.ts +1 -1
  58. package/dist/hooks/use-chat.js +220 -169
  59. package/dist/hooks/use-chat.js.map +1 -1
  60. package/dist/hooks/use-chat.mjs +4 -4
  61. package/dist/hooks/use-coagent-state-render.js +1 -1
  62. package/dist/hooks/use-coagent-state-render.js.map +1 -1
  63. package/dist/hooks/use-coagent-state-render.mjs +2 -2
  64. package/dist/hooks/use-coagent.d.ts +1 -1
  65. package/dist/hooks/use-coagent.js +154 -77
  66. package/dist/hooks/use-coagent.js.map +1 -1
  67. package/dist/hooks/use-coagent.mjs +14 -14
  68. package/dist/hooks/use-copilot-action.js +26 -7
  69. package/dist/hooks/use-copilot-action.js.map +1 -1
  70. package/dist/hooks/use-copilot-action.mjs +2 -2
  71. package/dist/hooks/use-copilot-additional-instructions.js +1 -1
  72. package/dist/hooks/use-copilot-additional-instructions.js.map +1 -1
  73. package/dist/hooks/use-copilot-additional-instructions.mjs +2 -2
  74. package/dist/hooks/use-copilot-authenticated-action.js +26 -7
  75. package/dist/hooks/use-copilot-authenticated-action.js.map +1 -1
  76. package/dist/hooks/use-copilot-authenticated-action.mjs +3 -3
  77. package/dist/hooks/use-copilot-chat.d.ts +1 -1
  78. package/dist/hooks/use-copilot-chat.js +128 -77
  79. package/dist/hooks/use-copilot-chat.js.map +1 -1
  80. package/dist/hooks/use-copilot-chat.mjs +13 -13
  81. package/dist/hooks/use-copilot-readable.js +1 -1
  82. package/dist/hooks/use-copilot-readable.js.map +1 -1
  83. package/dist/hooks/use-copilot-readable.mjs +2 -2
  84. package/dist/hooks/use-copilot-runtime-client.d.ts +2 -2
  85. package/dist/hooks/use-copilot-runtime-client.js +7 -7
  86. package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
  87. package/dist/hooks/use-copilot-runtime-client.mjs +1 -1
  88. package/dist/hooks/use-langgraph-interrupt-render.js +1 -1
  89. package/dist/hooks/use-langgraph-interrupt-render.js.map +1 -1
  90. package/dist/hooks/use-langgraph-interrupt-render.mjs +2 -2
  91. package/dist/hooks/use-langgraph-interrupt.d.ts +1 -1
  92. package/dist/hooks/use-langgraph-interrupt.js +128 -77
  93. package/dist/hooks/use-langgraph-interrupt.js.map +1 -1
  94. package/dist/hooks/use-langgraph-interrupt.mjs +14 -14
  95. package/dist/hooks/use-make-copilot-document-readable.js +1 -1
  96. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  97. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  98. package/dist/index.d.ts +1 -1
  99. package/dist/index.js +240 -103
  100. package/dist/index.js.map +1 -1
  101. package/dist/index.mjs +27 -27
  102. package/dist/lib/copilot-task.d.ts +1 -1
  103. package/dist/lib/copilot-task.js.map +1 -1
  104. package/dist/lib/copilot-task.mjs +11 -11
  105. package/dist/lib/index.d.ts +1 -1
  106. package/dist/lib/index.js.map +1 -1
  107. package/dist/lib/index.mjs +11 -11
  108. package/dist/setupTests.d.ts +2 -0
  109. package/dist/setupTests.js +26 -0
  110. package/dist/setupTests.js.map +1 -0
  111. package/dist/setupTests.mjs +24 -0
  112. package/dist/setupTests.mjs.map +1 -0
  113. package/dist/types/interrupt-action.d.ts +1 -1
  114. package/dist/utils/extract.d.ts +1 -1
  115. package/dist/utils/extract.js.map +1 -1
  116. package/dist/utils/extract.mjs +9 -9
  117. package/dist/utils/index.d.ts +1 -1
  118. package/dist/utils/index.js.map +1 -1
  119. package/dist/utils/index.mjs +10 -10
  120. package/jest.config.js +4 -0
  121. package/package.json +6 -3
  122. package/src/components/copilot-provider/__tests__/{copilotkit-trace.test.tsx → copilotkit-error.test.tsx} +17 -17
  123. package/src/components/copilot-provider/copilot-messages.tsx +7 -7
  124. package/src/components/copilot-provider/copilotkit-props.tsx +13 -8
  125. package/src/components/copilot-provider/copilotkit.tsx +61 -19
  126. package/src/context/copilot-context.tsx +4 -4
  127. package/src/hooks/__tests__/use-coagent-config.test.ts +284 -0
  128. package/src/hooks/use-chat.ts +149 -61
  129. package/src/hooks/use-coagent.ts +36 -0
  130. package/src/hooks/use-copilot-action.ts +51 -9
  131. package/src/hooks/use-copilot-runtime-client.ts +11 -12
  132. package/src/setupTests.ts +26 -0
  133. package/tsconfig.json +5 -2
  134. package/dist/chunk-55QZ2SVJ.mjs.map +0 -1
  135. package/dist/chunk-G7LYGERN.mjs.map +0 -1
  136. package/dist/chunk-NQVCZQ5T.mjs.map +0 -1
  137. package/dist/chunk-WOGURSAL.mjs.map +0 -1
  138. /package/dist/{chunk-ERXWDCY6.mjs.map → chunk-36MGCCPZ.mjs.map} +0 -0
  139. /package/dist/{chunk-UBNRUXEK.mjs.map → chunk-5BSUSFHM.mjs.map} +0 -0
  140. /package/dist/{chunk-JPMIAGI6.mjs.map → chunk-BVK7PLK6.mjs.map} +0 -0
  141. /package/dist/{chunk-FXK6RQIN.mjs.map → chunk-CUAFWKTQ.mjs.map} +0 -0
  142. /package/dist/{chunk-EF5BNM34.mjs.map → chunk-FN3UA2ZE.mjs.map} +0 -0
  143. /package/dist/{chunk-EXU7GWLC.mjs.map → chunk-GEE5AMYL.mjs.map} +0 -0
  144. /package/dist/{chunk-3YHYWAHK.mjs.map → chunk-KIXKBJUV.mjs.map} +0 -0
  145. /package/dist/{chunk-OF4SZTLL.mjs.map → chunk-NGQN3JRJ.mjs.map} +0 -0
  146. /package/dist/{chunk-SJJNFYGQ.mjs.map → chunk-SGF6C7I6.mjs.map} +0 -0
  147. /package/dist/{chunk-CMQV4XNY.mjs.map → chunk-VDADWRS3.mjs.map} +0 -0
@@ -1,4 +1,5 @@
1
1
  import React, { useCallback, useEffect, useRef } from "react";
2
+ import { flushSync } from "react-dom";
2
3
  import {
3
4
  FunctionCallHandler,
4
5
  COPILOT_CLOUD_PUBLIC_API_KEY_HEADER,
@@ -37,9 +38,8 @@ import {
37
38
  import { CopilotApiConfig } from "../context";
38
39
  import { FrontendAction, processActionsForRuntimeRequest } from "../types/frontend-action";
39
40
  import { CoagentState } from "../types/coagent-state";
40
- import { AgentSession } from "../context/copilot-context";
41
+ import { AgentSession, useCopilotContext } from "../context/copilot-context";
41
42
  import { useCopilotRuntimeClient } from "./use-copilot-runtime-client";
42
- import { useCopilotContext } from "../context/copilot-context";
43
43
  import { useAsyncCallback, useErrorToast } from "../components/error-boundary/error-utils";
44
44
  import { useToast } from "../components/toast/toast-provider";
45
45
  import {
@@ -223,13 +223,13 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
223
223
  const addErrorToast = useErrorToast();
224
224
  const { setBannerError } = useToast();
225
225
 
226
- // Get onTrace from context since it's not part of copilotConfig
227
- const { onTrace } = useCopilotContext();
226
+ // Get onError from context since it's not part of copilotConfig
227
+ const { onError } = useCopilotContext();
228
228
 
229
229
  // Add tracing functionality to use-chat
230
230
  const traceUIError = async (error: CopilotKitError, originalError?: any) => {
231
- // Just check if onTrace and publicApiKey are defined
232
- if (!onTrace || !copilotConfig?.publicApiKey) return;
231
+ // Just check if onError and publicApiKey are defined
232
+ if (!onError || !copilotConfig?.publicApiKey) return;
233
233
 
234
234
  try {
235
235
  const traceEvent = {
@@ -251,9 +251,9 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
251
251
  error,
252
252
  };
253
253
 
254
- await onTrace(traceEvent);
254
+ await onError(traceEvent);
255
255
  } catch (traceError) {
256
- console.error("Error in use-chat onTrace handler:", traceError);
256
+ console.error("Error in use-chat onError handler:", traceError);
257
257
  }
258
258
  };
259
259
  // We need to keep a ref of coagent states and session because of renderAndWait - making sure
@@ -623,6 +623,8 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
623
623
  threadId: lastAgentStateMessage.threadId,
624
624
  nodeName: lastAgentStateMessage.nodeName,
625
625
  runId: lastAgentStateMessage.runId,
626
+ // Preserve existing config from previous state
627
+ config: prevAgentStates[lastAgentStateMessage.agentName]?.config,
626
628
  },
627
629
  }));
628
630
  if (lastAgentStateMessage.running) {
@@ -658,6 +660,55 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
658
660
 
659
661
  let didExecuteAction = false;
660
662
 
663
+ // ----- Helper function to execute an action and manage its lifecycle -----
664
+ const executeActionFromMessage = async (
665
+ currentAction: FrontendAction<any>,
666
+ actionMessage: ActionExecutionMessage,
667
+ ) => {
668
+ const isInterruptAction = interruptMessages.find((m) => m.id === actionMessage.id);
669
+ // Determine follow-up behavior: use action's specific setting if defined, otherwise default based on interrupt status.
670
+ followUp = currentAction?.followUp ?? !isInterruptAction;
671
+
672
+ // Call _setActivatingMessageId before executing the action for HITL correlation
673
+ if ((currentAction as any)?._setActivatingMessageId) {
674
+ (currentAction as any)._setActivatingMessageId(actionMessage.id);
675
+ }
676
+
677
+ const resultMessage = await executeAction({
678
+ onFunctionCall: onFunctionCall!,
679
+ message: actionMessage,
680
+ chatAbortControllerRef,
681
+ onError: (error: Error) => {
682
+ addErrorToast([error]);
683
+ // console.error is kept here as it's a genuine error in action execution
684
+ console.error(`Failed to execute action ${actionMessage.name}: ${error}`);
685
+ },
686
+ setMessages,
687
+ getFinalMessages: () => finalMessages,
688
+ isRenderAndWait: (currentAction as any)?._isRenderAndWait || false,
689
+ });
690
+ didExecuteAction = true;
691
+ const messageIndex = finalMessages.findIndex((msg) => msg.id === actionMessage.id);
692
+ finalMessages.splice(messageIndex + 1, 0, resultMessage);
693
+
694
+ // If the executed action was a renderAndWaitForResponse type, update messages immediately
695
+ // to reflect its completion in the UI, making it interactive promptly.
696
+ if ((currentAction as any)?._isRenderAndWait) {
697
+ const messagesForImmediateUpdate = [...finalMessages];
698
+ flushSync(() => {
699
+ setMessages(messagesForImmediateUpdate);
700
+ });
701
+ }
702
+
703
+ // Clear _setActivatingMessageId after the action is done
704
+ if ((currentAction as any)?._setActivatingMessageId) {
705
+ (currentAction as any)._setActivatingMessageId(null);
706
+ }
707
+
708
+ return resultMessage;
709
+ };
710
+ // ----------------------------------------------------------------------
711
+
661
712
  // execute regular action executions that are specific to the frontend (last actions)
662
713
  if (onFunctionCall) {
663
714
  // Find consecutive action execution messages at the end
@@ -687,44 +738,38 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
687
738
  ? getPairedFeAction(actions, message)
688
739
  : null;
689
740
 
690
- const executeActionFromMessage = async (
691
- action: FrontendAction<any>,
692
- message: ActionExecutionMessage,
693
- ) => {
694
- const isInterruptAction = interruptMessages.find((m) => m.id === message.id);
695
- followUp = action?.followUp ?? !isInterruptAction;
696
- const resultMessage = await executeAction({
697
- onFunctionCall,
698
- previousMessages,
699
- message,
700
- chatAbortControllerRef,
701
- onError: (error: Error) => {
702
- addErrorToast([error]);
703
- console.error(`Failed to execute action ${message.name}: ${error}`);
704
- },
705
- });
706
- didExecuteAction = true;
707
- const messageIndex = finalMessages.findIndex((msg) => msg.id === message.id);
708
- finalMessages.splice(messageIndex + 1, 0, resultMessage);
709
-
710
- return resultMessage;
711
- };
712
-
713
741
  // execution message which has an action registered with the hook (remote availability):
714
742
  // execute that action first, and then the "paired FE action"
715
743
  if (action && message.isActionExecutionMessage()) {
716
- const resultMessage = await executeActionFromMessage(action, message);
717
- const pairedFeAction = getPairedFeAction(actions, resultMessage);
718
-
719
- if (pairedFeAction) {
720
- const newExecutionMessage = new ActionExecutionMessage({
721
- name: pairedFeAction.name,
722
- arguments: parseJson(resultMessage.result, resultMessage.result),
723
- status: message.status,
724
- createdAt: message.createdAt,
725
- parentMessageId: message.parentMessageId,
726
- });
727
- await executeActionFromMessage(pairedFeAction, newExecutionMessage);
744
+ // For HITL actions, check if they've already been processed to avoid redundant handler calls.
745
+ const isRenderAndWaitAction = (action as any)?._isRenderAndWait || false;
746
+ const alreadyProcessed =
747
+ isRenderAndWaitAction &&
748
+ finalMessages.some(
749
+ (fm) => fm.isResultMessage() && fm.actionExecutionId === message.id,
750
+ );
751
+
752
+ if (alreadyProcessed) {
753
+ // Skip re-execution if already processed
754
+ } else {
755
+ // Call the single, externally defined executeActionFromMessage
756
+ const resultMessage = await executeActionFromMessage(
757
+ action,
758
+ message as ActionExecutionMessage,
759
+ );
760
+ const pairedFeAction = getPairedFeAction(actions, resultMessage);
761
+
762
+ if (pairedFeAction) {
763
+ const newExecutionMessage = new ActionExecutionMessage({
764
+ name: pairedFeAction.name,
765
+ arguments: parseJson(resultMessage.result, resultMessage.result),
766
+ status: message.status,
767
+ createdAt: message.createdAt,
768
+ parentMessageId: message.parentMessageId,
769
+ });
770
+ // Call the single, externally defined executeActionFromMessage
771
+ await executeActionFromMessage(pairedFeAction, newExecutionMessage);
772
+ }
728
773
  }
729
774
  } else if (message.isResultMessage() && currentResultMessagePairedFeAction) {
730
775
  // Actions which are set up in runtime actions array: Grab the result, executed paired FE action with it as args.
@@ -735,6 +780,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
735
780
  createdAt: message.createdAt,
736
781
  });
737
782
  finalMessages.push(newExecutionMessage);
783
+ // Call the single, externally defined executeActionFromMessage
738
784
  await executeActionFromMessage(
739
785
  currentResultMessagePairedFeAction,
740
786
  newExecutionMessage,
@@ -745,10 +791,10 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
745
791
  setMessages(finalMessages);
746
792
  }
747
793
 
794
+ // Conditionally run chat completion again if followUp is not explicitly false
795
+ // and an action was executed or the last message is a server-side result (for non-agent runs).
748
796
  if (
749
- // if followUp is not explicitly false
750
797
  followUp !== false &&
751
- // and we executed an action
752
798
  (didExecuteAction ||
753
799
  // the last message is a server side result
754
800
  (!isAgentRun &&
@@ -892,25 +938,47 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
892
938
  );
893
939
 
894
940
  const reload = useAsyncCallback(
895
- async (messageId: string): Promise<void> => {
941
+ async (reloadMessageId: string): Promise<void> => {
896
942
  if (isLoading || messages.length === 0) {
897
943
  return;
898
944
  }
899
945
 
900
- const index = messages.findIndex((msg) => msg.id === messageId);
901
- if (index === -1) {
902
- console.warn(`Message with id ${messageId} not found`);
946
+ const reloadMessageIndex = messages.findIndex((msg) => msg.id === reloadMessageId);
947
+ if (reloadMessageIndex === -1) {
948
+ console.warn(`Message with id ${reloadMessageId} not found`);
903
949
  return;
904
950
  }
905
951
 
906
- let newMessages = messages.slice(0, index); // excludes the message with messageId
907
- if (newMessages.length > 0 && newMessages[newMessages.length - 1].isAgentStateMessage()) {
908
- newMessages = newMessages.slice(0, newMessages.length - 1); // remove last one too
952
+ // @ts-expect-error -- message has role
953
+ const reloadMessageRole = messages[reloadMessageIndex].role;
954
+ if (reloadMessageRole !== MessageRole.Assistant) {
955
+ console.warn(`Regenerate cannot be performed on ${reloadMessageRole} role`);
956
+ return;
909
957
  }
910
958
 
911
- setMessages(newMessages);
959
+ let historyCutoff: Message[] = [];
960
+ if (messages.length > 2) {
961
+ // message to regenerate from is now first.
962
+ // Work backwards to find the first the closest user message
963
+ const lastUserMessageBeforeRegenerate = messages
964
+ .slice(0, reloadMessageIndex)
965
+ .reverse()
966
+ .find(
967
+ (msg) =>
968
+ // @ts-expect-error -- message has role
969
+ msg.role === MessageRole.User,
970
+ );
971
+ const indexOfLastUserMessageBeforeRegenerate = messages.findIndex(
972
+ (msg) => msg.id === lastUserMessageBeforeRegenerate!.id,
973
+ );
974
+
975
+ // Include the user message, remove everything after it
976
+ historyCutoff = messages.slice(0, indexOfLastUserMessageBeforeRegenerate + 1);
977
+ }
912
978
 
913
- return runChatCompletionAndHandleFunctionCall(newMessages);
979
+ setMessages(historyCutoff);
980
+
981
+ return runChatCompletionAndHandleFunctionCall(historyCutoff);
914
982
  },
915
983
  [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],
916
984
  );
@@ -958,26 +1026,46 @@ function constructFinalMessages(
958
1026
 
959
1027
  async function executeAction({
960
1028
  onFunctionCall,
961
- previousMessages,
962
1029
  message,
963
1030
  chatAbortControllerRef,
964
1031
  onError,
1032
+ setMessages,
1033
+ getFinalMessages,
1034
+ isRenderAndWait,
965
1035
  }: {
966
1036
  onFunctionCall: FunctionCallHandler;
967
- previousMessages: Message[];
968
1037
  message: ActionExecutionMessage;
969
1038
  chatAbortControllerRef: React.MutableRefObject<AbortController | null>;
970
1039
  onError: (error: Error) => void;
1040
+ setMessages: React.Dispatch<React.SetStateAction<Message[]>>;
1041
+ getFinalMessages: () => Message[];
1042
+ isRenderAndWait: boolean;
971
1043
  }) {
972
1044
  let result: any;
973
1045
  let error: Error | null = null;
1046
+
1047
+ const currentMessagesForHandler = getFinalMessages();
1048
+
1049
+ // The handler (onFunctionCall) runs its synchronous part here, potentially setting up
1050
+ // renderAndWaitRef.current for HITL actions via useCopilotAction's transformed handler.
1051
+ const handlerReturnedPromise = onFunctionCall({
1052
+ messages: currentMessagesForHandler,
1053
+ name: message.name,
1054
+ args: message.arguments,
1055
+ });
1056
+
1057
+ // For HITL actions, call flushSync immediately after their handler has set up the promise
1058
+ // and before awaiting the promise. This ensures the UI updates to an interactive state.
1059
+ if (isRenderAndWait) {
1060
+ const currentMessagesForRender = getFinalMessages();
1061
+ flushSync(() => {
1062
+ setMessages([...currentMessagesForRender]);
1063
+ });
1064
+ }
1065
+
974
1066
  try {
975
1067
  result = await Promise.race([
976
- onFunctionCall({
977
- messages: previousMessages,
978
- name: message.name,
979
- args: message.arguments,
980
- }),
1068
+ handlerReturnedPromise, // Await the promise returned by the handler
981
1069
  new Promise((resolve) =>
982
1070
  chatAbortControllerRef.current?.signal.addEventListener("abort", () =>
983
1071
  resolve("Operation was aborted by the user"),
@@ -311,6 +311,42 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
311
311
  coagentStates[name] === undefined,
312
312
  ]);
313
313
 
314
+ // Sync config when runtime configuration changes
315
+ useEffect(() => {
316
+ const newConfig = options.config
317
+ ? options.config
318
+ : options.configurable
319
+ ? { configurable: options.configurable }
320
+ : undefined;
321
+
322
+ if (newConfig === undefined) return;
323
+
324
+ setCoagentStatesWithRef((prev) => {
325
+ const existing = prev[name] ?? {
326
+ name,
327
+ state: isInternalStateManagementWithInitial(options) ? options.initialState : {},
328
+ config: {},
329
+ running: false,
330
+ active: false,
331
+ threadId: undefined,
332
+ nodeName: undefined,
333
+ runId: undefined,
334
+ };
335
+
336
+ if (JSON.stringify(existing.config) === JSON.stringify(newConfig)) {
337
+ return prev;
338
+ }
339
+
340
+ return {
341
+ ...prev,
342
+ [name]: {
343
+ ...existing,
344
+ config: newConfig,
345
+ },
346
+ };
347
+ });
348
+ }, [JSON.stringify(options.config), JSON.stringify(options.configurable)]);
349
+
314
350
  const runAgentCallback = useAsyncCallback(
315
351
  async (hint?: HintFunction) => {
316
352
  await runAgent(name, context, appendMessage, runChatCompletion, hint);
@@ -159,11 +159,14 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
159
159
  const { setAction, removeAction, actions, chatComponentsCache } = useCopilotContext();
160
160
  const idRef = useRef<string>(randomId());
161
161
  const renderAndWaitRef = useRef<RenderAndWaitForResponse | null>(null);
162
+ const activatingMessageIdRef = useRef<string | null>(null);
162
163
  const { addToast } = useToast();
163
164
 
164
165
  // clone the action to avoid mutating the original object
165
166
  action = { ...action };
166
167
 
168
+ // const { currentlyActivatingHitlActionMessageIdRef } = useCopilotContext() as any; // <-- REMOVE THIS FOR NOW
169
+
167
170
  // If the developer provides a renderAndWaitForResponse function, we transform the action
168
171
  // to use a promise internally, so that we can treat it like a normal action.
169
172
  if (
@@ -172,12 +175,21 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
172
175
  // check if renderAndWaitForResponse is set
173
176
  (action.renderAndWait || action.renderAndWaitForResponse)
174
177
  ) {
178
+ (action as any)._isRenderAndWait = true; // Internal flag to identify this action type later
175
179
  const renderAndWait = action.renderAndWait || action.renderAndWaitForResponse;
176
180
  // remove the renderAndWait function from the action
177
181
  action.renderAndWait = undefined;
178
182
  action.renderAndWaitForResponse = undefined;
183
+
184
+ // Add a method for use-chat.ts to set the activating message ID.
185
+ // This helps correlate the action instance with the message being processed by use-chat.
186
+ (action as any)._setActivatingMessageId = (id: string | null) => {
187
+ activatingMessageIdRef.current = id;
188
+ };
189
+
179
190
  // add a handler that will be called when the action is executed
180
191
  action.handler = useAsyncCallback(async () => {
192
+ const currentActivatingId = activatingMessageIdRef.current;
181
193
  // we create a new promise when the handler is called
182
194
  let resolve: (result: any) => void;
183
195
  let reject: (error: any) => void;
@@ -185,26 +197,55 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
185
197
  resolve = resolvePromise;
186
198
  reject = rejectPromise;
187
199
  });
188
- renderAndWaitRef.current = { promise, resolve: resolve!, reject: reject! };
200
+ renderAndWaitRef.current = {
201
+ promise,
202
+ resolve: resolve!,
203
+ reject: reject!,
204
+ messageId: currentActivatingId,
205
+ };
189
206
  // then we await the promise (it will be resolved in the original renderAndWait function)
190
- return await promise;
207
+ const result = await promise;
208
+ return result;
191
209
  }, []) as any;
192
210
 
193
211
  // add a render function that will be called when the action is rendered
194
- action.render = ((props: ActionRenderProps<T>): React.ReactElement => {
195
- // Specifically for renderAndWaitForResponse the executing state is set too early, causing a race condition
196
- // To fit it: we will wait for the handler to be ready
212
+ action.render = ((props: ActionRenderProps<T> & { messageId?: string }): React.ReactElement => {
213
+ const currentRenderMessageId = props.messageId;
214
+ // For renderAndWaitForResponse, the 'executing' state might be set by use-chat before
215
+ // this specific action instance's handler (and thus its promise) is ready.
216
+ // This logic adjusts the status to 'inProgress' if the current render
217
+ // isn't for the actively processing HITL action, preventing premature interaction.
197
218
  let status = props.status;
198
- if (props.status === "executing" && !renderAndWaitRef.current) {
199
- status = "inProgress";
219
+ if (props.status === "executing") {
220
+ if (!renderAndWaitRef.current || !renderAndWaitRef.current.promise) {
221
+ status = "inProgress";
222
+ } else if (
223
+ renderAndWaitRef.current.messageId !== currentRenderMessageId &&
224
+ activatingMessageIdRef.current !== currentRenderMessageId
225
+ ) {
226
+ status = "inProgress";
227
+ }
228
+ // If conditions met, status remains 'executing'
200
229
  }
201
230
  // Create type safe waitProps based on whether T extends empty array or not
202
231
  const waitProps = {
203
232
  status,
204
233
  args: props.args,
205
234
  result: props.result,
206
- handler: status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
207
- respond: status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
235
+ // handler and respond should only be provided if this is the truly active instance
236
+ // and its promise infrastructure is ready.
237
+ handler:
238
+ status === "executing" &&
239
+ renderAndWaitRef.current &&
240
+ renderAndWaitRef.current.messageId === currentRenderMessageId
241
+ ? renderAndWaitRef.current!.resolve
242
+ : undefined,
243
+ respond:
244
+ status === "executing" &&
245
+ renderAndWaitRef.current &&
246
+ renderAndWaitRef.current.messageId === currentRenderMessageId
247
+ ? renderAndWaitRef.current!.resolve
248
+ : undefined,
208
249
  } as T extends [] ? ActionRenderPropsNoArgsWait<T> : ActionRenderPropsWait<T>;
209
250
 
210
251
  // Type guard to check if renderAndWait is for no args case
@@ -302,4 +343,5 @@ interface RenderAndWaitForResponse {
302
343
  promise: Promise<any>;
303
344
  resolve: (result: any) => void;
304
345
  reject: (error: any) => void;
346
+ messageId: string | null;
305
347
  }
@@ -12,31 +12,30 @@ import {
12
12
  CopilotKitAgentDiscoveryError,
13
13
  CopilotKitError,
14
14
  CopilotKitErrorCode,
15
- ERROR_CONFIG,
16
- CopilotTraceHandler,
17
- CopilotTraceEvent,
15
+ CopilotErrorHandler,
16
+ CopilotErrorEvent,
18
17
  } from "@copilotkit/shared";
19
18
  import { shouldShowDevConsole } from "../utils/dev-console";
20
19
 
21
20
  export interface CopilotRuntimeClientHookOptions extends CopilotRuntimeClientOptions {
22
21
  showDevConsole?: boolean;
23
- onTrace?: CopilotTraceHandler;
22
+ onError?: CopilotErrorHandler;
24
23
  }
25
24
 
26
25
  export const useCopilotRuntimeClient = (options: CopilotRuntimeClientHookOptions) => {
27
26
  const { setBannerError } = useToast();
28
- const { showDevConsole, onTrace, ...runtimeOptions } = options;
27
+ const { showDevConsole, onError, ...runtimeOptions } = options;
29
28
 
30
29
  // Deduplication state for structured errors
31
30
  const lastStructuredErrorRef = useRef<{ message: string; timestamp: number } | null>(null);
32
31
 
33
32
  // Helper function to trace UI errors
34
33
  const traceUIError = async (error: CopilotKitError, originalError?: any) => {
35
- // Just check if onTrace and publicApiKey are defined
36
- if (!onTrace || !runtimeOptions.publicApiKey) return;
34
+ // Just check if onError and publicApiKey are defined
35
+ if (!onError || !runtimeOptions.publicApiKey) return;
37
36
 
38
37
  try {
39
- const traceEvent: CopilotTraceEvent = {
38
+ const errorEvent: CopilotErrorEvent = {
40
39
  type: "error",
41
40
  timestamp: Date.now(),
42
41
  context: {
@@ -54,9 +53,9 @@ export const useCopilotRuntimeClient = (options: CopilotRuntimeClientHookOptions
54
53
  },
55
54
  error,
56
55
  };
57
- await onTrace(traceEvent);
58
- } catch (traceError) {
59
- console.error("Error in onTrace handler:", traceError);
56
+ await onError(errorEvent);
57
+ } catch (error) {
58
+ console.error("Error in onError handler:", error);
60
59
  }
61
60
  };
62
61
 
@@ -142,7 +141,7 @@ export const useCopilotRuntimeClient = (options: CopilotRuntimeClientHookOptions
142
141
  setBannerError(warningError);
143
142
  },
144
143
  });
145
- }, [runtimeOptions, setBannerError, showDevConsole, onTrace]);
144
+ }, [runtimeOptions, setBannerError, showDevConsole, onError]);
146
145
 
147
146
  return runtimeClient;
148
147
  };
@@ -0,0 +1,26 @@
1
+ // Mock modules that cause ES module issues
2
+ jest.mock("@segment/analytics-node", () => ({
3
+ Analytics: jest.fn().mockImplementation(() => ({
4
+ track: jest.fn(),
5
+ identify: jest.fn(),
6
+ page: jest.fn(),
7
+ group: jest.fn(),
8
+ alias: jest.fn(),
9
+ })),
10
+ }));
11
+
12
+ jest.mock("@copilotkit/shared", () => ({
13
+ parseJson: jest.fn((jsonString, defaultValue) => {
14
+ try {
15
+ return JSON.parse(jsonString);
16
+ } catch {
17
+ return defaultValue;
18
+ }
19
+ }),
20
+ CopilotKitAgentDiscoveryError: jest.fn(),
21
+ }));
22
+
23
+ // Mock react-dom/test-utils to avoid compatibility issues
24
+ jest.mock("react-dom/test-utils", () => ({
25
+ act: jest.fn((fn) => fn()),
26
+ }));
package/tsconfig.json CHANGED
@@ -1,5 +1,8 @@
1
1
  {
2
2
  "extends": "../../utilities/tsconfig/react-library.json",
3
- "include": ["."],
4
- "exclude": ["dist", "build", "node_modules", "**/*.test.ts", "**/*.test.tsx", "**/__tests__/*"]
3
+ "compilerOptions": {
4
+ "types": ["jest", "@types/jest"]
5
+ },
6
+ "include": ["src/**/*"],
7
+ "exclude": ["dist", "build", "node_modules"]
5
8
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-copilot-runtime-client.ts"],"sourcesContent":["import {\n CopilotRuntimeClient,\n CopilotRuntimeClientOptions,\n GraphQLError,\n} from \"@copilotkit/runtime-client-gql\";\nimport { useToast } from \"../components/toast/toast-provider\";\nimport { useMemo, useRef } from \"react\";\nimport {\n ErrorVisibility,\n CopilotKitApiDiscoveryError,\n CopilotKitRemoteEndpointDiscoveryError,\n CopilotKitAgentDiscoveryError,\n CopilotKitError,\n CopilotKitErrorCode,\n ERROR_CONFIG,\n CopilotTraceHandler,\n CopilotTraceEvent,\n} from \"@copilotkit/shared\";\nimport { shouldShowDevConsole } from \"../utils/dev-console\";\n\nexport interface CopilotRuntimeClientHookOptions extends CopilotRuntimeClientOptions {\n showDevConsole?: boolean;\n onTrace?: CopilotTraceHandler;\n}\n\nexport const useCopilotRuntimeClient = (options: CopilotRuntimeClientHookOptions) => {\n const { setBannerError } = useToast();\n const { showDevConsole, onTrace, ...runtimeOptions } = options;\n\n // Deduplication state for structured errors\n const lastStructuredErrorRef = useRef<{ message: string; timestamp: number } | null>(null);\n\n // Helper function to trace UI errors\n const traceUIError = async (error: CopilotKitError, originalError?: any) => {\n // Just check if onTrace and publicApiKey are defined\n if (!onTrace || !runtimeOptions.publicApiKey) return;\n\n try {\n const traceEvent: CopilotTraceEvent = {\n type: \"error\",\n timestamp: Date.now(),\n context: {\n source: \"ui\",\n request: {\n operation: \"runtimeClient\",\n url: runtimeOptions.url,\n startTime: Date.now(),\n },\n technical: {\n environment: \"browser\",\n userAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : undefined,\n stackTrace: originalError instanceof Error ? originalError.stack : undefined,\n },\n },\n error,\n };\n await onTrace(traceEvent);\n } catch (traceError) {\n console.error(\"Error in onTrace handler:\", traceError);\n }\n };\n\n const runtimeClient = useMemo(() => {\n return new CopilotRuntimeClient({\n ...runtimeOptions,\n handleGQLErrors: (error) => {\n if ((error as any).graphQLErrors?.length) {\n const graphQLErrors = (error as any).graphQLErrors as GraphQLError[];\n\n // Route all errors to banners for consistent UI\n const routeError = (gqlError: GraphQLError) => {\n const extensions = gqlError.extensions;\n const visibility = extensions?.visibility as ErrorVisibility;\n const isDev = shouldShowDevConsole(showDevConsole ?? false);\n\n // Silent errors - just log\n if (visibility === ErrorVisibility.SILENT) {\n console.error(\"CopilotKit Silent Error:\", gqlError.message);\n return;\n }\n\n if (!isDev) {\n console.error(\"CopilotKit Error (hidden in production):\", gqlError.message);\n return;\n }\n\n // All errors (including DEV_ONLY) show as banners for consistency\n // Deduplicate to prevent spam\n const now = Date.now();\n const errorMessage = gqlError.message;\n if (\n lastStructuredErrorRef.current &&\n lastStructuredErrorRef.current.message === errorMessage &&\n now - lastStructuredErrorRef.current.timestamp < 150\n ) {\n return; // Skip duplicate\n }\n lastStructuredErrorRef.current = { message: errorMessage, timestamp: now };\n\n const ckError = createStructuredError(gqlError);\n if (ckError) {\n setBannerError(ckError);\n // Trace the error\n traceUIError(ckError, gqlError);\n } else {\n // Fallback for unstructured errors\n const fallbackError = new CopilotKitError({\n message: gqlError.message,\n code: CopilotKitErrorCode.UNKNOWN,\n });\n setBannerError(fallbackError);\n // Trace the fallback error\n traceUIError(fallbackError, gqlError);\n }\n };\n\n // Process all errors as banners\n graphQLErrors.forEach(routeError);\n } else {\n const isDev = shouldShowDevConsole(showDevConsole ?? false);\n if (!isDev) {\n console.error(\"CopilotKit Error (hidden in production):\", error);\n } else {\n // Route non-GraphQL errors to banner as well\n const fallbackError = new CopilotKitError({\n message: error?.message || String(error),\n code: CopilotKitErrorCode.UNKNOWN,\n });\n setBannerError(fallbackError);\n // Trace the non-GraphQL error\n traceUIError(fallbackError, error);\n }\n }\n },\n handleGQLWarning: (message: string) => {\n console.warn(message);\n // Show warnings as banners too for consistency\n const warningError = new CopilotKitError({\n message,\n code: CopilotKitErrorCode.UNKNOWN,\n });\n setBannerError(warningError);\n },\n });\n }, [runtimeOptions, setBannerError, showDevConsole, onTrace]);\n\n return runtimeClient;\n};\n\n// Create appropriate structured error from GraphQL error\nfunction createStructuredError(gqlError: GraphQLError): CopilotKitError | null {\n const extensions = gqlError.extensions;\n const originalError = extensions?.originalError as any;\n const message = originalError?.message || gqlError.message;\n const code = extensions?.code as CopilotKitErrorCode;\n\n if (code) {\n return new CopilotKitError({ message, code });\n }\n\n // Legacy error detection by stack trace\n if (originalError?.stack?.includes(\"CopilotApiDiscoveryError\")) {\n return new CopilotKitApiDiscoveryError({ message });\n }\n if (originalError?.stack?.includes(\"CopilotKitRemoteEndpointDiscoveryError\")) {\n return new CopilotKitRemoteEndpointDiscoveryError({ message });\n }\n if (originalError?.stack?.includes(\"CopilotKitAgentDiscoveryError\")) {\n return new CopilotKitAgentDiscoveryError({\n agentName: \"\",\n availableAgents: [],\n });\n }\n\n return null;\n}\n"],"mappings":"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","names":["_a"]}