@copilotkit/react-core 1.4.8-no-pino-redact.1 → 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 (95) hide show
  1. package/CHANGELOG.md +8 -3
  2. package/dist/{chunk-XBVKTDXP.mjs → chunk-6EMLM6WX.mjs} +17 -14
  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-O22KGHOQ.mjs → chunk-FSC4A3JN.mjs} +17 -13
  7. package/dist/chunk-FSC4A3JN.mjs.map +1 -0
  8. package/dist/{chunk-OT67R4NB.mjs → chunk-IFTHM7LF.mjs} +2 -2
  9. package/dist/{chunk-DHGXL5PC.mjs → chunk-IVYL7JRC.mjs} +7 -4
  10. package/dist/chunk-IVYL7JRC.mjs.map +1 -0
  11. package/dist/chunk-NTLCOVE5.mjs +321 -0
  12. package/dist/chunk-NTLCOVE5.mjs.map +1 -0
  13. package/dist/chunk-QCUP6HLK.mjs +37 -0
  14. package/dist/chunk-QCUP6HLK.mjs.map +1 -0
  15. package/dist/{chunk-2KCEHGSI.mjs → chunk-SFPANIOY.mjs} +99 -49
  16. package/dist/chunk-SFPANIOY.mjs.map +1 -0
  17. package/dist/{chunk-JHEAUB3Z.mjs → chunk-X6ZF5WAX.mjs} +1 -1
  18. package/dist/{chunk-JHEAUB3Z.mjs.map → chunk-X6ZF5WAX.mjs.map} +1 -1
  19. package/dist/{chunk-Y7MI4PBB.mjs → chunk-YUY5ZAST.mjs} +6 -3
  20. package/dist/chunk-YUY5ZAST.mjs.map +1 -0
  21. package/dist/components/copilot-provider/copilotkit.js +156 -91
  22. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  23. package/dist/components/copilot-provider/copilotkit.mjs +4 -3
  24. package/dist/components/copilot-provider/index.js +156 -91
  25. package/dist/components/copilot-provider/index.js.map +1 -1
  26. package/dist/components/copilot-provider/index.mjs +4 -3
  27. package/dist/components/error-boundary/error-boundary.d.ts +22 -0
  28. package/dist/components/error-boundary/error-boundary.js +183 -0
  29. package/dist/components/error-boundary/error-boundary.js.map +1 -0
  30. package/dist/components/error-boundary/error-boundary.mjs +12 -0
  31. package/dist/components/error-boundary/error-boundary.mjs.map +1 -0
  32. package/dist/components/error-boundary/error-utils.d.ts +11 -0
  33. package/dist/components/error-boundary/error-utils.js +177 -0
  34. package/dist/components/error-boundary/error-utils.js.map +1 -0
  35. package/dist/components/error-boundary/error-utils.mjs +13 -0
  36. package/dist/components/error-boundary/error-utils.mjs.map +1 -0
  37. package/dist/components/index.js +156 -91
  38. package/dist/components/index.js.map +1 -1
  39. package/dist/components/index.mjs +4 -3
  40. package/dist/components/toast/toast-provider.d.ts +2 -1
  41. package/dist/components/toast/toast-provider.js +76 -62
  42. package/dist/components/toast/toast-provider.js.map +1 -1
  43. package/dist/components/toast/toast-provider.mjs +1 -1
  44. package/dist/hooks/index.js +398 -253
  45. package/dist/hooks/index.js.map +1 -1
  46. package/dist/hooks/index.mjs +9 -8
  47. package/dist/hooks/use-chat.js +343 -199
  48. package/dist/hooks/use-chat.js.map +1 -1
  49. package/dist/hooks/use-chat.mjs +3 -3
  50. package/dist/hooks/use-coagent-state-render.d.ts +2 -2
  51. package/dist/hooks/use-coagent-state-render.js.map +1 -1
  52. package/dist/hooks/use-coagent-state-render.mjs +1 -1
  53. package/dist/hooks/use-coagent.js +378 -233
  54. package/dist/hooks/use-coagent.js.map +1 -1
  55. package/dist/hooks/use-coagent.mjs +7 -6
  56. package/dist/hooks/use-copilot-action.js +132 -7
  57. package/dist/hooks/use-copilot-action.js.map +1 -1
  58. package/dist/hooks/use-copilot-action.mjs +3 -1
  59. package/dist/hooks/use-copilot-chat.js +367 -223
  60. package/dist/hooks/use-copilot-chat.js.map +1 -1
  61. package/dist/hooks/use-copilot-chat.mjs +6 -5
  62. package/dist/hooks/use-copilot-runtime-client.js +110 -4
  63. package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
  64. package/dist/hooks/use-copilot-runtime-client.mjs +2 -2
  65. package/dist/index.js +439 -335
  66. package/dist/index.js.map +1 -1
  67. package/dist/index.mjs +10 -9
  68. package/dist/lib/copilot-task.js.map +1 -1
  69. package/dist/lib/copilot-task.mjs +5 -4
  70. package/dist/lib/index.js.map +1 -1
  71. package/dist/lib/index.mjs +5 -4
  72. package/dist/utils/extract.js.map +1 -1
  73. package/dist/utils/extract.mjs +4 -3
  74. package/dist/utils/index.js.map +1 -1
  75. package/dist/utils/index.mjs +4 -3
  76. package/package.json +3 -3
  77. package/src/components/copilot-provider/copilotkit.tsx +4 -1
  78. package/src/components/error-boundary/error-boundary.tsx +42 -0
  79. package/src/components/error-boundary/error-utils.tsx +95 -0
  80. package/src/components/toast/toast-provider.tsx +10 -49
  81. package/src/hooks/use-chat.ts +286 -259
  82. package/src/hooks/use-coagent-state-render.ts +2 -2
  83. package/src/hooks/use-coagent.ts +14 -11
  84. package/src/hooks/use-copilot-action.ts +3 -2
  85. package/src/hooks/use-copilot-chat.ts +9 -8
  86. package/src/hooks/use-copilot-runtime-client.ts +4 -0
  87. package/dist/chunk-2KCEHGSI.mjs.map +0 -1
  88. package/dist/chunk-DHGXL5PC.mjs.map +0 -1
  89. package/dist/chunk-EUIBVFV6.mjs +0 -294
  90. package/dist/chunk-EUIBVFV6.mjs.map +0 -1
  91. package/dist/chunk-O22KGHOQ.mjs.map +0 -1
  92. package/dist/chunk-ODN4H66E.mjs.map +0 -1
  93. package/dist/chunk-XBVKTDXP.mjs.map +0 -1
  94. package/dist/chunk-Y7MI4PBB.mjs.map +0 -1
  95. /package/dist/{chunk-OT67R4NB.mjs.map → chunk-IFTHM7LF.mjs.map} +0 -0
