@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.
Files changed (140) hide show
  1. package/CHANGELOG.md +158 -4
  2. package/README.md +2 -0
  3. package/dist/{chunk-3AYELZJS.mjs → chunk-35EN6BG4.mjs} +2 -2
  4. package/dist/{chunk-3AYELZJS.mjs.map → chunk-35EN6BG4.mjs.map} +1 -1
  5. package/dist/{chunk-SEPYQHH7.mjs → chunk-42N5VKIX.mjs} +34 -28
  6. package/dist/chunk-42N5VKIX.mjs.map +1 -0
  7. package/dist/{chunk-USL3EHJB.mjs → chunk-5FYKUKG3.mjs} +2 -2
  8. package/dist/{chunk-ODN4H66E.mjs → chunk-7LRDVJH5.mjs} +6 -2
  9. package/dist/chunk-7LRDVJH5.mjs.map +1 -0
  10. package/dist/{chunk-CZMEZR6F.mjs → chunk-BT6WK2JZ.mjs} +34 -19
  11. package/dist/chunk-BT6WK2JZ.mjs.map +1 -0
  12. package/dist/{chunk-3R4J2TPH.mjs → chunk-EUU6NNYU.mjs} +29 -13
  13. package/dist/chunk-EUU6NNYU.mjs.map +1 -0
  14. package/dist/chunk-QCUP6HLK.mjs +37 -0
  15. package/dist/chunk-QCUP6HLK.mjs.map +1 -0
  16. package/dist/chunk-QTDCEDOC.mjs +392 -0
  17. package/dist/chunk-QTDCEDOC.mjs.map +1 -0
  18. package/dist/{chunk-JR55I3FL.mjs → chunk-QX6V774L.mjs} +6 -8
  19. package/dist/chunk-QX6V774L.mjs.map +1 -0
  20. package/dist/{chunk-2KCEHGSI.mjs → chunk-SFPANIOY.mjs} +99 -49
  21. package/dist/chunk-SFPANIOY.mjs.map +1 -0
  22. package/dist/{chunk-2JP64U3A.mjs → chunk-TQN3EZWQ.mjs} +4 -1
  23. package/dist/chunk-TQN3EZWQ.mjs.map +1 -0
  24. package/dist/{chunk-XUPO37VH.mjs → chunk-V3PFWGIY.mjs} +2 -2
  25. package/dist/{chunk-6QKA3SNN.mjs → chunk-VMP6JWBB.mjs} +21 -5
  26. package/dist/chunk-VMP6JWBB.mjs.map +1 -0
  27. package/dist/chunk-XERJQUHA.mjs +31 -0
  28. package/dist/chunk-XERJQUHA.mjs.map +1 -0
  29. package/dist/components/copilot-provider/copilotkit.js +173 -92
  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.js +173 -92
  33. package/dist/components/copilot-provider/index.js.map +1 -1
  34. package/dist/components/copilot-provider/index.mjs +5 -4
  35. package/dist/components/error-boundary/error-boundary.d.ts +22 -0
  36. package/dist/components/error-boundary/error-boundary.js +183 -0
  37. package/dist/components/error-boundary/error-boundary.js.map +1 -0
  38. package/dist/components/error-boundary/error-boundary.mjs +12 -0
  39. package/dist/components/error-boundary/error-boundary.mjs.map +1 -0
  40. package/dist/components/error-boundary/error-utils.d.ts +11 -0
  41. package/dist/components/error-boundary/error-utils.js +177 -0
  42. package/dist/components/error-boundary/error-utils.js.map +1 -0
  43. package/dist/components/error-boundary/error-utils.mjs +13 -0
  44. package/dist/components/error-boundary/error-utils.mjs.map +1 -0
  45. package/dist/components/index.js +173 -92
  46. package/dist/components/index.js.map +1 -1
  47. package/dist/components/index.mjs +5 -4
  48. package/dist/components/toast/toast-provider.d.ts +2 -1
  49. package/dist/components/toast/toast-provider.js +76 -62
  50. package/dist/components/toast/toast-provider.js.map +1 -1
  51. package/dist/components/toast/toast-provider.mjs +1 -1
  52. package/dist/context/copilot-context.d.ts +4 -2
  53. package/dist/context/copilot-context.js +3 -0
  54. package/dist/context/copilot-context.js.map +1 -1
  55. package/dist/context/copilot-context.mjs +1 -1
  56. package/dist/context/index.d.ts +1 -1
  57. package/dist/context/index.js +3 -0
  58. package/dist/context/index.js.map +1 -1
  59. package/dist/context/index.mjs +1 -1
  60. package/dist/hooks/index.js +554 -308
  61. package/dist/hooks/index.js.map +1 -1
  62. package/dist/hooks/index.mjs +13 -11
  63. package/dist/hooks/use-chat.d.ts +6 -2
  64. package/dist/hooks/use-chat.js +434 -219
  65. package/dist/hooks/use-chat.js.map +1 -1
  66. package/dist/hooks/use-chat.mjs +4 -3
  67. package/dist/hooks/use-coagent-state-render.d.ts +2 -2
  68. package/dist/hooks/use-coagent-state-render.js +3 -0
  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.d.ts +1 -1
  72. package/dist/hooks/use-coagent.js +510 -277
  73. package/dist/hooks/use-coagent.js.map +1 -1
  74. package/dist/hooks/use-coagent.mjs +9 -7
  75. package/dist/hooks/use-copilot-action.d.ts +12 -2
  76. package/dist/hooks/use-copilot-action.js +157 -16
  77. package/dist/hooks/use-copilot-action.js.map +1 -1
  78. package/dist/hooks/use-copilot-action.mjs +4 -2
  79. package/dist/hooks/use-copilot-chat.d.ts +1 -0
  80. package/dist/hooks/use-copilot-chat.js +483 -253
  81. package/dist/hooks/use-copilot-chat.js.map +1 -1
  82. package/dist/hooks/use-copilot-chat.mjs +8 -6
  83. package/dist/hooks/use-copilot-readable.js +3 -0
  84. package/dist/hooks/use-copilot-readable.js.map +1 -1
  85. package/dist/hooks/use-copilot-readable.mjs +2 -2
  86. package/dist/hooks/use-copilot-runtime-client.js +110 -4
  87. package/dist/hooks/use-copilot-runtime-client.js.map +1 -1
  88. package/dist/hooks/use-copilot-runtime-client.mjs +2 -2
  89. package/dist/hooks/use-make-copilot-document-readable.js +3 -0
  90. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  91. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  92. package/dist/index.d.ts +1 -1
  93. package/dist/index.js +616 -401
  94. package/dist/index.js.map +1 -1
  95. package/dist/index.mjs +14 -12
  96. package/dist/lib/copilot-task.d.ts +1 -1
  97. package/dist/lib/copilot-task.js +33 -13
  98. package/dist/lib/copilot-task.js.map +1 -1
  99. package/dist/lib/copilot-task.mjs +7 -5
  100. package/dist/lib/index.d.ts +1 -1
  101. package/dist/lib/index.js +33 -13
  102. package/dist/lib/index.js.map +1 -1
  103. package/dist/lib/index.mjs +7 -5
  104. package/dist/types/frontend-action.d.ts +21 -2
  105. package/dist/types/frontend-action.js +34 -0
  106. package/dist/types/frontend-action.js.map +1 -1
  107. package/dist/types/frontend-action.mjs +7 -0
  108. package/dist/types/index.d.ts +2 -1
  109. package/dist/types/index.js.map +1 -1
  110. package/dist/utils/extract.js.map +1 -1
  111. package/dist/utils/extract.mjs +5 -4
  112. package/dist/utils/index.js.map +1 -1
  113. package/dist/utils/index.mjs +5 -4
  114. package/package.json +5 -5
  115. package/src/components/copilot-provider/copilotkit.tsx +22 -1
  116. package/src/components/error-boundary/error-boundary.tsx +42 -0
  117. package/src/components/error-boundary/error-utils.tsx +95 -0
  118. package/src/components/toast/toast-provider.tsx +10 -49
  119. package/src/context/copilot-context.tsx +17 -2
  120. package/src/hooks/use-chat.ts +375 -279
  121. package/src/hooks/use-coagent-state-render.ts +2 -2
  122. package/src/hooks/use-coagent.ts +34 -28
  123. package/src/hooks/use-copilot-action.ts +50 -15
  124. package/src/hooks/use-copilot-chat.ts +28 -14
  125. package/src/hooks/use-copilot-runtime-client.ts +4 -0
  126. package/src/lib/copilot-task.ts +2 -8
  127. package/src/types/frontend-action.ts +55 -2
  128. package/src/types/index.ts +5 -1
  129. package/dist/chunk-2JP64U3A.mjs.map +0 -1
  130. package/dist/chunk-2KCEHGSI.mjs.map +0 -1
  131. package/dist/chunk-3R4J2TPH.mjs.map +0 -1
  132. package/dist/chunk-6EN7J4V2.mjs +0 -317
  133. package/dist/chunk-6EN7J4V2.mjs.map +0 -1
  134. package/dist/chunk-6QKA3SNN.mjs.map +0 -1
  135. package/dist/chunk-CZMEZR6F.mjs.map +0 -1
  136. package/dist/chunk-JR55I3FL.mjs.map +0 -1
  137. package/dist/chunk-ODN4H66E.mjs.map +0 -1
  138. package/dist/chunk-SEPYQHH7.mjs.map +0 -1
  139. /package/dist/{chunk-USL3EHJB.mjs.map → chunk-5FYKUKG3.mjs.map} +0 -0
  140. /package/dist/{chunk-XUPO37VH.mjs.map → chunk-V3PFWGIY.mjs.map} +0 -0
