@copilotkit/react-core 1.5.0-tyler-reset-chat.0 → 1.5.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 +158 -4
- package/README.md +2 -0
- package/dist/{chunk-3AYELZJS.mjs → chunk-35EN6BG4.mjs} +2 -2
- package/dist/{chunk-3AYELZJS.mjs.map → chunk-35EN6BG4.mjs.map} +1 -1
- package/dist/{chunk-SEPYQHH7.mjs → chunk-42N5VKIX.mjs} +34 -28
- package/dist/chunk-42N5VKIX.mjs.map +1 -0
- package/dist/{chunk-USL3EHJB.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-CZMEZR6F.mjs → chunk-BT6WK2JZ.mjs} +34 -19
- package/dist/chunk-BT6WK2JZ.mjs.map +1 -0
- package/dist/{chunk-3R4J2TPH.mjs → chunk-EUU6NNYU.mjs} +29 -13
- package/dist/chunk-EUU6NNYU.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-JR55I3FL.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-2JP64U3A.mjs → chunk-TQN3EZWQ.mjs} +4 -1
- package/dist/chunk-TQN3EZWQ.mjs.map +1 -0
- package/dist/{chunk-XUPO37VH.mjs → chunk-V3PFWGIY.mjs} +2 -2
- package/dist/{chunk-6QKA3SNN.mjs → chunk-VMP6JWBB.mjs} +21 -5
- 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 +173 -92
- 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 +173 -92
- 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 +173 -92
- 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 +4 -2
- package/dist/context/copilot-context.js +3 -0
- 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 +3 -0
- package/dist/context/index.js.map +1 -1
- package/dist/context/index.mjs +1 -1
- package/dist/hooks/index.js +554 -308
- package/dist/hooks/index.js.map +1 -1
- package/dist/hooks/index.mjs +13 -11
- package/dist/hooks/use-chat.d.ts +6 -2
- package/dist/hooks/use-chat.js +434 -219
- 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 +3 -0
- 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 +510 -277
- package/dist/hooks/use-coagent.js.map +1 -1
- package/dist/hooks/use-coagent.mjs +9 -7
- package/dist/hooks/use-copilot-action.d.ts +12 -2
- package/dist/hooks/use-copilot-action.js +157 -16
- 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 +483 -253
- 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 +3 -0
- 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 +3 -0
- 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 +616 -401
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -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 +5 -5
- package/src/components/copilot-provider/copilotkit.tsx +22 -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 +17 -2
- package/src/hooks/use-chat.ts +375 -279
- package/src/hooks/use-coagent-state-render.ts +2 -2
- package/src/hooks/use-coagent.ts +34 -28
- package/src/hooks/use-copilot-action.ts +50 -15
- package/src/hooks/use-copilot-chat.ts +28 -14
- 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-2JP64U3A.mjs.map +0 -1
- package/dist/chunk-2KCEHGSI.mjs.map +0 -1
- package/dist/chunk-3R4J2TPH.mjs.map +0 -1
- package/dist/chunk-6EN7J4V2.mjs +0 -317
- package/dist/chunk-6EN7J4V2.mjs.map +0 -1
- package/dist/chunk-6QKA3SNN.mjs.map +0 -1
- package/dist/chunk-CZMEZR6F.mjs.map +0 -1
- package/dist/chunk-JR55I3FL.mjs.map +0 -1
- package/dist/chunk-ODN4H66E.mjs.map +0 -1
- package/dist/chunk-SEPYQHH7.mjs.map +0 -1
- /package/dist/{chunk-USL3EHJB.mjs.map → chunk-5FYKUKG3.mjs.map} +0 -0
- /package/dist/{chunk-XUPO37VH.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
|
/**
|
|
@@ -81,12 +83,12 @@ export type UseChatOptions = {
|
|
|
81
83
|
/**
|
|
82
84
|
* The current list of coagent states.
|
|
83
85
|
*/
|
|
84
|
-
|
|
86
|
+
coagentStatesRef: React.RefObject<Record<string, CoagentState>>;
|
|
85
87
|
|
|
86
88
|
/**
|
|
87
89
|
* setState-powered method to update the agent states
|
|
88
90
|
*/
|
|
89
|
-
|
|
91
|
+
setCoagentStatesWithRef: React.Dispatch<React.SetStateAction<Record<string, CoagentState>>>;
|
|
90
92
|
|
|
91
93
|
/**
|
|
92
94
|
* The current agent session.
|
|
@@ -137,6 +139,11 @@ export type UseChatHelpers = {
|
|
|
137
139
|
* Abort the current request immediately, keep the generated tokens if any.
|
|
138
140
|
*/
|
|
139
141
|
stop: () => void;
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Run the chat completion.
|
|
145
|
+
*/
|
|
146
|
+
runChatCompletion: () => Promise<Message[]>;
|
|
140
147
|
};
|
|
141
148
|
|
|
142
149
|
export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
@@ -151,8 +158,8 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
151
158
|
actions,
|
|
152
159
|
onFunctionCall,
|
|
153
160
|
onCoAgentStateRender,
|
|
154
|
-
|
|
155
|
-
|
|
161
|
+
setCoagentStatesWithRef,
|
|
162
|
+
coagentStatesRef,
|
|
156
163
|
agentSession,
|
|
157
164
|
setAgentSession,
|
|
158
165
|
threadId,
|
|
@@ -161,18 +168,11 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
161
168
|
setRunId,
|
|
162
169
|
chatAbortControllerRef,
|
|
163
170
|
} = options;
|
|
164
|
-
|
|
165
|
-
const abortController = new AbortController();
|
|
166
|
-
chatAbortControllerRef.current = abortController;
|
|
167
|
-
|
|
168
171
|
const { addGraphQLErrorsToast } = useToast();
|
|
169
|
-
|
|
170
172
|
const runChatCompletionRef = useRef<(previousMessages: Message[]) => Promise<Message[]>>();
|
|
171
|
-
// We need to keep a ref of coagent states because of renderAndWait - making sure
|
|
173
|
+
// We need to keep a ref of coagent states and session because of renderAndWait - making sure
|
|
172
174
|
// the latest state is sent to the API
|
|
173
175
|
// This is a workaround and needs to be addressed in the future
|
|
174
|
-
const coagentStatesRef = useRef<Record<string, CoagentState>>(coagentStates);
|
|
175
|
-
coagentStatesRef.current = coagentStates;
|
|
176
176
|
const agentSessionRef = useRef<AgentSession | null>(agentSession);
|
|
177
177
|
agentSessionRef.current = agentSession;
|
|
178
178
|
const threadIdRef = useRef<string | null>(threadId);
|
|
@@ -194,305 +194,371 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
194
194
|
credentials: copilotConfig.credentials,
|
|
195
195
|
});
|
|
196
196
|
|
|
197
|
-
const runChatCompletion =
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}),
|
|
243
|
-
url: window.location.href,
|
|
244
|
-
},
|
|
245
|
-
threadId: threadIdRef.current,
|
|
246
|
-
runId: runIdRef.current,
|
|
247
|
-
messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
|
|
248
|
-
...(copilotConfig.cloud
|
|
249
|
-
? {
|
|
250
|
-
cloud: {
|
|
251
|
-
...(copilotConfig.cloud.guardrails?.input?.restrictToTopic?.enabled
|
|
252
|
-
? {
|
|
253
|
-
guardrails: {
|
|
254
|
-
inputValidationRules: {
|
|
255
|
-
allowList:
|
|
256
|
-
copilotConfig.cloud.guardrails.input.restrictToTopic.validTopics,
|
|
257
|
-
denyList:
|
|
258
|
-
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
|
+
},
|
|
259
242
|
},
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
: {
|
|
266
|
-
|
|
267
|
-
|
|
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
|
+
})),
|
|
268
260
|
},
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
},
|
|
279
|
-
properties: copilotConfig.properties,
|
|
280
|
-
signal: chatAbortControllerRef.current?.signal,
|
|
281
|
-
}),
|
|
282
|
-
);
|
|
283
|
-
|
|
284
|
-
const guardrailsEnabled =
|
|
285
|
-
copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
|
|
286
|
-
|
|
287
|
-
const reader = stream.getReader();
|
|
288
|
-
|
|
289
|
-
let actionResults: { [id: string]: string } = {};
|
|
290
|
-
let executedCoAgentStateRenders: string[] = [];
|
|
291
|
-
let followUp: FrontendAction["followUp"] = undefined;
|
|
292
|
-
|
|
293
|
-
try {
|
|
294
|
-
while (true) {
|
|
295
|
-
let done, value;
|
|
296
|
-
|
|
297
|
-
try {
|
|
298
|
-
const readResult = await reader.read();
|
|
299
|
-
done = readResult.done;
|
|
300
|
-
value = readResult.value;
|
|
301
|
-
} catch (readError) {
|
|
302
|
-
break;
|
|
303
|
-
}
|
|
261
|
+
properties: copilotConfig.properties,
|
|
262
|
+
signal: chatAbortControllerRef.current?.signal,
|
|
263
|
+
}),
|
|
264
|
+
);
|
|
265
|
+
|
|
266
|
+
const guardrailsEnabled =
|
|
267
|
+
copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
|
|
268
|
+
|
|
269
|
+
const reader = stream.getReader();
|
|
304
270
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
271
|
+
let executedCoAgentStateRenders: string[] = [];
|
|
272
|
+
let followUp: FrontendAction["followUp"] = undefined;
|
|
273
|
+
|
|
274
|
+
let messages: Message[] = [];
|
|
275
|
+
let syncedMessages: Message[] = [];
|
|
276
|
+
|
|
277
|
+
try {
|
|
278
|
+
while (true) {
|
|
279
|
+
let done, value;
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
const readResult = await reader.read();
|
|
283
|
+
done = readResult.done;
|
|
284
|
+
value = readResult.value;
|
|
285
|
+
} catch (readError) {
|
|
286
|
+
break;
|
|
308
287
|
}
|
|
309
|
-
break;
|
|
310
|
-
}
|
|
311
288
|
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
289
|
+
if (done) {
|
|
290
|
+
if (chatAbortControllerRef.current.signal.aborted) {
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
315
295
|
|
|
316
|
-
|
|
317
|
-
|
|
296
|
+
if (!value?.generateCopilotResponse) {
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
318
299
|
|
|
319
|
-
|
|
320
|
-
|
|
300
|
+
threadIdRef.current = value.generateCopilotResponse.threadId || null;
|
|
301
|
+
runIdRef.current = value.generateCopilotResponse.runId || null;
|
|
321
302
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
);
|
|
303
|
+
setThreadId(threadIdRef.current);
|
|
304
|
+
setRunId(runIdRef.current);
|
|
325
305
|
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
306
|
+
messages = convertGqlOutputToMessages(
|
|
307
|
+
filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
|
|
308
|
+
);
|
|
329
309
|
|
|
330
|
-
|
|
310
|
+
if (messages.length === 0) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
331
313
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
+
}
|
|
343
398
|
}
|
|
399
|
+
const finalMessages = constructFinalMessages(syncedMessages, previousMessages, newMessages);
|
|
400
|
+
|
|
401
|
+
let didExecuteAction = false;
|
|
344
402
|
|
|
345
|
-
//
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
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];
|
|
350
409
|
if (
|
|
351
410
|
message.isActionExecutionMessage() &&
|
|
352
|
-
message.status.code !== MessageStatusCode.Pending
|
|
353
|
-
message.scope === "client" &&
|
|
354
|
-
onFunctionCall
|
|
411
|
+
message.status.code !== MessageStatusCode.Pending
|
|
355
412
|
) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
413
|
+
lastMessages.unshift(message);
|
|
414
|
+
} else {
|
|
415
|
+
break;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
|
|
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);
|
|
423
|
+
|
|
424
|
+
const action = actions.find((action) => action.name === message.name);
|
|
425
|
+
|
|
426
|
+
if (action) {
|
|
427
|
+
followUp = action.followUp;
|
|
428
|
+
let result: any;
|
|
429
|
+
try {
|
|
430
|
+
result = await Promise.race([
|
|
431
|
+
onFunctionCall({
|
|
432
|
+
messages: previousMessages,
|
|
433
|
+
name: message.name,
|
|
434
|
+
args: message.arguments,
|
|
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}`);
|
|
390
451
|
}
|
|
391
|
-
|
|
392
|
-
|
|
452
|
+
didExecuteAction = true;
|
|
453
|
+
const messageIndex = finalMessages.findIndex((msg) => msg.id === message.id);
|
|
454
|
+
finalMessages.splice(
|
|
455
|
+
messageIndex + 1,
|
|
456
|
+
0,
|
|
393
457
|
new ResultMessage({
|
|
394
|
-
|
|
458
|
+
id: "result-" + message.id,
|
|
459
|
+
result: ResultMessage.encodeResult(result),
|
|
395
460
|
actionExecutionId: message.id,
|
|
396
461
|
actionName: message.name,
|
|
397
462
|
}),
|
|
398
463
|
);
|
|
399
464
|
}
|
|
400
|
-
// execute coagent actions
|
|
401
|
-
if (
|
|
402
|
-
message.isAgentStateMessage() &&
|
|
403
|
-
!message.active &&
|
|
404
|
-
!executedCoAgentStateRenders.includes(message.id) &&
|
|
405
|
-
onCoAgentStateRender
|
|
406
|
-
) {
|
|
407
|
-
// Do not execute a coagent action if guardrails are enabled but the status is not known
|
|
408
|
-
if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
|
|
409
|
-
break;
|
|
410
|
-
}
|
|
411
|
-
// execute coagent action
|
|
412
|
-
await onCoAgentStateRender({
|
|
413
|
-
name: message.agentName,
|
|
414
|
-
nodeName: message.nodeName,
|
|
415
|
-
state: message.state,
|
|
416
|
-
});
|
|
417
|
-
executedCoAgentStateRenders.push(message.id);
|
|
418
|
-
}
|
|
419
465
|
}
|
|
420
466
|
|
|
421
|
-
|
|
422
|
-
.reverse()
|
|
423
|
-
.find((message) => message.isAgentStateMessage());
|
|
424
|
-
|
|
425
|
-
if (lastAgentStateMessage) {
|
|
426
|
-
setCoagentStates((prevAgentStates) => ({
|
|
427
|
-
...prevAgentStates,
|
|
428
|
-
[lastAgentStateMessage.agentName]: {
|
|
429
|
-
name: lastAgentStateMessage.agentName,
|
|
430
|
-
state: lastAgentStateMessage.state,
|
|
431
|
-
running: lastAgentStateMessage.running,
|
|
432
|
-
active: lastAgentStateMessage.active,
|
|
433
|
-
threadId: lastAgentStateMessage.threadId,
|
|
434
|
-
nodeName: lastAgentStateMessage.nodeName,
|
|
435
|
-
runId: lastAgentStateMessage.runId,
|
|
436
|
-
},
|
|
437
|
-
}));
|
|
438
|
-
if (lastAgentStateMessage.running) {
|
|
439
|
-
setAgentSession({
|
|
440
|
-
threadId: lastAgentStateMessage.threadId,
|
|
441
|
-
agentName: lastAgentStateMessage.agentName,
|
|
442
|
-
nodeName: lastAgentStateMessage.nodeName,
|
|
443
|
-
});
|
|
444
|
-
} else {
|
|
445
|
-
setAgentSession(null);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
467
|
+
setMessages(finalMessages);
|
|
448
468
|
}
|
|
449
469
|
|
|
450
|
-
if (
|
|
451
|
-
//
|
|
452
|
-
|
|
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();
|
|
453
516
|
}
|
|
517
|
+
} finally {
|
|
518
|
+
setIsLoading(false);
|
|
454
519
|
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
}
|
|
474
|
-
} finally {
|
|
475
|
-
setIsLoading(false);
|
|
476
|
-
}
|
|
477
|
-
};
|
|
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
|
+
);
|
|
478
538
|
|
|
479
539
|
runChatCompletionRef.current = runChatCompletion;
|
|
480
540
|
|
|
481
|
-
const runChatCompletionAndHandleFunctionCall =
|
|
482
|
-
|
|
483
|
-
|
|
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
|
+
}
|
|
484
553
|
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
554
|
+
const newMessages = [...messages, message];
|
|
555
|
+
setMessages(newMessages);
|
|
556
|
+
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
557
|
+
},
|
|
558
|
+
[isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],
|
|
559
|
+
);
|
|
489
560
|
|
|
490
|
-
|
|
491
|
-
setMessages(newMessages);
|
|
492
|
-
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
493
|
-
};
|
|
494
|
-
|
|
495
|
-
const reload = async (): Promise<void> => {
|
|
561
|
+
const reload = useAsyncCallback(async (): Promise<void> => {
|
|
496
562
|
if (isLoading || messages.length === 0) {
|
|
497
563
|
return;
|
|
498
564
|
}
|
|
@@ -506,7 +572,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
506
572
|
setMessages(newMessages);
|
|
507
573
|
|
|
508
574
|
return runChatCompletionAndHandleFunctionCall(newMessages);
|
|
509
|
-
};
|
|
575
|
+
}, [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall]);
|
|
510
576
|
|
|
511
577
|
const stop = (): void => {
|
|
512
578
|
chatAbortControllerRef.current?.abort("Stop was called");
|
|
@@ -516,5 +582,35 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
|
|
|
516
582
|
append,
|
|
517
583
|
reload,
|
|
518
584
|
stop,
|
|
585
|
+
runChatCompletion: () => runChatCompletionRef.current!(messages),
|
|
519
586
|
};
|
|
520
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
|
+
}
|