@copilotkit/react-core 1.4.8-no-pino-redact.1 → 1.5.0-coagents-v0-3.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 +22 -3
- package/dist/{chunk-JHEAUB3Z.mjs → chunk-35EN6BG4.mjs} +2 -2
- package/dist/{chunk-JHEAUB3Z.mjs.map → chunk-35EN6BG4.mjs.map} +1 -1
- package/dist/{chunk-O22KGHOQ.mjs → chunk-42N5VKIX.mjs} +38 -16
- package/dist/chunk-42N5VKIX.mjs.map +1 -0
- package/dist/{chunk-AG7FH7OD.mjs → chunk-5FYKUKG3.mjs} +2 -2
- package/dist/{chunk-ODN4H66E.mjs → chunk-7LRDVJH5.mjs} +6 -2
- package/dist/chunk-7LRDVJH5.mjs.map +1 -0
- package/dist/{chunk-Y7MI4PBB.mjs → chunk-ALR5W5JK.mjs} +22 -10
- package/dist/chunk-ALR5W5JK.mjs.map +1 -0
- package/dist/{chunk-XBVKTDXP.mjs → chunk-BT6WK2JZ.mjs} +57 -17
- package/dist/chunk-BT6WK2JZ.mjs.map +1 -0
- package/dist/chunk-QCUP6HLK.mjs +37 -0
- package/dist/chunk-QCUP6HLK.mjs.map +1 -0
- package/dist/chunk-QTDCEDOC.mjs +392 -0
- package/dist/chunk-QTDCEDOC.mjs.map +1 -0
- package/dist/{chunk-OT67R4NB.mjs → chunk-QX6V774L.mjs} +6 -8
- package/dist/chunk-QX6V774L.mjs.map +1 -0
- package/dist/{chunk-2KCEHGSI.mjs → chunk-SFPANIOY.mjs} +99 -49
- package/dist/chunk-SFPANIOY.mjs.map +1 -0
- package/dist/{chunk-XQFVXX6R.mjs → chunk-TQN3EZWQ.mjs} +10 -2
- package/dist/chunk-TQN3EZWQ.mjs.map +1 -0
- package/dist/{chunk-UOVONDR6.mjs → chunk-V3PFWGIY.mjs} +2 -2
- package/dist/{chunk-DHGXL5PC.mjs → chunk-VMP6JWBB.mjs} +18 -6
- package/dist/chunk-VMP6JWBB.mjs.map +1 -0
- package/dist/chunk-XERJQUHA.mjs +31 -0
- package/dist/chunk-XERJQUHA.mjs.map +1 -0
- package/dist/components/copilot-provider/copilotkit.js +175 -93
- package/dist/components/copilot-provider/copilotkit.js.map +1 -1
- package/dist/components/copilot-provider/copilotkit.mjs +5 -4
- package/dist/components/copilot-provider/index.js +175 -93
- package/dist/components/copilot-provider/index.js.map +1 -1
- package/dist/components/copilot-provider/index.mjs +5 -4
- package/dist/components/error-boundary/error-boundary.d.ts +22 -0
- package/dist/components/error-boundary/error-boundary.js +183 -0
- package/dist/components/error-boundary/error-boundary.js.map +1 -0
- package/dist/components/error-boundary/error-boundary.mjs +12 -0
- package/dist/components/error-boundary/error-boundary.mjs.map +1 -0
- package/dist/components/error-boundary/error-utils.d.ts +11 -0
- package/dist/components/error-boundary/error-utils.js +177 -0
- package/dist/components/error-boundary/error-utils.js.map +1 -0
- package/dist/components/error-boundary/error-utils.mjs +13 -0
- package/dist/components/error-boundary/error-utils.mjs.map +1 -0
- package/dist/components/index.js +175 -93
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +5 -4
- package/dist/components/toast/toast-provider.d.ts +2 -1
- package/dist/components/toast/toast-provider.js +76 -62
- package/dist/components/toast/toast-provider.js.map +1 -1
- package/dist/components/toast/toast-provider.mjs +1 -1
- package/dist/context/copilot-context.d.ts +8 -2
- package/dist/context/copilot-context.js +9 -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 +9 -1
- package/dist/context/index.js.map +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/index.js +584 -270
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +19 -11
- package/dist/hooks/use-chat.d.ts +20 -0
- package/dist/hooks/use-chat.js +438 -200
- package/dist/hooks/use-chat.js.map +1 -1
- package/dist/hooks/use-chat.mjs +4 -3
- package/dist/hooks/use-coagent-state-render.d.ts +2 -2
- package/dist/hooks/use-coagent-state-render.js +9 -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 +14 -1
- package/dist/hooks/use-coagent.js +547 -242
- package/dist/hooks/use-coagent.js.map +1 -1
- package/dist/hooks/use-coagent.mjs +15 -7
- package/dist/hooks/use-copilot-action.d.ts +12 -2
- package/dist/hooks/use-copilot-action.js +156 -14
- package/dist/hooks/use-copilot-action.js.map +1 -1
- package/dist/hooks/use-copilot-action.mjs +4 -2
- package/dist/hooks/use-copilot-chat.d.ts +1 -0
- package/dist/hooks/use-copilot-chat.js +514 -231
- package/dist/hooks/use-copilot-chat.js.map +1 -1
- package/dist/hooks/use-copilot-chat.mjs +8 -6
- package/dist/hooks/use-copilot-readable.js +9 -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.js +110 -4
- package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
- package/dist/hooks/use-copilot-runtime-client.mjs +2 -2
- package/dist/hooks/use-make-copilot-document-readable.js +9 -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 +2 -2
- package/dist/index.js +642 -363
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +20 -12
- package/dist/lib/copilot-task.d.ts +1 -1
- package/dist/lib/copilot-task.js +33 -13
- package/dist/lib/copilot-task.js.map +1 -1
- package/dist/lib/copilot-task.mjs +7 -5
- package/dist/lib/index.d.ts +1 -1
- package/dist/lib/index.js +33 -13
- package/dist/lib/index.js.map +1 -1
- package/dist/lib/index.mjs +7 -5
- package/dist/types/frontend-action.d.ts +21 -2
- package/dist/types/frontend-action.js +34 -0
- package/dist/types/frontend-action.js.map +1 -1
- package/dist/types/frontend-action.mjs +7 -0
- package/dist/types/index.d.ts +2 -1
- package/dist/types/index.js.map +1 -1
- package/dist/utils/extract.js.map +1 -1
- package/dist/utils/extract.mjs +5 -4
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/index.mjs +5 -4
- package/package.json +3 -3
- package/src/components/copilot-provider/copilotkit.tsx +14 -1
- package/src/components/error-boundary/error-boundary.tsx +42 -0
- package/src/components/error-boundary/error-utils.tsx +95 -0
- package/src/components/toast/toast-provider.tsx +10 -49
- package/src/context/copilot-context.tsx +30 -2
- package/src/hooks/index.ts +1 -1
- package/src/hooks/use-chat.ts +391 -256
- package/src/hooks/use-coagent-state-render.ts +2 -2
- package/src/hooks/use-coagent.ts +35 -15
- package/src/hooks/use-copilot-action.ts +41 -12
- package/src/hooks/use-copilot-chat.ts +52 -11
- package/src/hooks/use-copilot-runtime-client.ts +4 -0
- package/src/lib/copilot-task.ts +2 -8
- package/src/types/frontend-action.ts +55 -2
- package/src/types/index.ts +5 -1
- package/dist/chunk-2KCEHGSI.mjs.map +0 -1
- package/dist/chunk-DHGXL5PC.mjs.map +0 -1
- package/dist/chunk-EUIBVFV6.mjs +0 -294
- package/dist/chunk-EUIBVFV6.mjs.map +0 -1
- package/dist/chunk-O22KGHOQ.mjs.map +0 -1
- package/dist/chunk-ODN4H66E.mjs.map +0 -1
- package/dist/chunk-OT67R4NB.mjs.map +0 -1
- package/dist/chunk-XBVKTDXP.mjs.map +0 -1
- package/dist/chunk-XQFVXX6R.mjs.map +0 -1
- package/dist/chunk-Y7MI4PBB.mjs.map +0 -1
- /package/dist/{chunk-AG7FH7OD.mjs.map → chunk-5FYKUKG3.mjs.map} +0 -0
- /package/dist/{chunk-UOVONDR6.mjs.map → chunk-V3PFWGIY.mjs.map} +0 -0
package/src/hooks/use-chat.ts
CHANGED
|
@@ -18,14 +18,16 @@ import {
|
|
|
18
18
|
Role,
|
|
19
19
|
CopilotRequestType,
|
|
20
20
|
ActionInputAvailability,
|
|
21
|
+
loadMessagesFromJsonRepresentation,
|
|
21
22
|
} from "@copilotkit/runtime-client-gql";
|
|
22
23
|
|
|
23
24
|
import { CopilotApiConfig } from "../context";
|
|
24
|
-
import { FrontendAction } from "../types/frontend-action";
|
|
25
|
+
import { FrontendAction, processActionsForRuntimeRequest } from "../types/frontend-action";
|
|
25
26
|
import { CoagentState } from "../types/coagent-state";
|
|
26
27
|
import { AgentSession } from "../context/copilot-context";
|
|
27
28
|
import { useToast } from "../components/toast/toast-provider";
|
|
28
29
|
import { useCopilotRuntimeClient } from "./use-copilot-runtime-client";
|
|
30
|
+
import { useAsyncCallback } from "../components/error-boundary/error-utils";
|
|
29
31
|
|
|
30
32
|
export type UseChatOptions = {
|
|
31
33
|
/**
|
|
@@ -97,6 +99,27 @@ export type UseChatOptions = {
|
|
|
97
99
|
* setState-powered method to update the agent session
|
|
98
100
|
*/
|
|
99
101
|
setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* The current thread ID.
|
|
105
|
+
*/
|
|
106
|
+
threadId: string | null;
|
|
107
|
+
/**
|
|
108
|
+
* set the current thread ID
|
|
109
|
+
*/
|
|
110
|
+
setThreadId: (threadId: string | null) => void;
|
|
111
|
+
/**
|
|
112
|
+
* The current run ID.
|
|
113
|
+
*/
|
|
114
|
+
runId: string | null;
|
|
115
|
+
/**
|
|
116
|
+
* set the current run ID
|
|
117
|
+
*/
|
|
118
|
+
setRunId: (runId: string | null) => void;
|
|
119
|
+
/**
|
|
120
|
+
* The global chat abort controller.
|
|
121
|
+
*/
|
|
122
|
+
chatAbortControllerRef: React.MutableRefObject<AbortController | null>;
|
|
100
123
|
};
|
|
101
124
|
|
|
102
125
|
export type UseChatHelpers = {
|
|
@@ -139,19 +162,23 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
139
162
|
coagentStatesRef,
|
|
140
163
|
agentSession,
|
|
141
164
|
setAgentSession,
|
|
165
|
+
threadId,
|
|
166
|
+
setThreadId,
|
|
167
|
+
runId,
|
|
168
|
+
setRunId,
|
|
169
|
+
chatAbortControllerRef,
|
|
142
170
|
} = options;
|
|
143
|
-
|
|
144
|
-
const abortControllerRef = useRef<AbortController>();
|
|
145
|
-
const threadIdRef = useRef<string | null>(null);
|
|
146
|
-
const runIdRef = useRef<string | null>(null);
|
|
147
171
|
const { addGraphQLErrorsToast } = useToast();
|
|
148
|
-
|
|
149
172
|
const runChatCompletionRef = useRef<(previousMessages: Message[]) => Promise<Message[]>>();
|
|
150
173
|
// We need to keep a ref of coagent states and session because of renderAndWait - making sure
|
|
151
174
|
// the latest state is sent to the API
|
|
152
175
|
// This is a workaround and needs to be addressed in the future
|
|
153
176
|
const agentSessionRef = useRef<AgentSession | null>(agentSession);
|
|
154
177
|
agentSessionRef.current = agentSession;
|
|
178
|
+
const threadIdRef = useRef<string | null>(threadId);
|
|
179
|
+
threadIdRef.current = threadId;
|
|
180
|
+
const runIdRef = useRef<string | null>(runId);
|
|
181
|
+
runIdRef.current = runId;
|
|
155
182
|
|
|
156
183
|
const publicApiKey = copilotConfig.publicApiKey;
|
|
157
184
|
|
|
@@ -167,292 +194,371 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
167
194
|
credentials: copilotConfig.credentials,
|
|
168
195
|
});
|
|
169
196
|
|
|
170
|
-
const runChatCompletion =
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}),
|
|
216
|
-
url: window.location.href,
|
|
217
|
-
},
|
|
218
|
-
threadId: threadIdRef.current,
|
|
219
|
-
runId: runIdRef.current,
|
|
220
|
-
messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
|
|
221
|
-
...(copilotConfig.cloud
|
|
222
|
-
? {
|
|
223
|
-
cloud: {
|
|
224
|
-
...(copilotConfig.cloud.guardrails?.input?.restrictToTopic?.enabled
|
|
225
|
-
? {
|
|
226
|
-
guardrails: {
|
|
227
|
-
inputValidationRules: {
|
|
228
|
-
allowList:
|
|
229
|
-
copilotConfig.cloud.guardrails.input.restrictToTopic.validTopics,
|
|
230
|
-
denyList:
|
|
231
|
-
copilotConfig.cloud.guardrails.input.restrictToTopic.invalidTopics,
|
|
197
|
+
const runChatCompletion = useAsyncCallback(
|
|
198
|
+
async (previousMessages: Message[]): Promise<Message[]> => {
|
|
199
|
+
setIsLoading(true);
|
|
200
|
+
|
|
201
|
+
// this message is just a placeholder. It will disappear once the first real message
|
|
202
|
+
// is received
|
|
203
|
+
let newMessages: Message[] = [
|
|
204
|
+
new TextMessage({
|
|
205
|
+
content: "",
|
|
206
|
+
role: Role.Assistant,
|
|
207
|
+
}),
|
|
208
|
+
];
|
|
209
|
+
|
|
210
|
+
chatAbortControllerRef.current = new AbortController();
|
|
211
|
+
|
|
212
|
+
setMessages([...previousMessages, ...newMessages]);
|
|
213
|
+
|
|
214
|
+
const systemMessage = makeSystemMessageCallback();
|
|
215
|
+
|
|
216
|
+
const messagesWithContext = [systemMessage, ...(initialMessages || []), ...previousMessages];
|
|
217
|
+
|
|
218
|
+
const isAgentRun = agentSessionRef.current !== null;
|
|
219
|
+
|
|
220
|
+
const stream = runtimeClient.asStream(
|
|
221
|
+
runtimeClient.generateCopilotResponse({
|
|
222
|
+
data: {
|
|
223
|
+
frontend: {
|
|
224
|
+
actions: processActionsForRuntimeRequest(actions),
|
|
225
|
+
url: window.location.href,
|
|
226
|
+
},
|
|
227
|
+
threadId: threadIdRef.current,
|
|
228
|
+
runId: runIdRef.current,
|
|
229
|
+
messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
|
|
230
|
+
...(copilotConfig.cloud
|
|
231
|
+
? {
|
|
232
|
+
cloud: {
|
|
233
|
+
...(copilotConfig.cloud.guardrails?.input?.restrictToTopic?.enabled
|
|
234
|
+
? {
|
|
235
|
+
guardrails: {
|
|
236
|
+
inputValidationRules: {
|
|
237
|
+
allowList:
|
|
238
|
+
copilotConfig.cloud.guardrails.input.restrictToTopic.validTopics,
|
|
239
|
+
denyList:
|
|
240
|
+
copilotConfig.cloud.guardrails.input.restrictToTopic.invalidTopics,
|
|
241
|
+
},
|
|
232
242
|
},
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
: {
|
|
239
|
-
|
|
240
|
-
|
|
243
|
+
}
|
|
244
|
+
: {}),
|
|
245
|
+
},
|
|
246
|
+
}
|
|
247
|
+
: {}),
|
|
248
|
+
metadata: {
|
|
249
|
+
requestType: CopilotRequestType.Chat,
|
|
250
|
+
},
|
|
251
|
+
...(agentSessionRef.current
|
|
252
|
+
? {
|
|
253
|
+
agentSession: agentSessionRef.current,
|
|
254
|
+
}
|
|
255
|
+
: {}),
|
|
256
|
+
agentStates: Object.values(coagentStatesRef.current!).map((state) => ({
|
|
257
|
+
agentName: state.name,
|
|
258
|
+
state: JSON.stringify(state.state),
|
|
259
|
+
})),
|
|
241
260
|
},
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
: {}),
|
|
247
|
-
agentStates: Object.values(coagentStatesRef.current!).map((state) => ({
|
|
248
|
-
agentName: state.name,
|
|
249
|
-
state: JSON.stringify(state.state),
|
|
250
|
-
})),
|
|
251
|
-
},
|
|
252
|
-
properties: copilotConfig.properties,
|
|
253
|
-
signal: abortControllerRef.current?.signal,
|
|
254
|
-
}),
|
|
255
|
-
);
|
|
256
|
-
|
|
257
|
-
const guardrailsEnabled =
|
|
258
|
-
copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
|
|
259
|
-
|
|
260
|
-
const reader = stream.getReader();
|
|
261
|
-
|
|
262
|
-
let actionResults: { [id: string]: string } = {};
|
|
263
|
-
let executedCoAgentStateRenders: string[] = [];
|
|
264
|
-
let followUp: FrontendAction["followUp"] = undefined;
|
|
265
|
-
|
|
266
|
-
try {
|
|
267
|
-
while (true) {
|
|
268
|
-
let done, value;
|
|
269
|
-
|
|
270
|
-
try {
|
|
271
|
-
const readResult = await reader.read();
|
|
272
|
-
done = readResult.done;
|
|
273
|
-
value = readResult.value;
|
|
274
|
-
} catch (readError) {
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
261
|
+
properties: copilotConfig.properties,
|
|
262
|
+
signal: chatAbortControllerRef.current?.signal,
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
277
265
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
266
|
+
const guardrailsEnabled =
|
|
267
|
+
copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
|
|
281
268
|
|
|
282
|
-
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
269
|
+
const reader = stream.getReader();
|
|
285
270
|
|
|
286
|
-
|
|
287
|
-
|
|
271
|
+
let executedCoAgentStateRenders: string[] = [];
|
|
272
|
+
let followUp: FrontendAction["followUp"] = undefined;
|
|
288
273
|
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
);
|
|
274
|
+
let messages: Message[] = [];
|
|
275
|
+
let syncedMessages: Message[] = [];
|
|
292
276
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
277
|
+
try {
|
|
278
|
+
while (true) {
|
|
279
|
+
let done, value;
|
|
296
280
|
|
|
297
|
-
|
|
281
|
+
try {
|
|
282
|
+
const readResult = await reader.read();
|
|
283
|
+
done = readResult.done;
|
|
284
|
+
value = readResult.value;
|
|
285
|
+
} catch (readError) {
|
|
286
|
+
break;
|
|
287
|
+
}
|
|
298
288
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
289
|
+
if (done) {
|
|
290
|
+
if (chatAbortControllerRef.current.signal.aborted) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (!value?.generateCopilotResponse) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
threadIdRef.current = value.generateCopilotResponse.threadId || null;
|
|
301
|
+
runIdRef.current = value.generateCopilotResponse.runId || null;
|
|
302
|
+
|
|
303
|
+
setThreadId(threadIdRef.current);
|
|
304
|
+
setRunId(runIdRef.current);
|
|
305
|
+
|
|
306
|
+
messages = convertGqlOutputToMessages(
|
|
307
|
+
filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
if (messages.length === 0) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
newMessages = [];
|
|
315
|
+
|
|
316
|
+
// request failed, display error message and quit
|
|
317
|
+
if (
|
|
318
|
+
value.generateCopilotResponse.status?.__typename === "FailedResponseStatus" &&
|
|
319
|
+
value.generateCopilotResponse.status.reason === "GUARDRAILS_VALIDATION_FAILED"
|
|
320
|
+
) {
|
|
321
|
+
newMessages = [
|
|
322
|
+
new TextMessage({
|
|
323
|
+
role: MessageRole.Assistant,
|
|
324
|
+
content: value.generateCopilotResponse.status.details?.guardrailsReason || "",
|
|
325
|
+
}),
|
|
326
|
+
];
|
|
327
|
+
setMessages([...previousMessages, ...newMessages]);
|
|
328
|
+
break;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
// add messages to the chat
|
|
332
|
+
else {
|
|
333
|
+
newMessages = [...messages];
|
|
334
|
+
|
|
335
|
+
for (const message of messages) {
|
|
336
|
+
// execute onCoAgentStateRender handler
|
|
337
|
+
if (
|
|
338
|
+
message.isAgentStateMessage() &&
|
|
339
|
+
!message.active &&
|
|
340
|
+
!executedCoAgentStateRenders.includes(message.id) &&
|
|
341
|
+
onCoAgentStateRender
|
|
342
|
+
) {
|
|
343
|
+
// Do not execute a coagent action if guardrails are enabled but the status is not known
|
|
344
|
+
if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
|
|
345
|
+
break;
|
|
346
|
+
}
|
|
347
|
+
// execute coagent action
|
|
348
|
+
await onCoAgentStateRender({
|
|
349
|
+
name: message.agentName,
|
|
350
|
+
nodeName: message.nodeName,
|
|
351
|
+
state: message.state,
|
|
352
|
+
});
|
|
353
|
+
executedCoAgentStateRenders.push(message.id);
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
const lastAgentStateMessage = [...messages]
|
|
358
|
+
.reverse()
|
|
359
|
+
.find((message) => message.isAgentStateMessage());
|
|
360
|
+
|
|
361
|
+
if (lastAgentStateMessage) {
|
|
362
|
+
if (
|
|
363
|
+
lastAgentStateMessage.state.messages &&
|
|
364
|
+
lastAgentStateMessage.state.messages.length > 0
|
|
365
|
+
) {
|
|
366
|
+
syncedMessages = loadMessagesFromJsonRepresentation(
|
|
367
|
+
lastAgentStateMessage.state.messages,
|
|
368
|
+
);
|
|
369
|
+
}
|
|
370
|
+
setCoagentStatesWithRef((prevAgentStates) => ({
|
|
371
|
+
...prevAgentStates,
|
|
372
|
+
[lastAgentStateMessage.agentName]: {
|
|
373
|
+
name: lastAgentStateMessage.agentName,
|
|
374
|
+
state: lastAgentStateMessage.state,
|
|
375
|
+
running: lastAgentStateMessage.running,
|
|
376
|
+
active: lastAgentStateMessage.active,
|
|
377
|
+
threadId: lastAgentStateMessage.threadId,
|
|
378
|
+
nodeName: lastAgentStateMessage.nodeName,
|
|
379
|
+
runId: lastAgentStateMessage.runId,
|
|
380
|
+
},
|
|
381
|
+
}));
|
|
382
|
+
if (lastAgentStateMessage.running) {
|
|
383
|
+
setAgentSession({
|
|
384
|
+
threadId: lastAgentStateMessage.threadId,
|
|
385
|
+
agentName: lastAgentStateMessage.agentName,
|
|
386
|
+
nodeName: lastAgentStateMessage.nodeName,
|
|
387
|
+
});
|
|
388
|
+
} else {
|
|
389
|
+
setAgentSession(null);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
if (newMessages.length > 0) {
|
|
395
|
+
// Update message state
|
|
396
|
+
setMessages([...previousMessages, ...newMessages]);
|
|
397
|
+
}
|
|
310
398
|
}
|
|
399
|
+
const finalMessages = constructFinalMessages(syncedMessages, previousMessages, newMessages);
|
|
400
|
+
|
|
401
|
+
let didExecuteAction = false;
|
|
311
402
|
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
403
|
+
// execute regular action executions that are specific to the frontend (last actions)
|
|
404
|
+
if (onFunctionCall) {
|
|
405
|
+
// Find consecutive action execution messages at the end
|
|
406
|
+
const lastMessages = [];
|
|
407
|
+
for (let i = finalMessages.length - 1; i >= 0; i--) {
|
|
408
|
+
const message = finalMessages[i];
|
|
317
409
|
if (
|
|
318
410
|
message.isActionExecutionMessage() &&
|
|
319
|
-
message.status.code !== MessageStatusCode.Pending
|
|
320
|
-
message.scope === "client" &&
|
|
321
|
-
onFunctionCall
|
|
411
|
+
message.status.code !== MessageStatusCode.Pending
|
|
322
412
|
) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
// execute action
|
|
329
|
-
try {
|
|
330
|
-
// We update the message state before calling the handler so that the render
|
|
331
|
-
// function can be called with `executing` state
|
|
332
|
-
setMessages([...previousMessages, ...newMessages]);
|
|
413
|
+
lastMessages.unshift(message);
|
|
414
|
+
} else {
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
333
418
|
|
|
334
|
-
|
|
419
|
+
for (const message of lastMessages) {
|
|
420
|
+
// We update the message state before calling the handler so that the render
|
|
421
|
+
// function can be called with `executing` state
|
|
422
|
+
setMessages(finalMessages);
|
|
335
423
|
|
|
336
|
-
|
|
337
|
-
followUp = action.followUp;
|
|
338
|
-
}
|
|
424
|
+
const action = actions.find((action) => action.name === message.name);
|
|
339
425
|
|
|
340
|
-
|
|
426
|
+
if (action) {
|
|
427
|
+
followUp = action.followUp;
|
|
428
|
+
let result: any;
|
|
429
|
+
try {
|
|
430
|
+
result = await Promise.race([
|
|
431
|
+
onFunctionCall({
|
|
341
432
|
messages: previousMessages,
|
|
342
433
|
name: message.name,
|
|
343
434
|
args: message.arguments,
|
|
344
|
-
})
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
435
|
+
}),
|
|
436
|
+
new Promise((resolve) =>
|
|
437
|
+
chatAbortControllerRef.current?.signal.addEventListener("abort", () =>
|
|
438
|
+
resolve("Operation was aborted by the user"),
|
|
439
|
+
),
|
|
440
|
+
),
|
|
441
|
+
// if the user stopped generation, we also abort consecutive actions
|
|
442
|
+
new Promise((resolve) => {
|
|
443
|
+
if (chatAbortControllerRef.current?.signal.aborted) {
|
|
444
|
+
resolve("Operation was aborted by the user");
|
|
445
|
+
}
|
|
446
|
+
}),
|
|
447
|
+
]);
|
|
448
|
+
} catch (e) {
|
|
449
|
+
result = `Failed to execute action ${message.name}`;
|
|
450
|
+
console.error(`Failed to execute action ${message.name}: ${e}`);
|
|
350
451
|
}
|
|
351
|
-
|
|
352
|
-
|
|
452
|
+
didExecuteAction = true;
|
|
453
|
+
const messageIndex = finalMessages.findIndex((msg) => msg.id === message.id);
|
|
454
|
+
finalMessages.splice(
|
|
455
|
+
messageIndex + 1,
|
|
456
|
+
0,
|
|
353
457
|
new ResultMessage({
|
|
354
|
-
|
|
458
|
+
id: "result-" + message.id,
|
|
459
|
+
result: ResultMessage.encodeResult(result),
|
|
355
460
|
actionExecutionId: message.id,
|
|
356
461
|
actionName: message.name,
|
|
357
462
|
}),
|
|
358
463
|
);
|
|
359
464
|
}
|
|
360
|
-
// execute coagent actions
|
|
361
|
-
if (
|
|
362
|
-
message.isAgentStateMessage() &&
|
|
363
|
-
!message.active &&
|
|
364
|
-
!executedCoAgentStateRenders.includes(message.id) &&
|
|
365
|
-
onCoAgentStateRender
|
|
366
|
-
) {
|
|
367
|
-
// Do not execute a coagent action if guardrails are enabled but the status is not known
|
|
368
|
-
if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
|
|
369
|
-
break;
|
|
370
|
-
}
|
|
371
|
-
// execute coagent action
|
|
372
|
-
await onCoAgentStateRender({
|
|
373
|
-
name: message.agentName,
|
|
374
|
-
nodeName: message.nodeName,
|
|
375
|
-
state: message.state,
|
|
376
|
-
});
|
|
377
|
-
executedCoAgentStateRenders.push(message.id);
|
|
378
|
-
}
|
|
379
465
|
}
|
|
380
466
|
|
|
381
|
-
|
|
382
|
-
.reverse()
|
|
383
|
-
.find((message) => message.isAgentStateMessage());
|
|
384
|
-
|
|
385
|
-
if (lastAgentStateMessage) {
|
|
386
|
-
setCoagentStatesWithRef((prevAgentStates) => ({
|
|
387
|
-
...prevAgentStates,
|
|
388
|
-
[lastAgentStateMessage.agentName]: {
|
|
389
|
-
name: lastAgentStateMessage.agentName,
|
|
390
|
-
state: lastAgentStateMessage.state,
|
|
391
|
-
running: lastAgentStateMessage.running,
|
|
392
|
-
active: lastAgentStateMessage.active,
|
|
393
|
-
threadId: lastAgentStateMessage.threadId,
|
|
394
|
-
nodeName: lastAgentStateMessage.nodeName,
|
|
395
|
-
runId: lastAgentStateMessage.runId,
|
|
396
|
-
},
|
|
397
|
-
}));
|
|
398
|
-
if (lastAgentStateMessage.running) {
|
|
399
|
-
setAgentSession({
|
|
400
|
-
threadId: lastAgentStateMessage.threadId,
|
|
401
|
-
agentName: lastAgentStateMessage.agentName,
|
|
402
|
-
nodeName: lastAgentStateMessage.nodeName,
|
|
403
|
-
});
|
|
404
|
-
} else {
|
|
405
|
-
setAgentSession(null);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
467
|
+
setMessages(finalMessages);
|
|
408
468
|
}
|
|
409
469
|
|
|
410
|
-
if (
|
|
411
|
-
//
|
|
412
|
-
|
|
470
|
+
if (
|
|
471
|
+
// if followUp is not explicitly false
|
|
472
|
+
followUp !== false &&
|
|
473
|
+
// and we executed an action
|
|
474
|
+
(didExecuteAction ||
|
|
475
|
+
// the last message is a server side result
|
|
476
|
+
(!isAgentRun &&
|
|
477
|
+
finalMessages.length &&
|
|
478
|
+
finalMessages[finalMessages.length - 1].isResultMessage())) &&
|
|
479
|
+
// the user did not stop generation
|
|
480
|
+
!chatAbortControllerRef.current?.signal.aborted
|
|
481
|
+
) {
|
|
482
|
+
// run the completion again and return the result
|
|
483
|
+
|
|
484
|
+
// wait for next tick to make sure all the react state updates
|
|
485
|
+
// - tried using react-dom's flushSync, but it did not work
|
|
486
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
487
|
+
|
|
488
|
+
return await runChatCompletionRef.current!(finalMessages);
|
|
489
|
+
} else if (chatAbortControllerRef.current?.signal.aborted) {
|
|
490
|
+
// filter out all the action execution messages that do not have a consecutive matching result message
|
|
491
|
+
const repairedMessages = finalMessages.filter((message, actionExecutionIndex) => {
|
|
492
|
+
if (message.isActionExecutionMessage()) {
|
|
493
|
+
return finalMessages.find(
|
|
494
|
+
(msg, resultIndex) =>
|
|
495
|
+
msg.isResultMessage() &&
|
|
496
|
+
msg.actionExecutionId === message.id &&
|
|
497
|
+
resultIndex === actionExecutionIndex + 1,
|
|
498
|
+
);
|
|
499
|
+
}
|
|
500
|
+
return true;
|
|
501
|
+
});
|
|
502
|
+
const repairedMessageIds = repairedMessages.map((message) => message.id);
|
|
503
|
+
setMessages(repairedMessages);
|
|
504
|
+
|
|
505
|
+
if (agentSessionRef.current?.nodeName) {
|
|
506
|
+
setAgentSession({
|
|
507
|
+
threadId: agentSessionRef.current.threadId,
|
|
508
|
+
agentName: agentSessionRef.current.agentName,
|
|
509
|
+
nodeName: "__end__",
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
// only return new messages that were not filtered out
|
|
513
|
+
return newMessages.filter((message) => repairedMessageIds.includes(message.id));
|
|
514
|
+
} else {
|
|
515
|
+
return newMessages.slice();
|
|
413
516
|
}
|
|
517
|
+
} finally {
|
|
518
|
+
setIsLoading(false);
|
|
414
519
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
} finally {
|
|
435
|
-
setIsLoading(false);
|
|
436
|
-
}
|
|
437
|
-
};
|
|
520
|
+
},
|
|
521
|
+
[
|
|
522
|
+
messages,
|
|
523
|
+
setMessages,
|
|
524
|
+
makeSystemMessageCallback,
|
|
525
|
+
copilotConfig,
|
|
526
|
+
setIsLoading,
|
|
527
|
+
initialMessages,
|
|
528
|
+
isLoading,
|
|
529
|
+
actions,
|
|
530
|
+
onFunctionCall,
|
|
531
|
+
onCoAgentStateRender,
|
|
532
|
+
setCoagentStatesWithRef,
|
|
533
|
+
coagentStatesRef,
|
|
534
|
+
agentSession,
|
|
535
|
+
setAgentSession,
|
|
536
|
+
],
|
|
537
|
+
);
|
|
438
538
|
|
|
439
539
|
runChatCompletionRef.current = runChatCompletion;
|
|
440
540
|
|
|
441
|
-
const runChatCompletionAndHandleFunctionCall =
|
|
442
|
-
|
|
443
|
-
|
|
541
|
+
const runChatCompletionAndHandleFunctionCall = useAsyncCallback(
|
|
542
|
+
async (messages: Message[]): Promise<void> => {
|
|
543
|
+
await runChatCompletionRef.current!(messages);
|
|
544
|
+
},
|
|
545
|
+
[messages],
|
|
546
|
+
);
|
|
547
|
+
|
|
548
|
+
const append = useAsyncCallback(
|
|
549
|
+
async (message: Message): Promise<void> => {
|
|
550
|
+
if (isLoading) {
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
444
553
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
554
|
+
const newMessages = [...messages, message];
|
|
555
|
+
setMessages(newMessages);
|
|
556
|
+
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
557
|
+
},
|
|
558
|
+
[isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],
|
|
559
|
+
);
|
|
449
560
|
|
|
450
|
-
|
|
451
|
-
setMessages(newMessages);
|
|
452
|
-
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
453
|
-
};
|
|
454
|
-
|
|
455
|
-
const reload = async (): Promise<void> => {
|
|
561
|
+
const reload = useAsyncCallback(async (): Promise<void> => {
|
|
456
562
|
if (isLoading || messages.length === 0) {
|
|
457
563
|
return;
|
|
458
564
|
}
|
|
@@ -466,10 +572,10 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
466
572
|
setMessages(newMessages);
|
|
467
573
|
|
|
468
574
|
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
469
|
-
};
|
|
575
|
+
}, [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall]);
|
|
470
576
|
|
|
471
577
|
const stop = (): void => {
|
|
472
|
-
|
|
578
|
+
chatAbortControllerRef.current?.abort("Stop was called");
|
|
473
579
|
};
|
|
474
580
|
|
|
475
581
|
return {
|
|
@@ -479,3 +585,32 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
479
585
|
runChatCompletion: () => runChatCompletionRef.current!(messages),
|
|
480
586
|
};
|
|
481
587
|
}
|
|
588
|
+
|
|
589
|
+
function constructFinalMessages(
|
|
590
|
+
syncedMessages: Message[],
|
|
591
|
+
previousMessages: Message[],
|
|
592
|
+
newMessages: Message[],
|
|
593
|
+
): Message[] {
|
|
594
|
+
const finalMessages =
|
|
595
|
+
syncedMessages.length > 0 ? [...syncedMessages] : [...previousMessages, ...newMessages];
|
|
596
|
+
|
|
597
|
+
if (syncedMessages.length > 0) {
|
|
598
|
+
const messagesWithAgentState = [...previousMessages, ...newMessages];
|
|
599
|
+
|
|
600
|
+
let previousMessageId: string | undefined = undefined;
|
|
601
|
+
|
|
602
|
+
for (const message of messagesWithAgentState) {
|
|
603
|
+
if (message.isAgentStateMessage()) {
|
|
604
|
+
// insert this message into finalMessages after the position of previousMessageId
|
|
605
|
+
const index = finalMessages.findIndex((msg) => msg.id === previousMessageId);
|
|
606
|
+
if (index !== -1) {
|
|
607
|
+
finalMessages.splice(index + 1, 0, message);
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
previousMessageId = message.id;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
return finalMessages;
|
|
616
|
+
}
|