@@ -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 }) => {
@@ -97,7 +97,9 @@ import {
97
97
  } from "../context";
98
98
  import { CoagentState } from "../types/coagent-state";
99
99
  import { useCopilotChat } from "./use-copilot-chat";
100
- import { AgentStateMessage, Message, Role, TextMessage } from "@copilotkit/runtime-client-gql";
100
+ import { Message } from "@copilotkit/runtime-client-gql";
101
+ import { flushSync } from "react-dom";
102
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
101
103
 
102
104
  interface WithInternalStateManagementAndInitial<T> {
103
105
  /**
@@ -218,8 +220,8 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
218
220
  const generalContext = useCopilotContext();
219
221
  const messagesContext = useCopilotMessagesContext();
220
222
  const context = { ...generalContext, ...messagesContext };
221
- const { coagentStates, setCoagentStates } = context;
222
- const { appendMessage } = useCopilotChat();
223
+ const { coagentStates, coagentStatesRef, setCoagentStatesWithRef } = context;
224
+ const { appendMessage, runChatCompletion } = useCopilotChat();
223
225
 
224
226
  const getCoagentState = (coagentStates: Record<string, CoagentState>, name: string) => {
225
227
  if (coagentStates[name]) {
@@ -239,19 +241,16 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
239
241
 
240
242
  // if we manage state internally, we need to provide a function to set the state
241
243
  const setState = (newState: T | ((prevState: T | undefined) => T)) => {
242
- setCoagentStates((prevAgentStates) => {
243
- let coagentState: CoagentState = getCoagentState(prevAgentStates, name);
244
+ let coagentState: CoagentState = getCoagentState(coagentStatesRef.current || {}, name);
245
+ const updatedState =
246
+ typeof newState === "function" ? (newState as Function)(coagentState.state) : newState;
244
247
 
245
- const updatedState =
246
- typeof newState === "function" ? (newState as Function)(coagentState.state) : newState;
247
-
248
- return {
249
- ...prevAgentStates,
250
- [name]: {
251
- ...coagentState,
252
- state: updatedState,
253
- },
254
- };
248
+ setCoagentStatesWithRef({
249
+ ...coagentStatesRef.current,
250
+ [name]: {
251
+ ...coagentState,
252
+ state: updatedState,
253
+ },
255
254
  });
256
255
  };
257
256
 
@@ -269,25 +268,27 @@ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentRe
269
268
  }, [
270
269
  isExternalStateManagement(options) ? JSON.stringify(options.state) : undefined,
271
270
  // reset initialstate on reset
272
- coagentStates === undefined,
271
+ coagentStates[name] === undefined,
273
272
  ]);
274
273
 
274
+ const runAgentCallback = useAsyncCallback(
275
+ async (hint?: HintFunction) => {
276
+ await runAgent(name, context, appendMessage, runChatCompletion, hint);
277
+ },
278
+ [name, context, appendMessage, runChatCompletion],
279
+ );
280
+
275
281
  // Return the state and setState function
276
282
  return {
277
283
  name,
278
284
  nodeName: coagentState.nodeName,
279
- state,
280
- setState,
285
+ threadId: coagentState.threadId,
281
286
  running: coagentState.running,
282
- start: () => {
283
- startAgent(name, context);
284
- },
285
- stop: () => {
286
- stopAgent(name, context);
287
- },
288
- run: (hint?: HintFunction) => {
289
- return runAgent(name, context, appendMessage, hint);
290
- },
287
+ state: coagentState.state,
288
+ setState: isExternalStateManagement(options) ? options.setState : setState,
289
+ start: () => startAgent(name, context),
290
+ stop: () => stopAgent(name, context),
291
+ run: runAgentCallback,
291
292
  };
292
293
  }
293
294
 
@@ -324,6 +325,7 @@ export async function runAgent(
324
325
  name: string,
325
326
  context: CopilotContextParams & CopilotMessagesContextParams,
326
327
  appendMessage: (message: Message) => Promise<void>,
328
+ runChatCompletion: () => Promise<Message[]>,
327
329
  hint?: HintFunction,
328
330
  ) {
329
331
  const { agentSession, setAgentSession } = context;
@@ -341,12 +343,16 @@ export async function runAgent(
341
343
  }
342
344
  }
343
345
 
344
- let state = context.coagentStates?.[name]?.state || {};
346
+ let state = context.coagentStatesRef.current?.[name]?.state || {};
345
347
 
346
348
  if (hint) {
347
349
  const hintMessage = hint({ previousState, currentState: state });
348
350
  if (hintMessage) {
349
351
  await appendMessage(hintMessage);
352
+ } else {
353
+ await runChatCompletion();
350
354
  }
355
+ } else {
356
+ await runChatCompletion();
351
357
  }
352
358
  }
@@ -71,6 +71,15 @@
71
71
  * );
72
72
  * },
73
73
  * });
74
+ *
75
+ * @example
76
+ * // Catch all action allows you to render actions that are not defined in the frontend
77
+ * useCopilotAction({
78
+ * name: "*",
79
+ * render: ({ name, args, status, result, handler, respond }) => {
80
+ * return <div>Rendering action: {name}</div>;
81
+ * },
82
+ * });
74
83
  */
75
84
 
76
85
  /**
@@ -124,10 +133,12 @@
124
133
  import { Parameter, randomId } from "@copilotkit/shared";
125
134
  import { createElement, Fragment, useEffect, useRef } from "react";
126
135
  import { useCopilotContext } from "../context/copilot-context";
136
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
127
137
  import {
128
138
  ActionRenderProps,
129
139
  ActionRenderPropsNoArgsWait,
130
140
  ActionRenderPropsWait,
141
+ CatchAllFrontendAction,
131
142
  FrontendAction,
132
143
  } from "../types/frontend-action";
133
144
 
@@ -141,7 +152,7 @@ import {
141
152
  // useCallback, useMemo or other memoization techniques are not suitable here,
142
153
  // because they will cause a infinite rerender loop.
143
154
  export function useCopilotAction<const T extends Parameter[] | [] = []>(
144
- action: FrontendAction<T>,
155
+ action: FrontendAction<T> | CatchAllFrontendAction,
145
156
  dependencies?: any[],
146
157
  ): void {
147
158
  const { setAction, removeAction, actions, chatComponentsCache } = useCopilotContext();
@@ -151,15 +162,20 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
151
162
  // clone the action to avoid mutating the original object
152
163
  action = { ...action };
153
164
 
154
- // If the developer provides a renderAndWait function, we transform the action
165
+ // If the developer provides a renderAndWaitForResponse function, we transform the action
155
166
  // to use a promise internally, so that we can treat it like a normal action.
156
- if (action.renderAndWait || action.renderAndWaitForResponse) {
167
+ if (
168
+ // renderAndWaitForResponse is not available for catch all actions
169
+ isFrontendAction(action) &&
170
+ // check if renderAndWaitForResponse is set
171
+ (action.renderAndWait || action.renderAndWaitForResponse)
172
+ ) {
157
173
  const renderAndWait = action.renderAndWait || action.renderAndWaitForResponse;
158
174
  // remove the renderAndWait function from the action
159
175
  action.renderAndWait = undefined;
160
176
  action.renderAndWaitForResponse = undefined;
161
177
  // add a handler that will be called when the action is executed
162
- action.handler = (async () => {
178
+ action.handler = useAsyncCallback(async () => {
163
179
  // we create a new promise when the handler is called
164
180
  let resolve: (result: any) => void;
165
181
  let reject: (error: any) => void;
@@ -170,17 +186,23 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
170
186
  renderAndWaitRef.current = { promise, resolve: resolve!, reject: reject! };
171
187
  // then we await the promise (it will be resolved in the original renderAndWait function)
172
188
  return await promise;
173
- }) as any;
189
+ }, []) as any;
174
190
 
175
191
  // add a render function that will be called when the action is rendered
176
192
  action.render = ((props: ActionRenderProps<T>): React.ReactElement => {
193
+ // Specifically for renderAndWaitForResponse the executing state is set too early, causing a race condition
194
+ // To fit it: we will wait for the handler to be ready
195
+ let status = props.status;
196
+ if (props.status === "executing" && !renderAndWaitRef.current) {
197
+ status = "inProgress";
198
+ }
177
199
  // Create type safe waitProps based on whether T extends empty array or not
178
200
  const waitProps = {
179
- status: props.status,
201
+ status,
180
202
  args: props.args,
181
203
  result: props.result,
182
- handler: props.status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
183
- respond: props.status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
204
+ handler: status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
205
+ respond: status === "executing" ? renderAndWaitRef.current!.resolve : undefined,
184
206
  } as T extends [] ? ActionRenderPropsNoArgsWait<T> : ActionRenderPropsWait<T>;
185
207
 
186
208
  // Type guard to check if renderAndWait is for no args case
@@ -211,10 +233,15 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
211
233
  // This ensures that any captured variables in the handler are up to date.
212
234
  if (dependencies === undefined) {
213
235
  if (actions[idRef.current]) {
214
- actions[idRef.current].handler = action.handler as any;
236
+ // catch all actions don't have a handler
237
+ if (isFrontendAction(action)) {
238
+ actions[idRef.current].handler = action.handler as any;
239
+ }
215
240
  if (typeof action.render === "function") {
216
241
  if (chatComponentsCache.current !== null) {
217
- chatComponentsCache.current.actions[action.name] = action.render;
242
+ // TODO: using as any here because the type definitions are getting to tricky
243
+ // not wasting time on this now - we know the types are compatible
244
+ chatComponentsCache.current.actions[action.name] = action.render as any;
218
245
  }
219
246
  }
220
247
  }
@@ -223,23 +250,25 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
223
250
  useEffect(() => {
224
251
  setAction(idRef.current, action as any);
225
252
  if (chatComponentsCache.current !== null && action.render !== undefined) {
226
- chatComponentsCache.current.actions[action.name] = action.render;
253
+ // see comment about type safety above
254
+ chatComponentsCache.current.actions[action.name] = action.render as any;
227
255
  }
228
256
  return () => {
229
257
  // NOTE: For now, we don't remove the chatComponentsCache entry when the action is removed.
230
258
  // This is because we currently don't have access to the messages array in CopilotContext.
259
+ // UPDATE: We now have access, we should remove the entry if not referenced by any message.
231
260
  removeAction(idRef.current);
232
261
  };
233
262
  }, [
234
263
  setAction,
235
264
  removeAction,
236
- action.description,
265
+ isFrontendAction(action) ? action.description : undefined,
237
266
  action.name,
238
- action.disabled,
239
- action.available,
267
+ isFrontendAction(action) ? action.disabled : undefined,
268
+ isFrontendAction(action) ? action.available : undefined,
240
269
  // This should be faster than deep equality checking
241
270
  // In addition, all major JS engines guarantee the order of object keys
242
- JSON.stringify(action.parameters),
271
+ JSON.stringify(isFrontendAction(action) ? action.parameters : []),
243
272
  // include render only if it's a string
244
273
  typeof action.render === "string" ? action.render : undefined,
245
274
  // dependencies set by the developer
@@ -247,6 +276,12 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
247
276
  ]);
248
277
  }
249
278
 
279
+ function isFrontendAction<T extends Parameter[]>(
280
+ action: FrontendAction<T> | CatchAllFrontendAction,
281
+ ): action is FrontendAction<T> {
282
+ return action.name !== "*";
283
+ }
284
+
250
285
  interface RenderAndWaitForResponse {
251
286
  promise: Promise<any>;
252
287
  resolve: (result: any) => void;
@@ -47,6 +47,7 @@ import { defaultCopilotContextCategories } from "../components";
47
47
  import { MessageStatusCode } from "@copilotkit/runtime-client-gql";
48
48
  import { CoAgentStateRenderHandlerArguments } from "@copilotkit/shared";
49
49
  import { useCopilotMessagesContext } from "../context";
50
+ import { useAsyncCallback } from "../components/error-boundary/error-utils";
50
51
 
51
52
  export interface UseCopilotChatOptions {
52
53
  /**
@@ -80,6 +81,7 @@ export interface UseCopilotChatReturn {
80
81
  stopGeneration: () => void;
81
82
  reset: () => void;
82
83
  isLoading: boolean;
84
+ runChatCompletion: () => Promise<Message[]>;
83
85
  }
84
86
 
85
87
  export function useCopilotChat({
@@ -94,9 +96,8 @@ export function useCopilotChat({
94
96
  setIsLoading,
95
97
  chatInstructions,
96
98
  actions,
97
-
98
- coagentStates,
99
- setCoagentStates,
99
+ coagentStatesRef,
100
+ setCoagentStatesWithRef,
100
101
  coAgentStateRenders,
101
102
  agentSession,
102
103
  setAgentSession,
@@ -130,7 +131,7 @@ export function useCopilotChat({
130
131
  });
131
132
  }, [getContextString, makeSystemMessage, chatInstructions]);
132
133
 
133
- const onCoAgentStateRender = useCallback(
134
+ const onCoAgentStateRender = useAsyncCallback(
134
135
  async (args: CoAgentStateRenderHandlerArguments) => {
135
136
  const { name, nodeName, state } = args;
136
137
  let action = Object.values(coAgentStateRenders).find(
@@ -148,7 +149,7 @@ export function useCopilotChat({
148
149
  [coAgentStateRenders],
149
150
  );
150
151
 
151
- const { append, reload, stop } = useChat({
152
+ const { append, reload, stop, runChatCompletion } = useChat({
152
153
  ...options,
153
154
  actions: Object.values(actions),
154
155
  copilotConfig: copilotApiConfig,
@@ -160,8 +161,8 @@ export function useCopilotChat({
160
161
  makeSystemMessageCallback,
161
162
  isLoading,
162
163
  setIsLoading,
163
- coagentStates,
164
- setCoagentStates,
164
+ coagentStatesRef,
165
+ setCoagentStatesWithRef,
165
166
  agentSession,
166
167
  setAgentSession,
167
168
  threadId,
@@ -180,16 +181,16 @@ export function useCopilotChat({
180
181
  // How does this work?
181
182
  // we store the relevant function in a ref that is always up-to-date, and then we use that ref in the callback.
182
183
  const latestAppend = useUpdatedRef(append);
183
- const latestAppendFunc = useCallback(
184
- (message: Message) => {
185
- return latestAppend.current(message);
184
+ const latestAppendFunc = useAsyncCallback(
185
+ async (message: Message) => {
186
+ return await latestAppend.current(message);
186
187
  },
187
188
  [latestAppend],
188
189
  );
189
190
 
190
191
  const latestReload = useUpdatedRef(reload);
191
- const latestReloadFunc = useCallback(() => {
192
- return latestReload.current();
192
+ const latestReloadFunc = useAsyncCallback(async () => {
193
+ return await latestReload.current();
193
194
  }, [latestReload]);
194
195
 
195
196
  const latestStop = useUpdatedRef(stop);
@@ -213,12 +214,17 @@ export function useCopilotChat({
213
214
  [latestSetMessages],
214
215
  );
215
216
 
217
+ const latestRunChatCompletion = useUpdatedRef(runChatCompletion);
218
+ const latestRunChatCompletionFunc = useAsyncCallback(async () => {
219
+ return await latestRunChatCompletion.current!();
220
+ }, [latestRunChatCompletion]);
221
+
216
222
  const reset = useCallback(() => {
217
223
  latestStopFunc();
218
224
  setMessages([]);
219
225
  setThreadId(null);
220
226
  setRunId(null);
221
- setCoagentStates({});
227
+ setCoagentStatesWithRef({});
222
228
  let initialAgentSession: AgentSession | null = null;
223
229
  if (agentLock) {
224
230
  initialAgentSession = {
@@ -226,7 +232,14 @@ export function useCopilotChat({
226
232
  };
227
233
  }
228
234
  setAgentSession(initialAgentSession);
229
- }, [latestStopFunc, setMessages, setThreadId, setCoagentStates, setAgentSession, agentLock]);
235
+ }, [
236
+ latestStopFunc,
237
+ setMessages,
238
+ setThreadId,
239
+ setCoagentStatesWithRef,
240
+ setAgentSession,
241
+ agentLock,
242
+ ]);
230
243
 
231
244
  const latestReset = useUpdatedRef(reset);
232
245
  const latestResetFunc = useCallback(() => {
@@ -241,6 +254,7 @@ export function useCopilotChat({
241
254
  stopGeneration: latestStopFunc,
242
255
  reset: latestResetFunc,
243
256
  deleteMessage: latestDeleteFunc,
257
+ runChatCompletion: latestRunChatCompletionFunc,
244
258
  isLoading,
245
259
  };
246
260
  }
@@ -5,9 +5,11 @@ import {
5
5
  } from "@copilotkit/runtime-client-gql";
6
6
  import { useToast } from "../components/toast/toast-provider";
7
7
  import { useMemo } from "react";
8
+ import { useErrorToast } from "../components/error-boundary/error-utils";
8
9
 
9
10
  export const useCopilotRuntimeClient = (options: CopilotRuntimeClientOptions) => {
10
11
  const { addGraphQLErrorsToast } = useToast();
12
+ const addErrorToast = useErrorToast();
11
13
 
12
14
  const runtimeClient = useMemo(() => {
13
15
  return new CopilotRuntimeClient({
@@ -15,6 +17,8 @@ export const useCopilotRuntimeClient = (options: CopilotRuntimeClientOptions) =>
15
17
  handleGQLErrors: (error) => {
16
18
  if ((error as any).graphQLErrors.length) {
17
19
  addGraphQLErrorsToast((error as any).graphQLErrors as GraphQLError[]);
20
+ } else {
21
+ addErrorToast([error]);
18
22
  }
19
23
  },
20
24
  });
@@ -57,11 +57,9 @@ import {
57
57
  filterAgentStateMessages,
58
58
  CopilotRequestType,
59
59
  } from "@copilotkit/runtime-client-gql";
60
- import { FrontendAction } from "../types/frontend-action";
60
+ import { FrontendAction, processActionsForRuntimeRequest } from "../types/frontend-action";
61
61
  import { CopilotContextParams } from "../context";
62
62
  import { defaultCopilotContextCategories } from "../components";
63
- import { MessageStatusCode } from "@copilotkit/runtime-client-gql";
64
- import { actionParametersToJsonSchema } from "@copilotkit/shared";
65
63
 
66
64
  export interface CopilotTaskConfig {
67
65
  /**
@@ -137,11 +135,7 @@ export class CopilotTask<T = any> {
137
135
  .generateCopilotResponse({
138
136
  data: {
139
137
  frontend: {
140
- actions: Object.values(actions).map((action) => ({
141
- name: action.name,
142
- description: action.description || "",
143
- jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters || [])),
144
- })),
138
+ actions: processActionsForRuntimeRequest(Object.values(actions)),
145
139
  url: window.location.href,
146
140
  },
147
141
  messages: convertMessagesToGqlInput(filterAgentStateMessages(messages)),
@@ -1,4 +1,10 @@
1
- import { Action, Parameter, MappedParameterTypes } from "@copilotkit/shared";
1
+ import { ActionInputAvailability } from "@copilotkit/runtime-client-gql";
2
+ import {
3
+ Action,
4
+ Parameter,
5
+ MappedParameterTypes,
6
+ actionParametersToJsonSchema,
7
+ } from "@copilotkit/shared";
2
8
  import React from "react";
3
9
 
4
10
  interface InProgressState<T extends Parameter[] | [] = []> {
@@ -110,9 +116,24 @@ export type ActionRenderPropsNoArgsWait<T extends Parameter[] | [] = []> =
110
116
  | ExecutingStateNoArgsWait<T>
111
117
  | InProgressStateNoArgsWait<T>;
112
118
 
119
+ export type CatchAllActionRenderProps<T extends Parameter[] | [] = []> =
120
+ | (CompleteState<T> & {
121
+ name: string;
122
+ })
123
+ | (ExecutingState<T> & {
124
+ name: string;
125
+ })
126
+ | (InProgressState<T> & {
127
+ name: string;
128
+ });
129
+
113
130
  export type FrontendActionAvailability = "disabled" | "enabled" | "remote";
114
131
 
115
- export type FrontendAction<T extends Parameter[] | [] = []> = Action<T> & {
132
+ export type FrontendAction<
133
+ T extends Parameter[] | [] = [],
134
+ N extends string = string,
135
+ > = Action<T> & {
136
+ name: Exclude<N, "*">;
116
137
  /**
117
138
  * @deprecated Use `available` instead.
118
139
  */
@@ -143,4 +164,36 @@ export type FrontendAction<T extends Parameter[] | [] = []> = Action<T> & {
143
164
  }
144
165
  );
145
166
 
167
+ export type CatchAllFrontendAction = {
168
+ name: "*";
169
+ render: (props: CatchAllActionRenderProps<any>) => React.ReactElement;
170
+ };
171
+
146
172
  export type RenderFunctionStatus = ActionRenderProps<any>["status"];
173
+
174
+ export function processActionsForRuntimeRequest(actions: FrontendAction<any>[]) {
175
+ const filteredActions = actions
176
+ .filter(
177
+ (action) =>
178
+ action.available !== ActionInputAvailability.Disabled &&
179
+ action.disabled !== true &&
180
+ action.name !== "*",
181
+ )
182
+ .map((action) => {
183
+ let available: ActionInputAvailability | undefined = ActionInputAvailability.Enabled;
184
+ if (action.disabled) {
185
+ available = ActionInputAvailability.Disabled;
186
+ } else if (action.available === "disabled") {
187
+ available = ActionInputAvailability.Disabled;
188
+ } else if (action.available === "remote") {
189
+ available = ActionInputAvailability.Remote;
190
+ }
191
+ return {
192
+ name: action.name,
193
+ description: action.description || "",
194
+ jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters || [])),
195
+ available,
196
+ };
197
+ });
198
+ return filteredActions;
199
+ }
@@ -1,4 +1,8 @@
1
1
  export type { DocumentPointer } from "./document-pointer";
