@copilotkit/react-core 1.4.8-next.2 → 1.4.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/CHANGELOG.md +8 -13
  2. package/dist/{chunk-DIX6ISOB.mjs → chunk-6EMLM6WX.mjs} +20 -19
  3. package/dist/chunk-6EMLM6WX.mjs.map +1 -0
  4. package/dist/{chunk-ODN4H66E.mjs → chunk-7LRDVJH5.mjs} +6 -2
  5. package/dist/chunk-7LRDVJH5.mjs.map +1 -0
  6. package/dist/{chunk-XXCJFOLY.mjs → chunk-AG7FH7OD.mjs} +2 -2
  7. package/dist/{chunk-XYFTGCMS.mjs → chunk-FSC4A3JN.mjs} +18 -14
  8. package/dist/chunk-FSC4A3JN.mjs.map +1 -0
  9. package/dist/{chunk-E3HHCHMQ.mjs → chunk-IFTHM7LF.mjs} +7 -10
  10. package/dist/chunk-IFTHM7LF.mjs.map +1 -0
  11. package/dist/{chunk-V6CEKRZA.mjs → chunk-IVYL7JRC.mjs} +12 -11
  12. package/dist/chunk-IVYL7JRC.mjs.map +1 -0
  13. package/dist/chunk-NTLCOVE5.mjs +321 -0
  14. package/dist/chunk-NTLCOVE5.mjs.map +1 -0
  15. package/dist/chunk-QCUP6HLK.mjs +37 -0
  16. package/dist/chunk-QCUP6HLK.mjs.map +1 -0
  17. package/dist/{chunk-2KCEHGSI.mjs → chunk-SFPANIOY.mjs} +99 -49
  18. package/dist/chunk-SFPANIOY.mjs.map +1 -0
  19. package/dist/{chunk-CBMCK7UC.mjs → chunk-UOVONDR6.mjs} +2 -2
  20. package/dist/{chunk-XSORW54K.mjs → chunk-X6ZF5WAX.mjs} +2 -2
  21. package/dist/{chunk-4P56GAFP.mjs → chunk-XQFVXX6R.mjs} +2 -3
  22. package/dist/chunk-XQFVXX6R.mjs.map +1 -0
  23. package/dist/{chunk-ETCKRNXQ.mjs → chunk-YUY5ZAST.mjs} +7 -4
  24. package/dist/chunk-YUY5ZAST.mjs.map +1 -0
  25. package/dist/components/copilot-provider/copilot-messages.d.ts +0 -1
  26. package/dist/components/copilot-provider/copilotkit-props.d.ts +0 -5
  27. package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
  28. package/dist/components/copilot-provider/copilotkit.d.ts +0 -1
  29. package/dist/components/copilot-provider/copilotkit.js +158 -95
  30. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  31. package/dist/components/copilot-provider/copilotkit.mjs +5 -4
  32. package/dist/components/copilot-provider/index.d.ts +0 -1
  33. package/dist/components/copilot-provider/index.js +158 -95
  34. package/dist/components/copilot-provider/index.js.map +1 -1
  35. package/dist/components/copilot-provider/index.mjs +5 -4
  36. package/dist/components/error-boundary/error-boundary.d.ts +22 -0
  37. package/dist/components/error-boundary/error-boundary.js +183 -0
  38. package/dist/components/error-boundary/error-boundary.js.map +1 -0
  39. package/dist/components/error-boundary/error-boundary.mjs +12 -0
  40. package/dist/components/error-boundary/error-boundary.mjs.map +1 -0
  41. package/dist/components/error-boundary/error-utils.d.ts +11 -0
  42. package/dist/components/error-boundary/error-utils.js +177 -0
  43. package/dist/components/error-boundary/error-utils.js.map +1 -0
  44. package/dist/components/error-boundary/error-utils.mjs +13 -0
  45. package/dist/components/error-boundary/error-utils.mjs.map +1 -0
  46. package/dist/components/index.d.ts +0 -1
  47. package/dist/components/index.js +158 -95
  48. package/dist/components/index.js.map +1 -1
  49. package/dist/components/index.mjs +5 -4
  50. package/dist/components/toast/toast-provider.d.ts +2 -1
  51. package/dist/components/toast/toast-provider.js +76 -62
  52. package/dist/components/toast/toast-provider.js.map +1 -1
  53. package/dist/components/toast/toast-provider.mjs +1 -1
  54. package/dist/context/copilot-context.d.ts +1 -5
  55. package/dist/context/copilot-context.js +1 -2
  56. package/dist/context/copilot-context.js.map +1 -1
  57. package/dist/context/copilot-context.mjs +1 -1
  58. package/dist/context/index.js +1 -2
  59. package/dist/context/index.js.map +1 -1
  60. package/dist/context/index.mjs +1 -1
  61. package/dist/hooks/index.js +401 -260
  62. package/dist/hooks/index.js.map +1 -1
  63. package/dist/hooks/index.mjs +19 -18
  64. package/dist/hooks/use-chat.d.ts +1 -2
  65. package/dist/hooks/use-chat.js +343 -200
  66. package/dist/hooks/use-chat.js.map +1 -1
  67. package/dist/hooks/use-chat.mjs +3 -3
  68. package/dist/hooks/use-coagent-state-render.js +1 -2
  69. package/dist/hooks/use-coagent-state-render.js.map +1 -1
  70. package/dist/hooks/use-coagent-state-render.mjs +2 -2
  71. package/dist/hooks/use-coagent.js +381 -240
  72. package/dist/hooks/use-coagent.js.map +1 -1
  73. package/dist/hooks/use-coagent.mjs +9 -8
  74. package/dist/hooks/use-copilot-action.js +133 -9
  75. package/dist/hooks/use-copilot-action.js.map +1 -1
  76. package/dist/hooks/use-copilot-action.mjs +4 -2
  77. package/dist/hooks/use-copilot-chat.js +370 -230
  78. package/dist/hooks/use-copilot-chat.js.map +1 -1
  79. package/dist/hooks/use-copilot-chat.mjs +8 -7
  80. package/dist/hooks/use-copilot-readable.js +1 -2
  81. package/dist/hooks/use-copilot-readable.js.map +1 -1
  82. package/dist/hooks/use-copilot-readable.mjs +2 -2
  83. package/dist/hooks/use-copilot-runtime-client.js +110 -4
  84. package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
  85. package/dist/hooks/use-copilot-runtime-client.mjs +2 -2
  86. package/dist/hooks/use-make-copilot-document-readable.js +1 -2
  87. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  88. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  89. package/dist/index.d.ts +1 -1
  90. package/dist/index.js +450 -353
  91. package/dist/index.js.map +1 -1
  92. package/dist/index.mjs +20 -19
  93. package/dist/lib/copilot-task.d.ts +1 -6
  94. package/dist/lib/copilot-task.js +4 -22
  95. package/dist/lib/copilot-task.js.map +1 -1
  96. package/dist/lib/copilot-task.mjs +6 -5
  97. package/dist/lib/index.d.ts +1 -1
  98. package/dist/lib/index.js +4 -22
  99. package/dist/lib/index.js.map +1 -1
  100. package/dist/lib/index.mjs +6 -5
  101. package/dist/utils/extract.d.ts +2 -3
  102. package/dist/utils/extract.js +3 -21
  103. package/dist/utils/extract.js.map +1 -1
  104. package/dist/utils/extract.mjs +5 -4
  105. package/dist/utils/index.js +3 -21
  106. package/dist/utils/index.js.map +1 -1
  107. package/dist/utils/index.mjs +5 -4
  108. package/package.json +3 -3
  109. package/src/components/copilot-provider/copilotkit-props.tsx +0 -6
  110. package/src/components/copilot-provider/copilotkit.tsx +4 -2
  111. package/src/components/error-boundary/error-boundary.tsx +42 -0
  112. package/src/components/error-boundary/error-utils.tsx +95 -0
  113. package/src/components/toast/toast-provider.tsx +10 -49
  114. package/src/context/copilot-context.tsx +1 -8
  115. package/src/hooks/use-chat.ts +286 -266
  116. package/src/hooks/use-coagent.ts +14 -11
  117. package/src/hooks/use-copilot-action.ts +3 -2
  118. package/src/hooks/use-copilot-chat.ts +9 -10
  119. package/src/hooks/use-copilot-runtime-client.ts +4 -0
  120. package/src/lib/copilot-task.ts +2 -10
  121. package/src/utils/extract.ts +0 -4
  122. package/dist/chunk-2KCEHGSI.mjs.map +0 -1
  123. package/dist/chunk-4P56GAFP.mjs.map +0 -1
  124. package/dist/chunk-DIX6ISOB.mjs.map +0 -1
  125. package/dist/chunk-E3HHCHMQ.mjs.map +0 -1
  126. package/dist/chunk-ETCKRNXQ.mjs.map +0 -1
  127. package/dist/chunk-ODN4H66E.mjs.map +0 -1
  128. package/dist/chunk-PG5XEJVS.mjs +0 -295
  129. package/dist/chunk-PG5XEJVS.mjs.map +0 -1
  130. package/dist/chunk-V6CEKRZA.mjs.map +0 -1
  131. package/dist/chunk-XYFTGCMS.mjs.map +0 -1
  132. /package/dist/{chunk-XXCJFOLY.mjs.map → chunk-AG7FH7OD.mjs.map} +0 -0
  133. /package/dist/{chunk-CBMCK7UC.mjs.map → chunk-UOVONDR6.mjs.map} +0 -0
  134. /package/dist/{chunk-XSORW54K.mjs.map → chunk-X6ZF5WAX.mjs.map} +0 -0
