@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.
- package/CHANGELOG.md +191 -0
- package/dist/{chunk-ERXWDCY6.mjs → chunk-36MGCCPZ.mjs} +2 -2
- package/dist/{chunk-UBNRUXEK.mjs → chunk-5BSUSFHM.mjs} +2 -2
- package/dist/{chunk-G7LYGERN.mjs → chunk-6ZLSC4KB.mjs} +124 -73
- package/dist/chunk-6ZLSC4KB.mjs.map +1 -0
- package/dist/{chunk-JDEWNLNP.mjs → chunk-BSAVFYRQ.mjs} +11 -11
- package/dist/{chunk-JDEWNLNP.mjs.map → chunk-BSAVFYRQ.mjs.map} +1 -1
- package/dist/{chunk-JPMIAGI6.mjs → chunk-BVK7PLK6.mjs} +2 -2
- package/dist/{chunk-FXK6RQIN.mjs → chunk-CUAFWKTQ.mjs} +4 -4
- package/dist/{chunk-XFOTNHYA.mjs → chunk-DKZTPL66.mjs} +2 -2
- package/dist/{chunk-XFOTNHYA.mjs.map → chunk-DKZTPL66.mjs.map} +1 -1
- package/dist/{chunk-EF5BNM34.mjs → chunk-FN3UA2ZE.mjs} +3 -3
- package/dist/{chunk-EXU7GWLC.mjs → chunk-GEE5AMYL.mjs} +9 -9
- package/dist/{chunk-WOGURSAL.mjs → chunk-GIMSRCVW.mjs} +64 -23
- package/dist/chunk-GIMSRCVW.mjs.map +1 -0
- package/dist/{chunk-55QZ2SVJ.mjs → chunk-JWAXDYOW.mjs} +8 -8
- package/dist/chunk-JWAXDYOW.mjs.map +1 -0
- package/dist/{chunk-3YHYWAHK.mjs → chunk-KIXKBJUV.mjs} +2 -2
- package/dist/{chunk-ADIITPD2.mjs → chunk-KLENTCQV.mjs} +34 -8
- package/dist/{chunk-ADIITPD2.mjs.map → chunk-KLENTCQV.mjs.map} +1 -1
- package/dist/{chunk-OF4SZTLL.mjs → chunk-NGQN3JRJ.mjs} +3 -3
- package/dist/{chunk-NQVCZQ5T.mjs → chunk-NJA5ZLAZ.mjs} +27 -8
- package/dist/chunk-NJA5ZLAZ.mjs.map +1 -0
- package/dist/{chunk-SJJNFYGQ.mjs → chunk-SGF6C7I6.mjs} +4 -4
- package/dist/{chunk-CMQV4XNY.mjs → chunk-VDADWRS3.mjs} +2 -2
- package/dist/components/copilot-provider/copilot-messages.js +7 -7
- package/dist/components/copilot-provider/copilot-messages.js.map +1 -1
- package/dist/components/copilot-provider/copilot-messages.mjs +3 -3
- package/dist/components/copilot-provider/copilotkit-props.d.ts +14 -9
- package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
- package/dist/components/copilot-provider/copilotkit.d.ts +1 -1
- package/dist/components/copilot-provider/copilotkit.js +70 -29
- package/dist/components/copilot-provider/copilotkit.js.map +1 -1
- package/dist/components/copilot-provider/copilotkit.mjs +9 -9
- package/dist/components/copilot-provider/index.d.ts +1 -1
- package/dist/components/copilot-provider/index.js +70 -29
- package/dist/components/copilot-provider/index.js.map +1 -1
- package/dist/components/copilot-provider/index.mjs +9 -9
- package/dist/components/error-boundary/error-boundary.mjs +2 -2
- package/dist/components/index.d.ts +1 -1
- package/dist/components/index.js +70 -29
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +9 -9
- package/dist/context/copilot-context.d.ts +1 -1
- package/dist/context/copilot-context.js +1 -1
- package/dist/context/copilot-context.js.map +1 -1
- package/dist/context/copilot-context.mjs +1 -1
- package/dist/context/index.d.ts +1 -1
- package/dist/context/index.js +1 -1
- package/dist/context/index.js.map +1 -1
- package/dist/context/index.mjs +4 -4
- package/dist/{copilot-context-3da805ab.d.ts → copilot-context-3ab4fdf5.d.ts} +3 -3
- package/dist/hooks/index.d.ts +1 -1
- package/dist/hooks/index.js +179 -83
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +23 -23
- package/dist/hooks/use-chat.d.ts +1 -1
- package/dist/hooks/use-chat.js +220 -169
- package/dist/hooks/use-chat.js.map +1 -1
- package/dist/hooks/use-chat.mjs +4 -4
- package/dist/hooks/use-coagent-state-render.js +1 -1
- package/dist/hooks/use-coagent-state-render.js.map +1 -1
- package/dist/hooks/use-coagent-state-render.mjs +2 -2
- package/dist/hooks/use-coagent.d.ts +1 -1
- package/dist/hooks/use-coagent.js +154 -77
- package/dist/hooks/use-coagent.js.map +1 -1
- package/dist/hooks/use-coagent.mjs +14 -14
- package/dist/hooks/use-copilot-action.js +26 -7
- package/dist/hooks/use-copilot-action.js.map +1 -1
- package/dist/hooks/use-copilot-action.mjs +2 -2
- package/dist/hooks/use-copilot-additional-instructions.js +1 -1
- package/dist/hooks/use-copilot-additional-instructions.js.map +1 -1
- package/dist/hooks/use-copilot-additional-instructions.mjs +2 -2
- package/dist/hooks/use-copilot-authenticated-action.js +26 -7
- package/dist/hooks/use-copilot-authenticated-action.js.map +1 -1
- package/dist/hooks/use-copilot-authenticated-action.mjs +3 -3
- package/dist/hooks/use-copilot-chat.d.ts +1 -1
- package/dist/hooks/use-copilot-chat.js +128 -77
- package/dist/hooks/use-copilot-chat.js.map +1 -1
- package/dist/hooks/use-copilot-chat.mjs +13 -13
- package/dist/hooks/use-copilot-readable.js +1 -1
- package/dist/hooks/use-copilot-readable.js.map +1 -1
- package/dist/hooks/use-copilot-readable.mjs +2 -2
- package/dist/hooks/use-copilot-runtime-client.d.ts +2 -2
- package/dist/hooks/use-copilot-runtime-client.js +7 -7
- package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
- package/dist/hooks/use-copilot-runtime-client.mjs +1 -1
- package/dist/hooks/use-langgraph-interrupt-render.js +1 -1
- package/dist/hooks/use-langgraph-interrupt-render.js.map +1 -1
- package/dist/hooks/use-langgraph-interrupt-render.mjs +2 -2
- package/dist/hooks/use-langgraph-interrupt.d.ts +1 -1
- package/dist/hooks/use-langgraph-interrupt.js +128 -77
- package/dist/hooks/use-langgraph-interrupt.js.map +1 -1
- package/dist/hooks/use-langgraph-interrupt.mjs +14 -14
- package/dist/hooks/use-make-copilot-document-readable.js +1 -1
- package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
- package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +240 -103
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +27 -27
- package/dist/lib/copilot-task.d.ts +1 -1
- package/dist/lib/copilot-task.js.map +1 -1
- package/dist/lib/copilot-task.mjs +11 -11
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +11 -11
- package/dist/setupTests.d.ts +2 -0
- package/dist/setupTests.js +26 -0
- package/dist/setupTests.js.map +1 -0
- package/dist/setupTests.mjs +24 -0
- package/dist/setupTests.mjs.map +1 -0
- package/dist/types/interrupt-action.d.ts +1 -1
- package/dist/utils/extract.d.ts +1 -1
- package/dist/utils/extract.js.map +1 -1
- package/dist/utils/extract.mjs +9 -9
- package/dist/utils/index.d.ts +1 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +10 -10
- package/jest.config.js +4 -0
- package/package.json +6 -3
- package/src/components/copilot-provider/__tests__/{copilotkit-trace.test.tsx → copilotkit-error.test.tsx} +17 -17
- package/src/components/copilot-provider/copilot-messages.tsx +7 -7
- package/src/components/copilot-provider/copilotkit-props.tsx +13 -8
- package/src/components/copilot-provider/copilotkit.tsx +61 -19
- package/src/context/copilot-context.tsx +4 -4
- package/src/hooks/__tests__/use-coagent-config.test.ts +284 -0
- package/src/hooks/use-chat.ts +149 -61
- package/src/hooks/use-coagent.ts +36 -0
- package/src/hooks/use-copilot-action.ts +51 -9
- package/src/hooks/use-copilot-runtime-client.ts +11 -12
- package/src/setupTests.ts +26 -0
- package/tsconfig.json +5 -2
- package/dist/chunk-55QZ2SVJ.mjs.map +0 -1
- package/dist/chunk-G7LYGERN.mjs.map +0 -1
- package/dist/chunk-NQVCZQ5T.mjs.map +0 -1
- package/dist/chunk-WOGURSAL.mjs.map +0 -1
- /package/dist/{chunk-ERXWDCY6.mjs.map → chunk-36MGCCPZ.mjs.map} +0 -0
- /package/dist/{chunk-UBNRUXEK.mjs.map → chunk-5BSUSFHM.mjs.map} +0 -0
- /package/dist/{chunk-JPMIAGI6.mjs.map → chunk-BVK7PLK6.mjs.map} +0 -0
- /package/dist/{chunk-FXK6RQIN.mjs.map → chunk-CUAFWKTQ.mjs.map} +0 -0
- /package/dist/{chunk-EF5BNM34.mjs.map → chunk-FN3UA2ZE.mjs.map} +0 -0
- /package/dist/{chunk-EXU7GWLC.mjs.map → chunk-GEE5AMYL.mjs.map} +0 -0
- /package/dist/{chunk-3YHYWAHK.mjs.map → chunk-KIXKBJUV.mjs.map} +0 -0
- /package/dist/{chunk-OF4SZTLL.mjs.map → chunk-NGQN3JRJ.mjs.map} +0 -0
- /package/dist/{chunk-SJJNFYGQ.mjs.map → chunk-SGF6C7I6.mjs.map} +0 -0
- /package/dist/{chunk-CMQV4XNY.mjs.map → chunk-VDADWRS3.mjs.map} +0 -0
package/src/hooks/use-chat.ts
CHANGED
|
@@ -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
|
|
227
|
-
const {
|
|
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
|
|
232
|
-
if (!
|
|
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
|
|
254
|
+
await onError(traceEvent);
|
|
255
255
|
} catch (traceError) {
|
|
256
|
-
console.error("Error in use-chat
|
|
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
|
-
|
|
717
|
-
const
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
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 (
|
|
941
|
+
async (reloadMessageId: string): Promise<void> => {
|
|
896
942
|
if (isLoading || messages.length === 0) {
|
|
897
943
|
return;
|
|
898
944
|
}
|
|
899
945
|
|
|
900
|
-
const
|
|
901
|
-
if (
|
|
902
|
-
console.warn(`Message with id ${
|
|
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
|
-
|
|
907
|
-
|
|
908
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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"),
|
package/src/hooks/use-coagent.ts
CHANGED
|
@@ -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 = {
|
|
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
|
-
|
|
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
|
-
|
|
196
|
-
//
|
|
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"
|
|
199
|
-
|
|
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
|
|
207
|
-
|
|
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
|
-
|
|
16
|
-
|
|
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
|
-
|
|
22
|
+
onError?: CopilotErrorHandler;
|
|
24
23
|
}
|
|
25
24
|
|
|
26
25
|
export const useCopilotRuntimeClient = (options: CopilotRuntimeClientHookOptions) => {
|
|
27
26
|
const { setBannerError } = useToast();
|
|
28
|
-
const { showDevConsole,
|
|
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
|
|
36
|
-
if (!
|
|
34
|
+
// Just check if onError and publicApiKey are defined
|
|
35
|
+
if (!onError || !runtimeOptions.publicApiKey) return;
|
|
37
36
|
|
|
38
37
|
try {
|
|
39
|
-
const
|
|
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
|
|
58
|
-
} catch (
|
|
59
|
-
console.error("Error in
|
|
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,
|
|
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
|
-
"
|
|
4
|
-
|
|
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"]}
|