2
2
  export type { SystemMessageFunction } from "./system-message";
3
- export type { ActionRenderProps, RenderFunctionStatus } from "./frontend-action";
3
+ export type {
4
+ ActionRenderProps,
5
+ RenderFunctionStatus,
6
+ CatchAllActionRenderProps,
7
+ } from "./frontend-action";
4
8
  export type { CopilotChatSuggestionConfiguration } from "./chat-suggestion-configuration";
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/context/copilot-context.tsx"],"sourcesContent":["import { CopilotCloudConfig, FunctionCallHandler } from \"@copilotkit/shared\";\nimport { ActionRenderProps, FrontendAction } from \"../types/frontend-action\";\nimport React from \"react\";\nimport { TreeNodeId } from \"../hooks/use-tree\";\nimport { DocumentPointer } from \"../types\";\nimport { CopilotChatSuggestionConfiguration } from \"../types/chat-suggestion-configuration\";\nimport { CoAgentStateRender, CoAgentStateRenderProps } from \"../types/coagent-action\";\nimport { CoagentState } from \"../types/coagent-state\";\nimport { CopilotRuntimeClient } from \"@copilotkit/runtime-client-gql\";\n\n/**\n * Interface for the configuration of the Copilot API.\n */\nexport interface CopilotApiConfig {\n /**\n * The public API key for Copilot Cloud.\n */\n publicApiKey?: string;\n\n /**\n * The configuration for Copilot Cloud.\n */\n cloud?: CopilotCloudConfig;\n\n /**\n * The endpoint for the chat API.\n */\n chatApiEndpoint: string;\n\n /**\n * The endpoint for the Copilot transcribe audio service.\n */\n transcribeAudioUrl?: string;\n\n /**\n * The endpoint for the Copilot text to speech service.\n */\n textToSpeechUrl?: string;\n\n /**\n * additional headers to be sent with the request\n * @default {}\n * @example\n * ```\n * {\n * 'Authorization': 'Bearer your_token_here'\n * }\n * ```\n */\n headers: Record<string, string>;\n\n /**\n * Custom properties to be sent with the request\n * @default {}\n * @example\n * ```\n * {\n * 'user_id': 'user_id'\n * }\n * ```\n */\n properties?: Record<string, any>;\n\n /**\n * Indicates whether the user agent should send or receive cookies from the other domain\n * in the case of cross-origin requests.\n */\n credentials?: RequestCredentials;\n}\n\nexport type InChatRenderFunction = (props: ActionRenderProps<any>) => string | JSX.Element;\nexport type CoagentInChatRenderFunction = (\n props: CoAgentStateRenderProps<any>,\n) => string | JSX.Element | undefined | null;\n\nexport interface ChatComponentsCache {\n actions: Record<string, InChatRenderFunction | string>;\n coAgentStateRenders: Record<string, CoagentInChatRenderFunction | string>;\n}\n\nexport interface AgentSession {\n agentName: string;\n threadId?: string;\n nodeName?: string;\n}\n\nexport interface CopilotContextParams {\n // function-calling\n actions: Record<string, FrontendAction<any>>;\n setAction: (id: string, action: FrontendAction<any>) => void;\n removeAction: (id: string) => void;\n\n // coagent actions\n coAgentStateRenders: Record<string, CoAgentStateRender<any>>;\n setCoAgentStateRender: (id: string, stateRender: CoAgentStateRender<any>) => void;\n removeCoAgentStateRender: (id: string) => void;\n\n chatComponentsCache: React.RefObject<ChatComponentsCache>;\n\n getFunctionCallHandler: (\n customEntryPoints?: Record<string, FrontendAction<any>>,\n ) => FunctionCallHandler;\n\n // text context\n addContext: (context: string, parentId?: string, categories?: string[]) => TreeNodeId;\n removeContext: (id: TreeNodeId) => void;\n getContextString: (documents: DocumentPointer[], categories: string[]) => string;\n\n // document context\n addDocumentContext: (documentPointer: DocumentPointer, categories?: string[]) => TreeNodeId;\n removeDocumentContext: (documentId: string) => void;\n getDocumentsContext: (categories: string[]) => DocumentPointer[];\n\n isLoading: boolean;\n setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;\n\n chatSuggestionConfiguration: { [key: string]: CopilotChatSuggestionConfiguration };\n addChatSuggestionConfiguration: (\n id: string,\n suggestion: CopilotChatSuggestionConfiguration,\n ) => void;\n removeChatSuggestionConfiguration: (id: string) => void;\n\n chatInstructions: string;\n setChatInstructions: React.Dispatch<React.SetStateAction<string>>;\n\n // api endpoints\n copilotApiConfig: CopilotApiConfig;\n\n showDevConsole: boolean | \"auto\";\n\n // agents\n coagentStates: Record<string, CoagentState>;\n setCoagentStates: React.Dispatch<React.SetStateAction<Record<string, CoagentState>>>;\n agentSession: AgentSession | null;\n setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;\n\n agentLock: string | null;\n\n threadId: string | null;\n setThreadId: React.Dispatch<React.SetStateAction<string | null>>;\n\n runId: string | null;\n setRunId: React.Dispatch<React.SetStateAction<string | null>>;\n\n // The chat abort controller can be used to stop generation globally,\n // i.e. when using `stop()` from `useChat`\n chatAbortControllerRef: React.MutableRefObject<AbortController | null>;\n\n // runtime\n runtimeClient: CopilotRuntimeClient;\n}\n\nconst emptyCopilotContext: CopilotContextParams = {\n actions: {},\n setAction: () => {},\n removeAction: () => {},\n\n coAgentStateRenders: {},\n setCoAgentStateRender: () => {},\n removeCoAgentStateRender: () => {},\n\n chatComponentsCache: { current: { actions: {}, coAgentStateRenders: {} } },\n getContextString: (documents: DocumentPointer[], categories: string[]) =>\n returnAndThrowInDebug(\"\"),\n addContext: () => \"\",\n removeContext: () => {},\n\n getFunctionCallHandler: () => returnAndThrowInDebug(async () => {}),\n\n isLoading: false,\n setIsLoading: () => returnAndThrowInDebug(false),\n\n chatInstructions: \"\",\n setChatInstructions: () => returnAndThrowInDebug(\"\"),\n\n getDocumentsContext: (categories: string[]) => returnAndThrowInDebug([]),\n addDocumentContext: () => returnAndThrowInDebug(\"\"),\n removeDocumentContext: () => {},\n runtimeClient: {} as any,\n\n copilotApiConfig: new (class implements CopilotApiConfig {\n get chatApiEndpoint(): string {\n throw new Error(\"Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!\");\n }\n\n get headers(): Record<string, string> {\n return {};\n }\n get body(): Record<string, any> {\n return {};\n }\n })(),\n\n chatSuggestionConfiguration: {},\n addChatSuggestionConfiguration: () => {},\n removeChatSuggestionConfiguration: () => {},\n showDevConsole: \"auto\",\n coagentStates: {},\n setCoagentStates: () => {},\n\n agentSession: null,\n setAgentSession: () => {},\n\n agentLock: null,\n\n threadId: null,\n setThreadId: () => {},\n\n runId: null,\n setRunId: () => {},\n\n chatAbortControllerRef: { current: null },\n};\n\nexport const CopilotContext = React.createContext<CopilotContextParams>(emptyCopilotContext);\n\nexport function useCopilotContext(): CopilotContextParams {\n const context = React.useContext(CopilotContext);\n if (context === emptyCopilotContext) {\n throw new Error(\"Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!\");\n }\n return context;\n}\n\nfunction returnAndThrowInDebug<T>(value: T): T {\n throw new Error(\"Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!\");\n return value;\n}\n"],"mappings":";;;;;AAEA,OAAO,WAAW;AAuJlB,IAAM,sBAA4C;AAAA,EAChD,SAAS,CAAC;AAAA,EACV,WAAW,MAAM;AAAA,EAAC;AAAA,EAClB,cAAc,MAAM;AAAA,EAAC;AAAA,EAErB,qBAAqB,CAAC;AAAA,EACtB,uBAAuB,MAAM;AAAA,EAAC;AAAA,EAC9B,0BAA0B,MAAM;AAAA,EAAC;AAAA,EAEjC,qBAAqB,EAAE,SAAS,EAAE,SAAS,CAAC,GAAG,qBAAqB,CAAC,EAAE,EAAE;AAAA,EACzE,kBAAkB,CAAC,WAA8B,eAC/C,sBAAsB,EAAE;AAAA,EAC1B,YAAY,MAAM;AAAA,EAClB,eAAe,MAAM;AAAA,EAAC;AAAA,EAEtB,wBAAwB,MAAM,sBAAsB,MAAY;AAAA,EAAC,EAAC;AAAA,EAElE,WAAW;AAAA,EACX,cAAc,MAAM,sBAAsB,KAAK;AAAA,EAE/C,kBAAkB;AAAA,EAClB,qBAAqB,MAAM,sBAAsB,EAAE;AAAA,EAEnD,qBAAqB,CAAC,eAAyB,sBAAsB,CAAC,CAAC;AAAA,EACvE,oBAAoB,MAAM,sBAAsB,EAAE;AAAA,EAClD,uBAAuB,MAAM;AAAA,EAAC;AAAA,EAC9B,eAAe,CAAC;AAAA,EAEhB,kBAAkB,IAAK,MAAkC;AAAA,IACvD,IAAI,kBAA0B;AAC5B,YAAM,IAAI,MAAM,uEAAuE;AAAA,IACzF;AAAA,IAEA,IAAI,UAAkC;AACpC,aAAO,CAAC;AAAA,IACV;AAAA,IACA,IAAI,OAA4B;AAC9B,aAAO,CAAC;AAAA,IACV;AAAA,EACF,EAAG;AAAA,EAEH,6BAA6B,CAAC;AAAA,EAC9B,gCAAgC,MAAM;AAAA,EAAC;AAAA,EACvC,mCAAmC,MAAM;AAAA,EAAC;AAAA,EAC1C,gBAAgB;AAAA,EAChB,eAAe,CAAC;AAAA,EAChB,kBAAkB,MAAM;AAAA,EAAC;AAAA,EAEzB,cAAc;AAAA,EACd,iBAAiB,MAAM;AAAA,EAAC;AAAA,EAExB,WAAW;AAAA,EAEX,UAAU;AAAA,EACV,aAAa,MAAM;AAAA,EAAC;AAAA,EAEpB,OAAO;AAAA,EACP,UAAU,MAAM;AAAA,EAAC;AAAA,EAEjB,wBAAwB,EAAE,SAAS,KAAK;AAC1C;AAEO,IAAM,iBAAiB,MAAM,cAAoC,mBAAmB;AAEpF,SAAS,oBAA0C;AACxD,QAAM,UAAU,MAAM,WAAW,cAAc;AAC/C,MAAI,YAAY,qBAAqB;AACnC,UAAM,IAAI,MAAM,uEAAuE;AAAA,EACzF;AACA,SAAO;AACT;AAEA,SAAS,sBAAyB,OAAa;AAC7C,QAAM,IAAI,MAAM,uEAAuE;AACvF,SAAO;AACT;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/toast/toast-provider.tsx"],"sourcesContent":["import { useCopilotContext } from \"../../context\";\nimport { GraphQLError } from \"@copilotkit/runtime-client-gql\";\nimport React, { createContext, useContext, useState, useCallback } from \"react\";\nimport { ExclamationMarkIcon } from \"./exclamation-mark-icon\";\n\ninterface Toast {\n id: string;\n message: string | React.ReactNode;\n type: \"info\" | \"success\" | \"warning\" | \"error\";\n duration?: number;\n}\n\ninterface ToastContextValue {\n toasts: Toast[];\n addToast: (toast: Omit<Toast, \"id\">) => void;\n addGraphQLErrorsToast: (errors: GraphQLError[]) => void;\n removeToast: (id: string) => void;\n enabled: boolean;\n}\n\nconst ToastContext = createContext<ToastContextValue | undefined>(undefined);\n\nexport function useToast() {\n const context = useContext(ToastContext);\n if (!context) {\n throw new Error(\"useToast must be used within a ToastProvider\");\n }\n return context;\n}\n\nexport function ToastProvider({\n enabled,\n children,\n}: {\n enabled: boolean;\n children: React.ReactNode;\n}) {\n const [toasts, setToasts] = useState<Toast[]>([]);\n const addToast = useCallback((toast: Omit<Toast, \"id\">) => {\n const id = Math.random().toString(36).substring(2, 9);\n\n setToasts((currentToasts) => [...currentToasts, { ...toast, id }]);\n\n if (toast.duration) {\n setTimeout(() => {\n removeToast(id);\n }, toast.duration);\n }\n }, []);\n\n const addGraphQLErrorsToast = useCallback((errors: GraphQLError[]) => {\n // We do not display these errors unless we are in dev mode.\n // if (!showDevConsole) {\n // return;\n // }\n\n const errorsToRender = errors.map((error, idx) => {\n const message = error.message;\n const code = error.extensions?.code as string;\n\n return (\n <div\n key={idx}\n style={{\n marginTop: idx === 0 ? 0 : 10,\n marginBottom: 14,\n }}\n >\n <ExclamationMarkIcon style={{ marginBottom: 4 }} />\n\n {code && (\n <div\n style={{\n fontWeight: \"600\",\n marginBottom: 4,\n }}\n >\n Copilot Cloud Error:{\" \"}\n <span style={{ fontFamily: \"monospace\", fontWeight: \"normal\" }}>{code}</span>\n </div>\n )}\n <div>{message}</div>\n </div>\n );\n });\n\n addToast({\n type: \"error\",\n message: (\n <div\n style={{\n fontSize: \"13px\",\n maxWidth: \"600px\",\n }}\n >\n {errorsToRender}\n <div style={{ fontSize: \"11px\", opacity: 0.75 }}>\n NOTE: This is a Copilot Cloud error, and it only displays during local development.\n </div>\n </div>\n ),\n });\n }, []);\n\n const removeToast = useCallback((id: string) => {\n setToasts((currentToasts) => currentToasts.filter((toast) => toast.id !== id));\n }, []);\n\n const value = {\n toasts,\n addToast,\n addGraphQLErrorsToast,\n removeToast,\n enabled,\n };\n\n return (\n <ToastContext.Provider value={value}>\n <div\n style={{\n position: \"fixed\",\n bottom: \"1rem\",\n left: \"50%\",\n transform: \"translateX(-50%)\",\n zIndex: 50,\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"0.5rem\",\n }}\n >\n {toasts.length > 1 && (\n <div style={{ textAlign: \"right\" }}>\n <button\n onClick={() => setToasts([])}\n style={{\n padding: \"4px 8px\",\n fontSize: \"12px\",\n cursor: \"pointer\",\n background: \"white\",\n border: \"1px solid rgba(0,0,0,0.2)\",\n borderRadius: \"4px\",\n }}\n >\n Close All\n </button>\n </div>\n )}\n {toasts.map((toast) => (\n <Toast\n key={toast.id}\n message={toast.message}\n type={toast.type}\n onClose={() => removeToast(toast.id)}\n />\n ))}\n </div>\n {children}\n </ToastContext.Provider>\n );\n}\n\nfunction Toast({\n message,\n type = \"info\",\n onClose,\n}: {\n message: string | React.ReactNode;\n type: \"info\" | \"success\" | \"warning\" | \"error\";\n onClose: () => void;\n}) {\n const bgColors = {\n info: \"#3b82f6\",\n success: \"#22c55e\",\n warning: \"#eab308\",\n error: \"#ef4444\",\n };\n\n return (\n <div\n style={{\n backgroundColor: bgColors[type],\n color: \"white\",\n padding: \"0.5rem 1rem\",\n borderRadius: \"0.25rem\",\n boxShadow: \"0 2px 4px rgba(0,0,0,0.1)\",\n position: \"relative\",\n minWidth: \"200px\",\n }}\n >\n <div>{message}</div>\n <button\n onClick={onClose}\n style={{\n position: \"absolute\",\n top: \"0\",\n right: \"0\",\n background: \"none\",\n border: \"none\",\n color: \"white\",\n cursor: \"pointer\",\n padding: \"0.5rem\",\n fontSize: \"1rem\",\n }}\n >\n ✕\n </button>\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/use-copilot-action.ts"],"sourcesContent":["/**\n * Example usage of useCopilotAction with complex parameters:\n *\n * @example\n * useCopilotAction({\n * name: \"myAction\",\n * parameters: [\n * { name: \"arg1\", type: \"string\", enum: [\"option1\", \"option2\", \"option3\"], required: false },\n * { name: \"arg2\", type: \"number\" },\n * {\n * name: \"arg3\",\n * type: \"object\",\n * attributes: [\n * { name: \"nestedArg1\", type: \"boolean\" },\n * { name: \"xyz\", required: false },\n * ],\n * },\n * { name: \"arg4\", type: \"number[]\" },\n * ],\n * handler: ({ arg1, arg2, arg3, arg4 }) => {\n * const x = arg3.nestedArg1;\n * const z = arg3.xyz;\n * console.log(arg1, arg2, arg3);\n * },\n * });\n *\n * @example\n * // Simple action without parameters\n * useCopilotAction({\n * name: \"myAction\",\n * handler: () => {\n * console.log(\"No parameters provided.\");\n * },\n * });\n *\n * @example\n * // Interactive action with UI rendering and response handling\n * useCopilotAction({\n * name: \"handleMeeting\",\n * description: \"Handle a meeting by booking or canceling\",\n * parameters: [\n * {\n * name: \"meeting\",\n * type: \"string\",\n * description: \"The meeting to handle\",\n * required: true,\n * },\n * {\n * name: \"date\",\n * type: \"string\",\n * description: \"The date of the meeting\",\n * required: true,\n * },\n * {\n * name: \"title\",\n * type: \"string\",\n * description: \"The title of the meeting\",\n * required: true,\n * },\n * ],\n * renderAndWaitForResponse: ({ args, respond, status }) => {\n * const { meeting, date, title } = args;\n * return (\n * <MeetingConfirmationDialog\n * meeting={meeting}\n * date={date}\n * title={title}\n * onConfirm={() => respond('meeting confirmed')}\n * onCancel={() => respond('meeting canceled')}\n * />\n * );\n * },\n * });\n */\n\n/**\n * <img src=\"/images/use-copilot-action/useCopilotAction.gif\" width=\"500\" />\n * `useCopilotAction` is a React hook that you can use in your application to provide\n * custom actions that can be called by the AI. Essentially, it allows the Copilot to\n * execute these actions contextually during a chat, based on the user's interactions\n * and needs.\n *\n * Here's how it works:\n *\n * Use `useCopilotAction` to set up actions that the Copilot can call. To provide\n * more context to the Copilot, you can provide it with a `description` (for example to explain\n * what the action does, under which conditions it can be called, etc.).\n *\n * Then you define the parameters of the action, which can be simple, e.g. primitives like strings or numbers,\n * or complex, e.g. objects or arrays.\n *\n * Finally, you provide a `handler` function that receives the parameters and returns a result.\n * CopilotKit takes care of automatically inferring the parameter types, so you get type safety\n * and autocompletion for free.\n *\n * To render a custom UI for the action, you can provide a `render()` function. This function\n * lets you render a custom component or return a string to display.\n *\n * ## Usage\n *\n * ### Simple Usage\n *\n * ```tsx\n * useCopilotAction({\n * name: \"sayHello\",\n * description: \"Say hello to someone.\",\n * parameters: [\n * {\n * name: \"name\",\n * type: \"string\",\n * description: \"name of the person to say greet\",\n * },\n * ],\n * handler: async ({ name }) => {\n * alert(`Hello, ${name}!`);\n * },\n * });\n * ```\n *\n * ## Generative UI\n *\n * This hooks enables you to dynamically generate UI elements and render them in the copilot chat. For more information, check out the [Generative UI](/guides/generative-ui) page.\n */\nimport { Parameter, randomId } from \"@copilotkit/shared\";\nimport { createElement, Fragment, useEffect, useRef } from \"react\";\nimport { useCopilotContext } from \"../context/copilot-context\";\nimport {\n ActionRenderProps,\n ActionRenderPropsNoArgsWait,\n ActionRenderPropsWait,\n FrontendAction,\n} from \"../types/frontend-action\";\n\n// We implement useCopilotAction dependency handling so that\n// the developer has the option to not provide any dependencies.\n// In this case, we assume they want to update the handler on each rerender.\n// To avoid getting stuck in an infinite loop, we update the handler directly,\n// skipping React state updates.\n// This is ok in this case, because the handler is not part of any UI that\n// needs to be updated.\n// useCallback, useMemo or other memoization techniques are not suitable here,\n// because they will cause a infinite rerender loop.\nexport function useCopilotAction<const T extends Parameter[] | [] = []>(\n action: FrontendAction<T>,\n dependencies?: any[],\n): void {\n const { setAction, removeAction, actions, chatComponentsCache } = useCopilotContext();\n const idRef = useRef<string>(randomId());\n const renderAndWaitRef = useRef<RenderAndWaitForResponse | null>(null);\n\n // clone the action to avoid mutating the original object\n action = { ...action };\n\n // If the developer provides a renderAndWait function, we transform the action\n // to use a promise internally, so that we can treat it like a normal action.\n if (action.renderAndWait || action.renderAndWaitForResponse) {\n const renderAndWait = action.renderAndWait || action.renderAndWaitForResponse;\n // remove the renderAndWait function from the action\n action.renderAndWait = undefined;\n action.renderAndWaitForResponse = undefined;\n // add a handler that will be called when the action is executed\n action.handler = (async () => {\n // we create a new promise when the handler is called\n let resolve: (result: any) => void;\n let reject: (error: any) => void;\n const promise = new Promise<any>((resolvePromise, rejectPromise) => {\n resolve = resolvePromise;\n reject = rejectPromise;\n });\n renderAndWaitRef.current = { promise, resolve: resolve!, reject: reject! };\n // then we await the promise (it will be resolved in the original renderAndWait function)\n return await promise;\n }) as any;\n\n // add a render function that will be called when the action is rendered\n action.render = ((props: ActionRenderProps<T>): React.ReactElement => {\n // Create type safe waitProps based on whether T extends empty array or not\n const waitProps = {\n status: props.status,\n args: props.args,\n result: props.result,\n handler: props.status === \"executing\" ? renderAndWaitRef.current!.resolve : undefined,\n respond: props.status === \"executing\" ? renderAndWaitRef.current!.resolve : undefined,\n } as T extends [] ? ActionRenderPropsNoArgsWait<T> : ActionRenderPropsWait<T>;\n\n // Type guard to check if renderAndWait is for no args case\n const isNoArgsRenderWait = (\n _fn:\n | ((props: ActionRenderPropsNoArgsWait<T>) => React.ReactElement)\n | ((props: ActionRenderPropsWait<T>) => React.ReactElement),\n ): _fn is (props: ActionRenderPropsNoArgsWait<T>) => React.ReactElement => {\n return action.parameters?.length === 0;\n };\n\n // Safely call renderAndWait with correct props type\n if (renderAndWait) {\n if (isNoArgsRenderWait(renderAndWait)) {\n return renderAndWait(waitProps as ActionRenderPropsNoArgsWait<T>);\n } else {\n return renderAndWait(waitProps as ActionRenderPropsWait<T>);\n }\n }\n\n // Return empty Fragment instead of null\n return createElement(Fragment);\n }) as any;\n }\n\n // If the developer doesn't provide dependencies, we assume they want to\n // update handler and render function when the action object changes.\n // This ensures that any captured variables in the handler are up to date.\n if (dependencies === undefined) {\n if (actions[idRef.current]) {\n actions[idRef.current].handler = action.handler as any;\n if (typeof action.render === \"function\") {\n if (chatComponentsCache.current !== null) {\n chatComponentsCache.current.actions[action.name] = action.render;\n }\n }\n }\n }\n\n useEffect(() => {\n setAction(idRef.current, action as any);\n if (chatComponentsCache.current !== null && action.render !== undefined) {\n chatComponentsCache.current.actions[action.name] = action.render;\n }\n return () => {\n // NOTE: For now, we don't remove the chatComponentsCache entry when the action is removed.\n // This is because we currently don't have access to the messages array in CopilotContext.\n removeAction(idRef.current);\n };\n }, [\n setAction,\n removeAction,\n action.description,\n action.name,\n action.disabled,\n action.available,\n // This should be faster than deep equality checking\n // In addition, all major JS engines guarantee the order of object keys\n JSON.stringify(action.parameters),\n // include render only if it's a string\n typeof action.render === \"string\" ? action.render : undefined,\n // dependencies set by the developer\n ...(dependencies || []),\n ]);\n}\n\ninterface RenderAndWaitForResponse {\n promise: Promise<any>;\n resolve: (result: any) => void;\n reject: (error: any) => void;\n}\n"],"mappings":";;;;;;;;;AA2HA,SAAoB,gBAAgB;AACpC,SAAS,eAAe,UAAU,WAAW,cAAc;AAkBpD,SAAS,iBACd,QACA,cACM;AACN,QAAM,EAAE,WAAW,cAAc,SAAS,oBAAoB,IAAI,kBAAkB;AACpF,QAAM,QAAQ,OAAe,SAAS,CAAC;AACvC,QAAM,mBAAmB,OAAwC,IAAI;AAGrE,WAAS,mBAAK;AAId,MAAI,OAAO,iBAAiB,OAAO,0BAA0B;AAC3D,UAAM,gBAAgB,OAAO,iBAAiB,OAAO;AAErD,WAAO,gBAAgB;AACvB,WAAO,2BAA2B;AAElC,WAAO,UAAW,MAAY;AAE5B,UAAI;AACJ,UAAI;AACJ,YAAM,UAAU,IAAI,QAAa,CAAC,gBAAgB,kBAAkB;AAClE,kBAAU;AACV,iBAAS;AAAA,MACX,CAAC;AACD,uBAAiB,UAAU,EAAE,SAAS,SAAmB,OAAgB;AAEzE,aAAO,MAAM;AAAA,IACf;AAGA,WAAO,SAAU,CAAC,UAAoD;AAEpE,YAAM,YAAY;AAAA,QAChB,QAAQ,MAAM;AAAA,QACd,MAAM,MAAM;AAAA,QACZ,QAAQ,MAAM;AAAA,QACd,SAAS,MAAM,WAAW,cAAc,iBAAiB,QAAS,UAAU;AAAA,QAC5E,SAAS,MAAM,WAAW,cAAc,iBAAiB,QAAS,UAAU;AAAA,MAC9E;AAGA,YAAM,qBAAqB,CACzB,QAGyE;AA9LjF;AA+LQ,iBAAO,YAAO,eAAP,mBAAmB,YAAW;AAAA,MACvC;AAGA,UAAI,eAAe;AACjB,YAAI,mBAAmB,aAAa,GAAG;AACrC,iBAAO,cAAc,SAA2C;AAAA,QAClE,OAAO;AACL,iBAAO,cAAc,SAAqC;AAAA,QAC5D;AAAA,MACF;AAGA,aAAO,cAAc,QAAQ;AAAA,IAC/B;AAAA,EACF;AAKA,MAAI,iBAAiB,QAAW;AAC9B,QAAI,QAAQ,MAAM,OAAO,GAAG;AAC1B,cAAQ,MAAM,OAAO,EAAE,UAAU,OAAO;AACxC,UAAI,OAAO,OAAO,WAAW,YAAY;AACvC,YAAI,oBAAoB,YAAY,MAAM;AACxC,8BAAoB,QAAQ,QAAQ,OAAO,IAAI,IAAI,OAAO;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,YAAU,MAAM;AACd,cAAU,MAAM,SAAS,MAAa;AACtC,QAAI,oBAAoB,YAAY,QAAQ,OAAO,WAAW,QAAW;AACvE,0BAAoB,QAAQ,QAAQ,OAAO,IAAI,IAAI,OAAO;AAAA,IAC5D;AACA,WAAO,MAAM;AAGX,mBAAa,MAAM,OAAO;AAAA,IAC5B;AAAA,EACF,GAAG;AAAA,IACD;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA,IACP,OAAO;AAAA;AAAA;AAAA,IAGP,KAAK,UAAU,OAAO,UAAU;AAAA;AAAA,IAEhC,OAAO,OAAO,WAAW,WAAW,OAAO,SAAS;AAAA;AAAA,IAEpD,GAAI,gBAAgB,CAAC;AAAA,EACvB,CAAC;AACH;","names":[]}