@@ -18,7 +18,6 @@ import {
18
18
  Role,
19
19
  CopilotRequestType,
20
20
  ActionInputAvailability,
21
- ForwardedParametersInput,
22
21
  } from "@copilotkit/runtime-client-gql";
23
22
 
24
23
  import { CopilotApiConfig } from "../context";
@@ -27,6 +26,7 @@ import { CoagentState } from "../types/coagent-state";
27
26
  import { AgentSession } from "../context/copilot-context";
28
27
  import { useToast } from "../components/toast/toast-provider";
29
28
  import { useCopilotRuntimeClient } from "./use-copilot-runtime-client";
29
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
30
30
 
31
31
  export type UseChatOptions = {
32
32
  /**
@@ -98,11 +98,6 @@ export type UseChatOptions = {
98
98
  * setState-powered method to update the agent session
99
99
  */
100
100
  setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;
101
-
102
- /*
103
- * This is forwarded to LLM as a parameter.
104
- */
105
- forwardedParameters?: Pick<ForwardedParametersInput, "temperature">;
106
101
  };
107
102
 
108
103
  export type UseChatHelpers = {
@@ -173,293 +168,318 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
173
168
  credentials: copilotConfig.credentials,
174
169
  });
175
170
 
176
- const runChatCompletion = async (previousMessages: Message[]): Promise<Message[]> => {
177
- setIsLoading(true);
178
-
179
- // this message is just a placeholder. It will disappear once the first real message
180
- // is received
181
- let newMessages: Message[] = [
182
- new TextMessage({
183
- content: "",
184
- role: Role.Assistant,
185
- }),
186
- ];
187
- const abortController = new AbortController();
188
- abortControllerRef.current = abortController;
189
-
190
- setMessages([...previousMessages, ...newMessages]);
191
-
192
- const systemMessage = makeSystemMessageCallback();
193
-
194
- const messagesWithContext = [systemMessage, ...(initialMessages || []), ...previousMessages];
195
-
196
- const stream = runtimeClient.asStream(
197
- runtimeClient.generateCopilotResponse({
198
- data: {
199
- frontend: {
200
- actions: actions
201
- .filter(
202
- (action) =>
203
- action.available !== ActionInputAvailability.Disabled || !action.disabled,
204
- )
205
- .map((action) => {
206
- let available: ActionInputAvailability | undefined =
207
- ActionInputAvailability.Enabled;
208
- if (action.disabled) {
209
- available = ActionInputAvailability.Disabled;
210
- } else if (action.available === "disabled") {
211
- available = ActionInputAvailability.Disabled;
212
- } else if (action.available === "remote") {
213
- available = ActionInputAvailability.Remote;
214
- }
215
- return {
216
- name: action.name,
217
- description: action.description || "",
218
- jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters || [])),
219
- available,
220
- };
221
- }),
222
- url: window.location.href,
223
- },
224
- threadId: threadIdRef.current,
225
- runId: runIdRef.current,
226
- messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
227
- ...(copilotConfig.cloud
228
- ? {
229
- cloud: {
230
- ...(copilotConfig.cloud.guardrails?.input?.restrictToTopic?.enabled
231
- ? {
232
- guardrails: {
233
- inputValidationRules: {
234
- allowList:
235
- copilotConfig.cloud.guardrails.input.restrictToTopic.validTopics,
236
- denyList:
237
- copilotConfig.cloud.guardrails.input.restrictToTopic.invalidTopics,
171
+ const runChatCompletion = useAsyncCallback(
172
+ async (previousMessages: Message[]): Promise<Message[]> => {
173
+ setIsLoading(true);
174
+
175
+ // this message is just a placeholder. It will disappear once the first real message
176
+ // is received
177
+ let newMessages: Message[] = [
178
+ new TextMessage({
179
+ content: "",
180
+ role: Role.Assistant,
181
+ }),
182
+ ];
183
+ const abortController = new AbortController();
184
+ abortControllerRef.current = abortController;
185
+
186
+ setMessages([...previousMessages, ...newMessages]);
187
+
188
+ const systemMessage = makeSystemMessageCallback();
189
+
190
+ const messagesWithContext = [systemMessage, ...(initialMessages || []), ...previousMessages];
191
+
192
+ const stream = runtimeClient.asStream(
193
+ runtimeClient.generateCopilotResponse({
194
+ data: {
195
+ frontend: {
196
+ actions: actions
197
+ .filter(
198
+ (action) =>
199
+ action.available !== ActionInputAvailability.Disabled || !action.disabled,
200
+ )
201
+ .map((action) => {
202
+ let available: ActionInputAvailability | undefined =
203
+ ActionInputAvailability.Enabled;
204
+ if (action.disabled) {
205
+ available = ActionInputAvailability.Disabled;
206
+ } else if (action.available === "disabled") {
207
+ available = ActionInputAvailability.Disabled;
208
+ } else if (action.available === "remote") {
209
+ available = ActionInputAvailability.Remote;
210
+ }
211
+ return {
212
+ name: action.name,
213
+ description: action.description || "",
214
+ jsonSchema: JSON.stringify(
215
+ actionParametersToJsonSchema(action.parameters || []),
216
+ ),
217
+ available,
218
+ };
219
+ }),
220
+ url: window.location.href,
221
+ },
222
+ threadId: threadIdRef.current,
223
+ runId: runIdRef.current,
224
+ messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
225
+ ...(copilotConfig.cloud
226
+ ? {
227
+ cloud: {
228
+ ...(copilotConfig.cloud.guardrails?.input?.restrictToTopic?.enabled
229
+ ? {
230
+ guardrails: {
231
+ inputValidationRules: {
232
+ allowList:
233
+ copilotConfig.cloud.guardrails.input.restrictToTopic.validTopics,
234
+ denyList:
235
+ copilotConfig.cloud.guardrails.input.restrictToTopic.invalidTopics,
236
+ },
238
237
  },
239
- },
240
- }
241
- : {}),
242
- },
243
- }
244
- : {}),
245
- metadata: {
246
- requestType: CopilotRequestType.Chat,
238
+ }
239
+ : {}),
240
+ },
241
+ }
242
+ : {}),
243
+ metadata: {
244
+ requestType: CopilotRequestType.Chat,
245
+ },
246
+ ...(agentSessionRef.current
247
+ ? {
248
+ agentSession: agentSessionRef.current,
249
+ }
250
+ : {}),
251
+ agentStates: Object.values(coagentStatesRef.current!).map((state) => ({
252
+ agentName: state.name,
253
+ state: JSON.stringify(state.state),
254
+ })),
247
255
  },
248
- ...(agentSessionRef.current
249
- ? {
250
- agentSession: agentSessionRef.current,
251
- }
252
- : {}),
253
- agentStates: Object.values(coagentStatesRef.current!).map((state) => ({
254
- agentName: state.name,
255
- state: JSON.stringify(state.state),
256
- })),
257
- forwardedParameters: options.forwardedParameters || {},
258
- },
259
- properties: copilotConfig.properties,
260
- signal: abortControllerRef.current?.signal,
261
- }),
262
- );
263
-
264
- const guardrailsEnabled =
265
- copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
266
-
267
- const reader = stream.getReader();
268
-
269
- let actionResults: { [id: string]: string } = {};
270
- let executedCoAgentStateRenders: string[] = [];
271
- let followUp: FrontendAction["followUp"] = undefined;
272
-
273
- try {
274
- while (true) {
275
- let done, value;
276
-
277
- try {
278
- const readResult = await reader.read();
279
- done = readResult.done;
280
- value = readResult.value;
281
- } catch (readError) {
282
- break;
283
- }
284
-
285
- if (done) {
286
- break;
287
- }
256
+ properties: copilotConfig.properties,
257
+ signal: abortControllerRef.current?.signal,
258
+ }),
259
+ );
260
+
261
+ const guardrailsEnabled =
262
+ copilotConfig.cloud?.guardrails?.input?.restrictToTopic.enabled || false;
263
+
264
+ const reader = stream.getReader();
265
+
266
+ let actionResults: { [id: string]: string } = {};
267
+ let executedCoAgentStateRenders: string[] = [];
268
+ let followUp: FrontendAction["followUp"] = undefined;
269
+
270
+ try {
271
+ while (true) {
272
+ let done, value;
273
+
274
+ try {
275
+ const readResult = await reader.read();
276
+ done = readResult.done;
277
+ value = readResult.value;
278
+ } catch (readError) {
279
+ break;
280
+ }
288
281
 
289
- if (!value?.generateCopilotResponse) {
290
- continue;
291
- }
282
+ if (done) {
283
+ break;
284
+ }
292
285
 
293
- threadIdRef.current = value.generateCopilotResponse.threadId || null;
294
- runIdRef.current = value.generateCopilotResponse.runId || null;
286
+ if (!value?.generateCopilotResponse) {
287
+ continue;
288
+ }
295
289
 
296
- const messages = convertGqlOutputToMessages(
297
- filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
298
- );
290
+ threadIdRef.current = value.generateCopilotResponse.threadId || null;
291
+ runIdRef.current = value.generateCopilotResponse.runId || null;
299
292
 
300
- if (messages.length === 0) {
301
- continue;
302
- }
293
+ const messages = convertGqlOutputToMessages(
294
+ filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
295
+ );
303
296
 
304
- newMessages = [];
297
+ if (messages.length === 0) {
298
+ continue;
299
+ }
305
300
 
306
- // request failed, display error message
307
- if (
308
- value.generateCopilotResponse.status?.__typename === "FailedResponseStatus" &&
309
- value.generateCopilotResponse.status.reason === "GUARDRAILS_VALIDATION_FAILED"
310
- ) {
311
- newMessages = [
312
- new TextMessage({
313
- role: MessageRole.Assistant,
314
- content: value.generateCopilotResponse.status.details?.guardrailsReason || "",
315
- }),
316
- ];
317
- }
301
+ newMessages = [];
302
+
303
+ // request failed, display error message
304
+ if (
305
+ value.generateCopilotResponse.status?.__typename === "FailedResponseStatus" &&
306
+ value.generateCopilotResponse.status.reason === "GUARDRAILS_VALIDATION_FAILED"
307
+ ) {
308
+ newMessages = [
309
+ new TextMessage({
310
+ role: MessageRole.Assistant,
311
+ content: value.generateCopilotResponse.status.details?.guardrailsReason || "",
312
+ }),
313
+ ];
314
+ }
318
315
 
319
- // add messages to the chat
320
- else {
321
- for (const message of messages) {
322
- newMessages.push(message);
323
- // execute regular action executions
324
- if (
325
- message.isActionExecutionMessage() &&
326
- message.status.code !== MessageStatusCode.Pending &&
327
- message.scope === "client" &&
328
- onFunctionCall
329
- ) {
330
- if (!(message.id in actionResults)) {
331
- // Do not execute a function call if guardrails are enabled but the status is not known
316
+ // add messages to the chat
317
+ else {
318
+ for (const message of messages) {
319
+ newMessages.push(message);
320
+ // execute regular action executions
321
+ if (
322
+ message.isActionExecutionMessage() &&
323
+ message.status.code !== MessageStatusCode.Pending &&
324
+ message.scope === "client" &&
325
+ onFunctionCall
326
+ ) {
327
+ if (!(message.id in actionResults)) {
328
+ // Do not execute a function call if guardrails are enabled but the status is not known
329
+ if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
330
+ break;
331
+ }
332
+ // execute action
333
+ try {
334
+ // We update the message state before calling the handler so that the render
335
+ // function can be called with `executing` state
336
+ setMessages([...previousMessages, ...newMessages]);
337
+
338
+ const action = actions.find((action) => action.name === message.name);
339
+
340
+ if (action) {
341
+ followUp = action.followUp;
342
+ }
343
+
344
+ const result = await onFunctionCall({
345
+ messages: previousMessages,
346
+ name: message.name,
347
+ args: message.arguments,
348
+ });
349
+ actionResults[message.id] = result;
350
+ } catch (e) {
351
+ actionResults[message.id] = `Failed to execute action ${message.name}`;
352
+ console.error(`Failed to execute action ${message.name}: ${e}`);
353
+ }
354
+ }
355
+ // add the result message
356
+ newMessages.push(
357
+ new ResultMessage({
358
+ result: ResultMessage.encodeResult(actionResults[message.id]),
359
+ actionExecutionId: message.id,
360
+ actionName: message.name,
361
+ }),
362
+ );
363
+ }
364
+ // execute coagent actions
365
+ if (
366
+ message.isAgentStateMessage() &&
367
+ !message.active &&
368
+ !executedCoAgentStateRenders.includes(message.id) &&
369
+ onCoAgentStateRender
370
+ ) {
371
+ // Do not execute a coagent action if guardrails are enabled but the status is not known
332
372
  if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
333
373
  break;
334
374
  }
335
- // execute action
336
- try {
337
- // We update the message state before calling the handler so that the render
338
- // function can be called with `executing` state
339
- setMessages([...previousMessages, ...newMessages]);
340
-
341
- const action = actions.find((action) => action.name === message.name);
342
-
343
- if (action) {
344
- followUp = action.followUp;
345
- }
346
-
347
- const result = await onFunctionCall({
348
- messages: previousMessages,
349
- name: message.name,
350
- args: message.arguments,
351
- });
352
- actionResults[message.id] = result;
353
- } catch (e) {
354
- actionResults[message.id] = `Failed to execute action ${message.name}`;
355
- console.error(`Failed to execute action ${message.name}: ${e}`);
356
- }
375
+ // execute coagent action
376
+ await onCoAgentStateRender({
377
+ name: message.agentName,
378
+ nodeName: message.nodeName,
379
+ state: message.state,
380
+ });
381
+ executedCoAgentStateRenders.push(message.id);
357
382
  }
358
- // add the result message
359
- newMessages.push(
360
- new ResultMessage({
361
- result: ResultMessage.encodeResult(actionResults[message.id]),
362
- actionExecutionId: message.id,
363
- actionName: message.name,
364
- }),
365
- );
366
383
  }
367
- // execute coagent actions
368
- if (
369
- message.isAgentStateMessage() &&
370
- !message.active &&
371
- !executedCoAgentStateRenders.includes(message.id) &&
372
- onCoAgentStateRender
373
- ) {
374
- // Do not execute a coagent action if guardrails are enabled but the status is not known
375
- if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
376
- break;
384
+
385
+ const lastAgentStateMessage = [...messages]
386
+ .reverse()
387
+ .find((message) => message.isAgentStateMessage());
388
+
389
+ if (lastAgentStateMessage) {
390
+ setCoagentStatesWithRef((prevAgentStates) => ({
391
+ ...prevAgentStates,
392
+ [lastAgentStateMessage.agentName]: {
393
+ name: lastAgentStateMessage.agentName,
394
+ state: lastAgentStateMessage.state,
395
+ running: lastAgentStateMessage.running,
396
+ active: lastAgentStateMessage.active,
397
+ threadId: lastAgentStateMessage.threadId,
398
+ nodeName: lastAgentStateMessage.nodeName,
399
+ runId: lastAgentStateMessage.runId,
400
+ },
401
+ }));
402
+ if (lastAgentStateMessage.running) {
403
+ setAgentSession({
404
+ threadId: lastAgentStateMessage.threadId,
405
+ agentName: lastAgentStateMessage.agentName,
406
+ nodeName: lastAgentStateMessage.nodeName,
407
+ });
408
+ } else {
409
+ setAgentSession(null);
377
410
  }
378
- // execute coagent action
379
- await onCoAgentStateRender({
380
- name: message.agentName,
381
- nodeName: message.nodeName,
382
- state: message.state,
383
- });
384
- executedCoAgentStateRenders.push(message.id);
385
411
  }
386
412
  }
387
413
 
388
- const lastAgentStateMessage = [...messages]
389
- .reverse()
390
- .find((message) => message.isAgentStateMessage());
391
-
392
- if (lastAgentStateMessage) {
393
- setCoagentStatesWithRef((prevAgentStates) => ({
394
- ...prevAgentStates,
395
- [lastAgentStateMessage.agentName]: {
396
- name: lastAgentStateMessage.agentName,
397
- state: lastAgentStateMessage.state,
398
- running: lastAgentStateMessage.running,
399
- active: lastAgentStateMessage.active,
400
- threadId: lastAgentStateMessage.threadId,
401
- nodeName: lastAgentStateMessage.nodeName,
402
- runId: lastAgentStateMessage.runId,
403
- },
404
- }));
405
- if (lastAgentStateMessage.running) {
406
- setAgentSession({
407
- threadId: lastAgentStateMessage.threadId,
408
- agentName: lastAgentStateMessage.agentName,
409
- nodeName: lastAgentStateMessage.nodeName,
410
- });
411
- } else {
412
- setAgentSession(null);
413
- }
414
+ if (newMessages.length > 0) {
415
+ // Update message state
416
+ setMessages([...previousMessages, ...newMessages]);
414
417
  }
415
418
  }
416
419
 
417
- if (newMessages.length > 0) {
418
- // Update message state
419
- setMessages([...previousMessages, ...newMessages]);
420
- }
421
- }
420
+ if (
421
+ // if followUp is not explicitly false
422
+ followUp !== false &&
423
+ // if we have client side results
424
+ (Object.values(actionResults).length ||
425
+ // or the last message we received is a result
426
+ (newMessages.length && newMessages[newMessages.length - 1].isResultMessage()))
427
+ ) {
428
+ // run the completion again and return the result
429
+
430
+ // wait for next tick to make sure all the react state updates
431
+ // - tried using react-dom's flushSync, but it did not work
432
+ await new Promise((resolve) => setTimeout(resolve, 10));
422
433
 
423
- if (
424
- // if followUp is not explicitly false
425
- followUp !== false &&
426
- // if we have client side results
427
- (Object.values(actionResults).length ||
428
- // or the last message we received is a result
429
- (newMessages.length && newMessages[newMessages.length - 1].isResultMessage()))
430
- ) {
431
- // run the completion again and return the result
432
-
433
- // wait for next tick to make sure all the react state updates
434
- // - tried using react-dom's flushSync, but it did not work
435
- await new Promise((resolve) => setTimeout(resolve, 10));
436
-
437
- return await runChatCompletionRef.current!([...previousMessages, ...newMessages]);
438
- } else {
439
- return newMessages.slice();
434
+ return await runChatCompletionRef.current!([...previousMessages, ...newMessages]);
435
+ } else {
436
+ return newMessages.slice();
437
+ }
438
+ } finally {
439
+ setIsLoading(false);
440
440
  }
441
- } finally {
442
- setIsLoading(false);
443
- }
444
- };
441
+ },
442
+ [
443
+ messages,
444
+ setMessages,
445
+ makeSystemMessageCallback,
446
+ copilotConfig,
447
+ setIsLoading,
448
+ initialMessages,
449
+ isLoading,
450
+ actions,
451
+ onFunctionCall,
452
+ onCoAgentStateRender,
453
+ setCoagentStatesWithRef,
454
+ coagentStatesRef,
455
+ agentSession,
456
+ setAgentSession,
457
+ ],
458
+ );
445
459
 
446
460
  runChatCompletionRef.current = runChatCompletion;
447
461
 
448
- const runChatCompletionAndHandleFunctionCall = async (messages: Message[]): Promise<void> => {
449
- await runChatCompletionRef.current!(messages);
450
- };
451
-
452
- const append = async (message: Message): Promise<void> => {
453
- if (isLoading) {
454
- return;
455
- }
462
+ const runChatCompletionAndHandleFunctionCall = useAsyncCallback(
463
+ async (messages: Message[]): Promise<void> => {
464
+ await runChatCompletionRef.current!(messages);
465
+ },
466
+ [messages],
467
+ );
468
+
469
+ const append = useAsyncCallback(
470
+ async (message: Message): Promise<void> => {
471
+ if (isLoading) {
472
+ return;
473
+ }
456
474
 
457
- const newMessages = [...messages, message];
458
- setMessages(newMessages);
459
- return runChatCompletionAndHandleFunctionCall(newMessages);
460
- };
475
+ const newMessages = [...messages, message];
476
+ setMessages(newMessages);
477
+ return runChatCompletionAndHandleFunctionCall(newMessages);
478
+ },
479
+ [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],
480
+ );
461
481
 
462
- const reload = async (): Promise<void> => {
482
+ const reload = useAsyncCallback(async (): Promise<void> => {
463
483
  if (isLoading || messages.length === 0) {
464
484
  return;
465
485
  }
@@ -473,7 +493,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
473
493
  setMessages(newMessages);
474
494
 
475
495
  return runChatCompletionAndHandleFunctionCall(newMessages);
476
- };
496
+ }, [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall]);
477
497
 
478
498
  const stop = (): void => {
479
499
  abortControllerRef.current?.abort();
@@ -99,6 +99,7 @@ import { CoagentState } from "../types/coagent-state";
99
99
  import { useCopilotChat } from "./use-copilot-chat";
100
100
  import { Message } from "@copilotkit/runtime-client-gql";
101
101
  import { flushSync } from "react-dom";
102
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
102
103
 
103
104
  interface WithInternalStateManagementAndInitial<T> {
104
105
  /**
@@ -266,22 +267,24 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
266
267
  }
267
268
  }, [isExternalStateManagement(options) ? JSON.stringify(options.state) : undefined]);
268
269
 
270
+ const runAgentCallback = useAsyncCallback(
271
+ async (hint?: HintFunction) => {
272
+ await runAgent(name, context, appendMessage, runChatCompletion, hint);
273
+ },
274
+ [name, context, appendMessage, runChatCompletion],
275
+ );
276
+
269
277
  // Return the state and setState function
270
278
  return {
271
279
  name,
272
280
  nodeName: coagentState.nodeName,
273
- state,
274
- setState,
281
+ threadId: coagentState.threadId,
275
282
  running: coagentState.running,
276
- start: () => {
277
- startAgent(name, context);
278
- },
279
- stop: () => {
280
- stopAgent(name, context);
281
- },
282
- run: (hint?: HintFunction) => {
283
- return runAgent(name, context, appendMessage, runChatCompletion, hint);
284
- },
283
+ state: coagentState.state,
284
+ setState: isExternalStateManagement(options) ? options.setState : setState,
285
+ start: () => startAgent(name, context),
286
+ stop: () => stopAgent(name, context),
287
+ run: runAgentCallback,
285
288
  };
286
289
  }
287
290