@@ -26,6 +26,7 @@ import { CoagentState } from "../types/coagent-state";
26
26
  import { AgentSession } from "../context/copilot-context";
27
27
  import { useToast } from "../components/toast/toast-provider";
28
28
  import { useCopilotRuntimeClient } from "./use-copilot-runtime-client";
29
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
29
30
 
30
31
  export type UseChatOptions = {
31
32
  /**
@@ -167,292 +168,318 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
167
168
  credentials: copilotConfig.credentials,
168
169
  });
169
170
 
170
- const runChatCompletion = async (previousMessages: Message[]): Promise<Message[]> => {
171
- setIsLoading(true);
172
-
173
- // this message is just a placeholder. It will disappear once the first real message
174
- // is received
175
- let newMessages: Message[] = [
176
- new TextMessage({
177
- content: "",
178
- role: Role.Assistant,
179
- }),
180
- ];
181
- const abortController = new AbortController();
182
- abortControllerRef.current = abortController;
183
-
184
- setMessages([...previousMessages, ...newMessages]);
185
-
186
- const systemMessage = makeSystemMessageCallback();
187
-
188
- const messagesWithContext = [systemMessage, ...(initialMessages || []), ...previousMessages];
189
-
190
- const stream = runtimeClient.asStream(
191
- runtimeClient.generateCopilotResponse({
192
- data: {
193
- frontend: {
194
- actions: actions
195
- .filter(
196
- (action) =>
197
- action.available !== ActionInputAvailability.Disabled || !action.disabled,
198
- )
199
- .map((action) => {
200
- let available: ActionInputAvailability | undefined =
201
- ActionInputAvailability.Enabled;
202
- if (action.disabled) {
203
- available = ActionInputAvailability.Disabled;
204
- } else if (action.available === "disabled") {
205
- available = ActionInputAvailability.Disabled;
206
- } else if (action.available === "remote") {
207
- available = ActionInputAvailability.Remote;
208
- }
209
- return {
210
- name: action.name,
211
- description: action.description || "",
212
- jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters || [])),
213
- available,
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,
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
+ },
232
237
  },
233
- },
234
- }
235
- : {}),
236
- },
237
- }
238
- : {}),
239
- metadata: {
240
- 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
+ })),
241
255
  },
242
- ...(agentSessionRef.current
243
- ? {
244
- agentSession: agentSessionRef.current,
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
- }
277
-
278
- if (done) {
279
- break;
280
- }
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
+ }
281
281
 
282
- if (!value?.generateCopilotResponse) {
283
- continue;
284
- }
282
+ if (done) {
283
+ break;
284
+ }
285
285
 
286
- threadIdRef.current = value.generateCopilotResponse.threadId || null;
287
- runIdRef.current = value.generateCopilotResponse.runId || null;
286
+ if (!value?.generateCopilotResponse) {
287
+ continue;
288
+ }
288
289
 
289
- const messages = convertGqlOutputToMessages(
290
- filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
291
- );
290
+ threadIdRef.current = value.generateCopilotResponse.threadId || null;
291
+ runIdRef.current = value.generateCopilotResponse.runId || null;
292
292
 
293
- if (messages.length === 0) {
294
- continue;
295
- }
293
+ const messages = convertGqlOutputToMessages(
294
+ filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
295
+ );
296
296
 
297
- newMessages = [];
297
+ if (messages.length === 0) {
298
+ continue;
299
+ }
298
300
 
299
- // request failed, display error message
300
- if (
301
- value.generateCopilotResponse.status?.__typename === "FailedResponseStatus" &&
302
- value.generateCopilotResponse.status.reason === "GUARDRAILS_VALIDATION_FAILED"
303
- ) {
304
- newMessages = [
305
- new TextMessage({
306
- role: MessageRole.Assistant,
307
- content: value.generateCopilotResponse.status.details?.guardrailsReason || "",
308
- }),
309
- ];
310
- }
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
+ }
311
315
 
312
- // add messages to the chat
313
- else {
314
- for (const message of messages) {
315
- newMessages.push(message);
316
- // execute regular action executions
317
- if (
318
- message.isActionExecutionMessage() &&
319
- message.status.code !== MessageStatusCode.Pending &&
320
- message.scope === "client" &&
321
- onFunctionCall
322
- ) {
323
- if (!(message.id in actionResults)) {
324
- // 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
325
372
  if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
326
373
  break;
327
374
  }
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]);
333
-
334
- const action = actions.find((action) => action.name === message.name);
335
-
336
- if (action) {
337
- followUp = action.followUp;
338
- }
339
-
340
- const result = await onFunctionCall({
341
- messages: previousMessages,
342
- name: message.name,
343
- args: message.arguments,
344
- });
345
- actionResults[message.id] = result;
346
- } catch (e) {
347
- actionResults[message.id] = `Failed to execute action ${message.name}`;
348
- console.error(`Failed to execute action ${message.name}: ${e}`);
349
- }
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);
350
382
  }
351
- // add the result message
352
- newMessages.push(
353
- new ResultMessage({
354
- result: ResultMessage.encodeResult(actionResults[message.id]),
355
- actionExecutionId: message.id,
356
- actionName: message.name,
357
- }),
358
- );
359
383
  }
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;
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);
370
410
  }
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
411
  }
379
412
  }
380
413
 
381
- const lastAgentStateMessage = [...messages]
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
- }
414
+ if (newMessages.length > 0) {
415
+ // Update message state
416
+ setMessages([...previousMessages, ...newMessages]);
407
417
  }
408
418
  }
409
419
 
410
- if (newMessages.length > 0) {
411
- // Update message state
412
- setMessages([...previousMessages, ...newMessages]);
413
- }
414
- }
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
415
429
 
416
- if (
417
- // if followUp is not explicitly false
418
- followUp !== false &&
419
- // if we have client side results
420
- (Object.values(actionResults).length ||
421
- // or the last message we received is a result
422
- (newMessages.length && newMessages[newMessages.length - 1].isResultMessage()))
423
- ) {
424
- // run the completion again and return the result
425
-
426
- // wait for next tick to make sure all the react state updates
427
- // - tried using react-dom's flushSync, but it did not work
428
- await new Promise((resolve) => setTimeout(resolve, 10));
429
-
430
- return await runChatCompletionRef.current!([...previousMessages, ...newMessages]);
431
- } else {
432
- return newMessages.slice();
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));
433
+
434
+ return await runChatCompletionRef.current!([...previousMessages, ...newMessages]);
435
+ } else {
436
+ return newMessages.slice();
437
+ }
438
+ } finally {
439
+ setIsLoading(false);
433
440
  }
434
- } finally {
435
- setIsLoading(false);
436
- }
437
- };
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
+ );
438
459
 
439
460
  runChatCompletionRef.current = runChatCompletion;
440
461
 
441
- const runChatCompletionAndHandleFunctionCall = async (messages: Message[]): Promise<void> => {
442
- await runChatCompletionRef.current!(messages);
443
- };
444
-
445
- const append = async (message: Message): Promise<void> => {
446
- if (isLoading) {
447
- return;
448
- }
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
+ }
449
474
 
450
- const newMessages = [...messages, message];
451
- setMessages(newMessages);
452
- return runChatCompletionAndHandleFunctionCall(newMessages);
453
- };
475
+ const newMessages = [...messages, message];
476
+ setMessages(newMessages);
477
+ return runChatCompletionAndHandleFunctionCall(newMessages);
478
+ },
479
+ [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall],
480
+ );
454
481
 
455
- const reload = async (): Promise<void> => {
482
+ const reload = useAsyncCallback(async (): Promise<void> => {
456
483
  if (isLoading || messages.length === 0) {
457
484
  return;
458
485
  }
@@ -466,7 +493,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
466
493
  setMessages(newMessages);
467
494
 
468
495
  return runChatCompletionAndHandleFunctionCall(newMessages);
469
- };
496
+ }, [isLoading, messages, setMessages, runChatCompletionAndHandleFunctionCall]);
470
497
 
471
498
  const stop = (): void => {
472
499
  abortControllerRef.current?.abort();
@@ -12,13 +12,13 @@
12
12
  * ### Simple Usage
13
13
  *
14
14
  * ```tsx
15
- * import { useCoagentStateRender } from "@copilotkit/react-core";
15
+ * import { useCoAgentStateRender } from "@copilotkit/react-core";
16
16
  *
17
17
  * type YourAgentState = {
18
18
  * agent_state_property: string;
19
19
  * }
20
20
  *
21
- * useCoagentStateRender<YourAgentState>({
21
+ * useCoAgentStateRender<YourAgentState>({
22
22
  * name: "basic_agent",
23
23
  * nodeName: "optionally_specify_a_specific_node",
24
24
  * render: ({ status, state, nodeName }) => {
@@ -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