@copilotkit/react-core 1.2.0 → 1.2.2-feat-runtime-remote-actions.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 (126) hide show
  1. package/CHANGELOG.md +45 -0
  2. package/dist/{chunk-QR4XKQOA.mjs → chunk-326LK7LX.mjs} +2 -2
  3. package/dist/{chunk-EVK5346D.mjs → chunk-3U22BXKC.mjs} +4 -3
  4. package/dist/chunk-3U22BXKC.mjs.map +1 -0
  5. package/dist/{chunk-GSL4ZHUB.mjs → chunk-A37GANOW.mjs} +4 -4
  6. package/dist/chunk-A37GANOW.mjs.map +1 -0
  7. package/dist/chunk-BWYAGPEF.mjs +1 -0
  8. package/dist/{chunk-LB53QWLY.mjs → chunk-CODXG6KU.mjs} +2 -2
  9. package/dist/{chunk-LB7ULLSU.mjs → chunk-J2YXDQHR.mjs} +14 -3
  10. package/dist/chunk-J2YXDQHR.mjs.map +1 -0
  11. package/dist/chunk-Q4TTTAXQ.mjs +87 -0
  12. package/dist/chunk-Q4TTTAXQ.mjs.map +1 -0
  13. package/dist/{chunk-CFCRJA63.mjs → chunk-RBNULK3U.mjs} +39 -5
  14. package/dist/chunk-RBNULK3U.mjs.map +1 -0
  15. package/dist/{chunk-PZOEBYWP.mjs → chunk-RWPGGPW5.mjs} +63 -11
  16. package/dist/chunk-RWPGGPW5.mjs.map +1 -0
  17. package/dist/chunk-STUXJ3BN.mjs +44 -0
  18. package/dist/chunk-STUXJ3BN.mjs.map +1 -0
  19. package/dist/{chunk-HUC6EZVP.mjs → chunk-TCZBK3HZ.mjs} +7 -4
  20. package/dist/chunk-TCZBK3HZ.mjs.map +1 -0
  21. package/dist/{chunk-AIW2RAN2.mjs → chunk-VCEOT4GG.mjs} +35 -6
  22. package/dist/chunk-VCEOT4GG.mjs.map +1 -0
  23. package/dist/components/copilot-provider/copilotkit-props.d.ts +4 -0
  24. package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
  25. package/dist/components/copilot-provider/copilotkit.js +50 -5
  26. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  27. package/dist/components/copilot-provider/copilotkit.mjs +2 -2
  28. package/dist/components/copilot-provider/index.js +50 -5
  29. package/dist/components/copilot-provider/index.js.map +1 -1
  30. package/dist/components/copilot-provider/index.mjs +2 -2
  31. package/dist/components/index.js +50 -5
  32. package/dist/components/index.js.map +1 -1
  33. package/dist/components/index.mjs +2 -2
  34. package/dist/context/copilot-context.d.ts +21 -2
  35. package/dist/context/copilot-context.js +13 -2
  36. package/dist/context/copilot-context.js.map +1 -1
  37. package/dist/context/copilot-context.mjs +1 -1
  38. package/dist/context/index.d.ts +2 -0
  39. package/dist/context/index.js +13 -2
  40. package/dist/context/index.js.map +1 -1
  41. package/dist/context/index.mjs +1 -1
  42. package/dist/hooks/index.d.ts +4 -0
  43. package/dist/hooks/index.js +224 -21
  44. package/dist/hooks/index.js.map +1 -1
  45. package/dist/hooks/index.mjs +17 -8
  46. package/dist/hooks/use-chat.d.ts +26 -4
  47. package/dist/hooks/use-chat.js +58 -9
  48. package/dist/hooks/use-chat.js.map +1 -1
  49. package/dist/hooks/use-chat.mjs +1 -1
  50. package/dist/hooks/use-coagent-action.d.ts +5 -0
  51. package/dist/hooks/use-coagent-action.js +156 -0
  52. package/dist/hooks/use-coagent-action.js.map +1 -0
  53. package/dist/hooks/use-coagent-action.mjs +9 -0
  54. package/dist/hooks/use-coagent-action.mjs.map +1 -0
  55. package/dist/hooks/use-coagent.d.ts +27 -0
  56. package/dist/hooks/use-coagent.js +219 -0
  57. package/dist/hooks/use-coagent.js.map +1 -0
  58. package/dist/hooks/use-coagent.mjs +10 -0
  59. package/dist/hooks/use-coagent.mjs.map +1 -0
  60. package/dist/hooks/use-copilot-action.js +15 -4
  61. package/dist/hooks/use-copilot-action.js.map +1 -1
  62. package/dist/hooks/use-copilot-action.mjs +2 -2
  63. package/dist/hooks/use-copilot-chat.js +101 -13
  64. package/dist/hooks/use-copilot-chat.js.map +1 -1
  65. package/dist/hooks/use-copilot-chat.mjs +4 -4
  66. package/dist/hooks/use-copilot-readable.js +13 -2
  67. package/dist/hooks/use-copilot-readable.js.map +1 -1
  68. package/dist/hooks/use-copilot-readable.mjs +2 -2
  69. package/dist/hooks/use-make-copilot-document-readable.js +13 -2
  70. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  71. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  72. package/dist/index.d.ts +4 -0
  73. package/dist/index.js +268 -31
  74. package/dist/index.js.map +1 -1
  75. package/dist/index.mjs +20 -12
  76. package/dist/lib/copilot-task.d.ts +2 -0
  77. package/dist/lib/copilot-task.js +1 -1
  78. package/dist/lib/copilot-task.js.map +1 -1
  79. package/dist/lib/copilot-task.mjs +3 -3
  80. package/dist/lib/index.d.ts +2 -0
  81. package/dist/lib/index.js +1 -1
  82. package/dist/lib/index.js.map +1 -1
  83. package/dist/lib/index.mjs +3 -3
  84. package/dist/types/coagent-action.d.ts +17 -0
  85. package/dist/types/coagent-action.js +19 -0
  86. package/dist/types/coagent-action.js.map +1 -0
  87. package/dist/types/coagent-action.mjs +1 -0
  88. package/dist/types/coagent-action.mjs.map +1 -0
  89. package/dist/types/coagent-state.d.ts +11 -0
  90. package/dist/types/coagent-state.js +19 -0
  91. package/dist/types/coagent-state.js.map +1 -0
  92. package/dist/types/coagent-state.mjs +1 -0
  93. package/dist/types/coagent-state.mjs.map +1 -0
  94. package/dist/utils/extract.d.ts +2 -0
  95. package/dist/utils/extract.js +1 -1
  96. package/dist/utils/extract.js.map +1 -1
  97. package/dist/utils/extract.mjs +3 -3
  98. package/dist/utils/index.d.ts +2 -0
  99. package/dist/utils/index.js +1 -1
  100. package/dist/utils/index.js.map +1 -1
  101. package/dist/utils/index.mjs +3 -3
  102. package/package.json +5 -5
  103. package/src/components/copilot-provider/copilotkit-props.tsx +5 -0
  104. package/src/components/copilot-provider/copilotkit.tsx +45 -3
  105. package/src/context/copilot-context.tsx +39 -2
  106. package/src/hooks/index.ts +2 -0
  107. package/src/hooks/use-chat.ts +111 -11
  108. package/src/hooks/use-coagent-action.ts +44 -0
  109. package/src/hooks/use-coagent.ts +133 -0
  110. package/src/hooks/use-copilot-action.ts +2 -2
  111. package/src/hooks/use-copilot-chat.ts +31 -0
  112. package/src/lib/copilot-task.ts +2 -1
  113. package/src/types/coagent-action.ts +17 -0
  114. package/src/types/coagent-state.ts +9 -0
  115. package/src/utils/extract.ts +7 -2
  116. package/dist/chunk-5JB4B2SV.mjs +0 -1
  117. package/dist/chunk-AIW2RAN2.mjs.map +0 -1
  118. package/dist/chunk-CFCRJA63.mjs.map +0 -1
  119. package/dist/chunk-EVK5346D.mjs.map +0 -1
  120. package/dist/chunk-GSL4ZHUB.mjs.map +0 -1
  121. package/dist/chunk-HUC6EZVP.mjs.map +0 -1
  122. package/dist/chunk-LB7ULLSU.mjs.map +0 -1
  123. package/dist/chunk-PZOEBYWP.mjs.map +0 -1
  124. /package/dist/{chunk-QR4XKQOA.mjs.map → chunk-326LK7LX.mjs.map} +0 -0
  125. /package/dist/{chunk-5JB4B2SV.mjs.map → chunk-BWYAGPEF.mjs.map} +0 -0
  126. /package/dist/{chunk-LB53QWLY.mjs.map → chunk-CODXG6KU.mjs.map} +0 -0
@@ -73,4 +73,9 @@ export interface CopilotKitProps {
73
73
  * If set to "auto", the dev console will be show on localhost only.
74
74
  */
75
75
  showDevConsole?: boolean | "auto";
76
+
77
+ /**
78
+ * The name of the agent to use.
79
+ */
80
+ agent?: string;
76
81
  }
@@ -35,6 +35,8 @@ import {
35
35
  CopilotContext,
36
36
  CopilotApiConfig,
37
37
  InChatRenderFunction,
38
+ ChatComponentsCache,
39
+ AgentSession,
38
40
  } from "../../context/copilot-context";
39
41
  import useTree from "../../hooks/use-tree";
40
42
  import { CopilotChatSuggestionConfiguration, DocumentPointer } from "../../types";
@@ -44,11 +46,13 @@ import {
44
46
  CopilotCloudConfig,
45
47
  FunctionCallHandler,
46
48
  } from "@copilotkit/shared";
47
- import { Message } from "@copilotkit/runtime-client-gql";
49
+ import { AgentStateMessage, Message } from "@copilotkit/runtime-client-gql";
48
50
 
49
51
  import { FrontendAction } from "../../types/frontend-action";
50
52
  import useFlatCategoryStore from "../../hooks/use-flat-category-store";
51
53
  import { CopilotKitProps } from "./copilotkit-props";
54
+ import { CoagentAction } from "../../types/coagent-action";
55
+ import { CoagentState } from "../../types/coagent-state";
52
56
 
53
57
  export function CopilotKit({ children, ...props }: CopilotKitProps) {
54
58
  // Compute all the functions and properties that we need to pass
@@ -63,7 +67,11 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
63
67
  const chatApiEndpoint = props.runtimeUrl || COPILOT_CLOUD_CHAT_URL;
64
68
 
65
69
  const [actions, setActions] = useState<Record<string, FrontendAction<any>>>({});
66
- const chatComponentsCache = useRef<Record<string, InChatRenderFunction | string>>({});
70
+ const [coagentActions, setCoagentActions] = useState<Record<string, CoagentAction<any>>>({});
71
+ const chatComponentsCache = useRef<ChatComponentsCache>({
72
+ actions: {},
73
+ coagentActions: {},
74
+ });
67
75
  const { addElement, removeElement, printTree } = useTree();
68
76
  const [messages, setMessages] = useState<Message[]>([]);
69
77
  const [isLoading, setIsLoading] = useState(false);
@@ -92,6 +100,23 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
92
100
  });
93
101
  }, []);
94
102
 
103
+ const setCoagentAction = useCallback((id: string, action: CoagentAction<any>) => {
104
+ setCoagentActions((prevPoints) => {
105
+ return {
106
+ ...prevPoints,
107
+ [id]: action,
108
+ };
109
+ });
110
+ }, []);
111
+
112
+ const removeCoagentAction = useCallback((id: string) => {
113
+ setCoagentActions((prevPoints) => {
114
+ const newPoints = { ...prevPoints };
115
+ delete newPoints[id];
116
+ return newPoints;
117
+ });
118
+ }, []);
119
+
95
120
  const getContextString = useCallback(
96
121
  (documents: DocumentPointer[], categories: string[]) => {
97
122
  const documentsString = documents
@@ -206,6 +231,16 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
206
231
  });
207
232
  };
208
233
 
234
+ const [coagentStates, setCoagentStates] = useState<Record<string, CoagentState>>({});
235
+ let initialAgentSession: AgentSession | null = null;
236
+ if (props.agent) {
237
+ initialAgentSession = {
238
+ agentName: props.agent,
239
+ };
240
+ }
241
+
242
+ const [agentSession, setAgentSession] = useState<AgentSession | null>(initialAgentSession);
243
+
209
244
  return (
210
245
  <CopilotContext.Provider
211
246
  value={{
@@ -214,6 +249,9 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
214
249
  getFunctionCallHandler,
215
250
  setAction,
216
251
  removeAction,
252
+ coagentActions,
253
+ setCoagentAction,
254
+ removeCoagentAction,
217
255
  getContextString,
218
256
  addContext,
219
257
  removeContext,
@@ -231,6 +269,10 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
231
269
  chatInstructions,
232
270
  setChatInstructions,
233
271
  showDevConsole: props.showDevConsole === undefined ? "auto" : props.showDevConsole,
272
+ coagentStates,
273
+ setCoagentStates,
274
+ agentSession,
275
+ setAgentSession,
234
276
  }}
235
277
  >
236
278
  {children}
@@ -253,7 +295,7 @@ function entryPointsToFunctionCallHandler(actions: FrontendAction<any>[]): Funct
253
295
  await new Promise<void>((resolve, reject) => {
254
296
  flushSync(async () => {
255
297
  try {
256
- result = await action.handler(args);
298
+ result = await action.handler?.(args);
257
299
  resolve();
258
300
  } catch (error) {
259
301
  reject(error);
@@ -5,6 +5,8 @@ import React from "react";
5
5
  import { TreeNodeId } from "../hooks/use-tree";
6
6
  import { DocumentPointer } from "../types";
7
7
  import { CopilotChatSuggestionConfiguration } from "../types/chat-suggestion-configuration";
8
+ import { CoagentAction, CoagentActionRenderProps } from "../types/coagent-action";
9
+ import { CoagentState } from "../types/coagent-state";
8
10
 
9
11
  /**
10
12
  * Interface for the configuration of the Copilot API.
@@ -67,13 +69,33 @@ export interface CopilotApiConfig {
67
69
  }
68
70
 
69
71
  export type InChatRenderFunction = (props: ActionRenderProps<any>) => string | JSX.Element;
72
+ export type CoagentInChatRenderFunction = (
73
+ props: CoagentActionRenderProps<any>,
74
+ ) => string | JSX.Element;
75
+
76
+ export interface ChatComponentsCache {
77
+ actions: Record<string, InChatRenderFunction | string>;
78
+ coagentActions: Record<string, CoagentInChatRenderFunction | string>;
79
+ }
80
+
81
+ export interface AgentSession {
82
+ agentName: string;
83
+ threadId?: string;
84
+ nodeName?: string;
85
+ }
70
86
 
71
87
  export interface CopilotContextParams {
72
88
  // function-calling
73
89
  actions: Record<string, FrontendAction<any>>;
74
90
  setAction: (id: string, action: FrontendAction<any>) => void;
75
91
  removeAction: (id: string) => void;
76
- chatComponentsCache: React.RefObject<Record<string, InChatRenderFunction | string>>;
92
+
93
+ // coagent actions
94
+ coagentActions: Record<string, CoagentAction<any>>;
95
+ setCoagentAction: (id: string, action: CoagentAction<any>) => void;
96
+ removeCoagentAction: (id: string) => void;
97
+
98
+ chatComponentsCache: React.RefObject<ChatComponentsCache>;
77
99
 
78
100
  getFunctionCallHandler: (
79
101
  customEntryPoints?: Record<string, FrontendAction<any>>,
@@ -110,6 +132,12 @@ export interface CopilotContextParams {
110
132
  copilotApiConfig: CopilotApiConfig;
111
133
 
112
134
  showDevConsole: boolean | "auto";
135
+
136
+ // agents
137
+ coagentStates: Record<string, CoagentState>;
138
+ setCoagentStates: React.Dispatch<React.SetStateAction<Record<string, CoagentState>>>;
139
+ agentSession: AgentSession | null;
140
+ setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;
113
141
  }
114
142
 
115
143
  const emptyCopilotContext: CopilotContextParams = {
@@ -117,7 +145,11 @@ const emptyCopilotContext: CopilotContextParams = {
117
145
  setAction: () => {},
118
146
  removeAction: () => {},
119
147
 
120
- chatComponentsCache: { current: {} },
148
+ coagentActions: {},
149
+ setCoagentAction: () => {},
150
+ removeCoagentAction: () => {},
151
+
152
+ chatComponentsCache: { current: { actions: {}, coagentActions: {} } },
121
153
  getContextString: (documents: DocumentPointer[], categories: string[]) =>
122
154
  returnAndThrowInDebug(""),
123
155
  addContext: () => "",
@@ -155,6 +187,11 @@ const emptyCopilotContext: CopilotContextParams = {
155
187
  addChatSuggestionConfiguration: () => {},
156
188
  removeChatSuggestionConfiguration: () => {},
157
189
  showDevConsole: "auto",
190
+ coagentStates: {},
191
+ setCoagentStates: () => {},
192
+
193
+ agentSession: null,
194
+ setAgentSession: () => {},
158
195
  };
159
196
 
160
197
  export const CopilotContext = React.createContext<CopilotContextParams>(emptyCopilotContext);
@@ -3,6 +3,8 @@ export type { UseCopilotChatOptions } from "./use-copilot-chat";
3
3
  export type { UseCopilotChatReturn } from "./use-copilot-chat";
4
4
 
5
5
  export { useCopilotAction } from "./use-copilot-action";
6
+ export { useCoAgentAction } from "./use-coagent-action";
6
7
  export { useMakeCopilotDocumentReadable } from "./use-make-copilot-document-readable";
7
8
  export { type UseChatHelpers } from "./use-chat";
8
9
  export { useCopilotReadable } from "./use-copilot-readable";
10
+ export { useCoAgent } from "./use-coagent";
@@ -2,8 +2,8 @@ import { useRef } from "react";
2
2
  import {
3
3
  FunctionCallHandler,
4
4
  COPILOT_CLOUD_PUBLIC_API_KEY_HEADER,
5
- Action,
6
5
  actionParametersToJsonSchema,
6
+ CoagentActionHandler,
7
7
  } from "@copilotkit/shared";
8
8
  import {
9
9
  Message,
@@ -12,14 +12,20 @@ import {
12
12
  ResultMessage,
13
13
  CopilotRuntimeClient,
14
14
  convertMessagesToGqlInput,
15
+ filterAdjacentAgentStateMessages,
16
+ filterAgentStateMessages,
15
17
  convertGqlOutputToMessages,
16
18
  MessageStatusCode,
17
19
  MessageRole,
18
20
  Role,
19
21
  CopilotRequestType,
22
+ AgentStateMessage,
20
23
  } from "@copilotkit/runtime-client-gql";
21
24
 
22
25
  import { CopilotApiConfig } from "../context";
26
+ import { FrontendAction } from "../types/frontend-action";
27
+ import { CoagentState } from "../types/coagent-state";
28
+ import { AgentSession } from "../context/copilot-context";
23
29
 
24
30
  export type UseChatOptions = {
25
31
  /**
@@ -32,10 +38,16 @@ export type UseChatOptions = {
32
38
  * automatically to the API and will be used to update the chat.
33
39
  */
34
40
  onFunctionCall?: FunctionCallHandler;
41
+
42
+ /**
43
+ * Callback function to be called when a coagent action is received.
44
+ */
45
+ onCoagentAction?: CoagentActionHandler;
46
+
35
47
  /**
36
48
  * Function definitions to be sent to the API.
37
49
  */
38
- actions: Action[];
50
+ actions: FrontendAction<any>[];
39
51
 
40
52
  /**
41
53
  * The CopilotKit API configuration.
@@ -65,6 +77,26 @@ export type UseChatOptions = {
65
77
  * setState-powered method to update the isChatLoading value
66
78
  */
67
79
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
80
+
81
+ /**
82
+ * The current list of coagent states.
83
+ */
84
+ coagentStates: Record<string, CoagentState>;
85
+
86
+ /**
87
+ * setState-powered method to update the agent states
88
+ */
89
+ setCoagentStates: React.Dispatch<React.SetStateAction<Record<string, CoagentState>>>;
90
+
91
+ /**
92
+ * The current agent session.
93
+ */
94
+ agentSession: AgentSession | null;
95
+
96
+ /**
97
+ * setState-powered method to update the agent session
98
+ */
99
+ setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;
68
100
  };
69
101
 
70
102
  export type UseChatHelpers = {
@@ -97,11 +129,19 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
97
129
  isLoading,
98
130
  actions,
99
131
  onFunctionCall,
132
+ onCoagentAction,
133
+ setCoagentStates,
134
+ coagentStates,
135
+ agentSession,
136
+ setAgentSession,
100
137
  } = options;
138
+
101
139
  const abortControllerRef = useRef<AbortController>();
102
140
  const threadIdRef = useRef<string | null>(null);
103
141
  const runIdRef = useRef<string | null>(null);
142
+
104
143
  const publicApiKey = copilotConfig.publicApiKey;
144
+
105
145
  const headers = {
106
146
  ...(copilotConfig.headers || {}),
107
147
  ...(publicApiKey ? { [COPILOT_CLOUD_PUBLIC_API_KEY_HEADER]: publicApiKey } : {}),
@@ -147,7 +187,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
147
187
  },
148
188
  threadId: threadIdRef.current,
149
189
  runId: runIdRef.current,
150
- messages: convertMessagesToGqlInput(messagesWithContext),
190
+ messages: convertMessagesToGqlInput(filterAgentStateMessages(messagesWithContext)),
151
191
  ...(copilotConfig.cloud
152
192
  ? {
153
193
  cloud: {
@@ -169,6 +209,15 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
169
209
  metadata: {
170
210
  requestType: CopilotRequestType.Chat,
171
211
  },
212
+ ...(agentSession
213
+ ? {
214
+ agentSession,
215
+ }
216
+ : {}),
217
+ agentStates: Object.values(coagentStates).map((state) => ({
218
+ agentName: state.name,
219
+ state: JSON.stringify(state.state),
220
+ })),
172
221
  },
173
222
  properties: copilotConfig.properties,
174
223
  signal: abortControllerRef.current?.signal,
@@ -180,7 +229,8 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
180
229
 
181
230
  const reader = stream.getReader();
182
231
 
183
- let results: { [id: string]: string } = {};
232
+ let actionResults: { [id: string]: string } = {};
233
+ let executedCoagentActions: string[] = [];
184
234
 
185
235
  try {
186
236
  while (true) {
@@ -197,7 +247,9 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
197
247
  threadIdRef.current = value.generateCopilotResponse.threadId || null;
198
248
  runIdRef.current = value.generateCopilotResponse.runId || null;
199
249
 
200
- const messages = convertGqlOutputToMessages(value.generateCopilotResponse.messages);
250
+ const messages = convertGqlOutputToMessages(
251
+ filterAdjacentAgentStateMessages(value.generateCopilotResponse.messages),
252
+ );
201
253
 
202
254
  if (messages.length === 0) {
203
255
  continue;
@@ -222,14 +274,14 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
222
274
  else {
223
275
  for (const message of messages) {
224
276
  newMessages.push(message);
225
-
277
+ // execute regular action executions
226
278
  if (
227
279
  message instanceof ActionExecutionMessage &&
228
280
  message.status.code !== MessageStatusCode.Pending &&
229
281
  message.scope === "client" &&
230
282
  onFunctionCall
231
283
  ) {
232
- if (!(message.id in results)) {
284
+ if (!(message.id in actionResults)) {
233
285
  // Do not execute a function call if guardrails are enabled but the status is not known
234
286
  if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
235
287
  break;
@@ -240,29 +292,76 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
240
292
  name: message.name,
241
293
  args: message.arguments,
242
294
  });
243
- results[message.id] = result;
295
+ actionResults[message.id] = result;
244
296
  }
245
-
246
297
  // add the result message
247
298
  newMessages.push(
248
299
  new ResultMessage({
249
- result: ResultMessage.encodeResult(results[message.id]),
300
+ result: ResultMessage.encodeResult(actionResults[message.id]),
250
301
  actionExecutionId: message.id,
251
302
  actionName: message.name,
252
303
  }),
253
304
  );
254
305
  }
306
+ // execute coagent actions
307
+ if (
308
+ message instanceof AgentStateMessage &&
309
+ !message.active &&
310
+ !executedCoagentActions.includes(message.id) &&
311
+ onCoagentAction
312
+ ) {
313
+ // Do not execute a coagent action if guardrails are enabled but the status is not known
314
+ if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
315
+ break;
316
+ }
317
+ // execute coagent action
318
+ await onCoagentAction({
319
+ name: message.agentName,
320
+ nodeName: message.nodeName,
321
+ state: message.state,
322
+ });
323
+ executedCoagentActions.push(message.id);
324
+ }
325
+ }
326
+
327
+ const lastAgentStateMessage = [...messages]
328
+ .reverse()
329
+ .find((message) => message instanceof AgentStateMessage);
330
+
331
+ if (lastAgentStateMessage) {
332
+ if (lastAgentStateMessage.running) {
333
+ setCoagentStates((prevAgentStates) => ({
334
+ ...prevAgentStates,
335
+ [lastAgentStateMessage.agentName]: {
336
+ name: lastAgentStateMessage.agentName,
337
+ state: lastAgentStateMessage.state,
338
+ running: lastAgentStateMessage.running,
339
+ active: lastAgentStateMessage.active,
340
+ threadId: lastAgentStateMessage.threadId,
341
+ nodeName: lastAgentStateMessage.nodeName,
342
+ runId: lastAgentStateMessage.runId,
343
+ },
344
+ }));
345
+ setAgentSession({
346
+ threadId: lastAgentStateMessage.threadId,
347
+ agentName: lastAgentStateMessage.agentName,
348
+ nodeName: lastAgentStateMessage.nodeName,
349
+ });
350
+ } else {
351
+ setAgentSession(null);
352
+ }
255
353
  }
256
354
  }
257
355
 
258
356
  if (newMessages.length > 0) {
357
+ // Update message state
259
358
  setMessages([...previousMessages, ...newMessages]);
260
359
  }
261
360
  }
262
361
 
263
362
  if (
264
363
  // if we have client side results
265
- Object.values(results).length ||
364
+ Object.values(actionResults).length ||
266
365
  // or the last message we received is a result
267
366
  (newMessages.length && newMessages[newMessages.length - 1] instanceof ResultMessage)
268
367
  ) {
@@ -289,6 +388,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
289
388
  if (isLoading) {
290
389
  return;
291
390
  }
391
+
292
392
  const newMessages = [...messages, message];
293
393
  setMessages(newMessages);
294
394
  return runChatCompletionAndHandleFunctionCall(newMessages);
@@ -0,0 +1,44 @@
1
+ import { useRef, useContext, useEffect } from "react";
2
+ import { CopilotContext } from "../context/copilot-context";
3
+ import { randomId } from "@copilotkit/shared";
4
+ import { CoagentAction } from "../types/coagent-action";
5
+
6
+ // We implement useCoAgentAction dependency handling so that
7
+ // the developer has the option to not provide any dependencies.
8
+ // see useCopilotAction for more details about this approach.
9
+ export function useCoAgentAction<T = any>(action: CoagentAction<T>, dependencies?: any[]): void {
10
+ const { setCoagentAction, removeCoagentAction, coagentActions, chatComponentsCache } =
11
+ useContext(CopilotContext);
12
+ const idRef = useRef<string>(randomId());
13
+
14
+ const key = `${action.name}-${action.nodeName || "global"}`;
15
+
16
+ if (dependencies === undefined) {
17
+ if (coagentActions[idRef.current]) {
18
+ coagentActions[idRef.current].handler = action.handler as any;
19
+ if (typeof action.render === "function") {
20
+ if (chatComponentsCache.current !== null) {
21
+ chatComponentsCache.current.coagentActions[key] = action.render;
22
+ }
23
+ }
24
+ }
25
+ }
26
+
27
+ useEffect(() => {
28
+ setCoagentAction(idRef.current, action as any);
29
+ if (chatComponentsCache.current !== null && action.render !== undefined) {
30
+ chatComponentsCache.current.coagentActions[key] = action.render;
31
+ }
32
+ return () => {
33
+ removeCoagentAction(idRef.current);
34
+ };
35
+ }, [
36
+ setCoagentAction,
37
+ removeCoagentAction,
38
+ action.name,
39
+ // include render only if it's a string
40
+ typeof action.render === "string" ? action.render : undefined,
41
+ // dependencies set by the developer
42
+ ...(dependencies || []),
43
+ ]);
44
+ }
@@ -0,0 +1,133 @@
1
+ import { useEffect } from "react";
2
+ import { useCopilotContext } from "../context";
3
+ import { CoagentState } from "../types/coagent-state";
4
+
5
+ interface WithInternalStateManagementAndInitial<T> {
6
+ name: string;
7
+ initialState: T;
8
+ }
9
+
10
+ interface WithInternalStateManagement {
11
+ name: string;
12
+ initialState?: any; // Optional initialState with default type any
13
+ }
14
+
15
+ interface WithExternalStateManagement<T> {
16
+ name: string;
17
+ state: T;
18
+ setState: (newState: T | ((prevState: T | undefined) => T)) => void;
19
+ }
20
+
21
+ type UseCoagentOptions<T> =
22
+ | WithInternalStateManagementAndInitial<T>
23
+ | WithInternalStateManagement
24
+ | WithExternalStateManagement<T>;
25
+
26
+ export interface UseCoagentReturnType<T> {
27
+ name: string;
28
+ nodeName?: string;
29
+ threadId?: string;
30
+ running: boolean;
31
+ state: T;
32
+ setState: (newState: T | ((prevState: T | undefined) => T)) => void;
33
+ start: () => void;
34
+ stop: () => void;
35
+ }
36
+
37
+ export function useCoAgent<T = any>(options: UseCoagentOptions<T>): UseCoagentReturnType<T> {
38
+ const isExternalStateManagement = (
39
+ options: UseCoagentOptions<T>,
40
+ ): options is WithExternalStateManagement<T> => {
41
+ return "state" in options && "setState" in options;
42
+ };
43
+
44
+ const { name } = options;
45
+
46
+ const isInternalStateManagementWithInitial = (
47
+ options: UseCoagentOptions<T>,
48
+ ): options is WithInternalStateManagementAndInitial<T> => {
49
+ return "initialState" in options;
50
+ };
51
+
52
+ const { coagentStates, setCoagentStates } = useCopilotContext();
53
+
54
+ const getCoagentState = (coagentStates: Record<string, CoagentState>, name: string) => {
55
+ if (coagentStates[name]) {
56
+ return coagentStates[name];
57
+ } else {
58
+ return {
59
+ name,
60
+ state: isInternalStateManagementWithInitial(options) ? options.initialState : {},
61
+ running: false,
62
+ active: false,
63
+ threadId: undefined,
64
+ nodeName: undefined,
65
+ runId: undefined,
66
+ };
67
+ }
68
+ };
69
+
70
+ // if we manage state internally, we need to provide a function to set the state
71
+ const setState = (newState: T | ((prevState: T | undefined) => T)) => {
72
+ setCoagentStates((prevAgentStates) => {
73
+ let coagentState: CoagentState = getCoagentState(prevAgentStates, name);
74
+
75
+ const updatedState =
76
+ typeof newState === "function" ? (newState as Function)(coagentState.state) : newState;
77
+
78
+ return {
79
+ ...prevAgentStates,
80
+ [name]: {
81
+ ...coagentState,
82
+ state: updatedState,
83
+ },
84
+ };
85
+ });
86
+ };
87
+
88
+ const coagentState = getCoagentState(coagentStates, name);
89
+
90
+ const state = isExternalStateManagement(options) ? options.state : coagentState.state;
91
+
92
+ // Sync internal state with external state if state management is external
93
+ useEffect(() => {
94
+ if (isExternalStateManagement(options)) {
95
+ setState(options.state);
96
+ } else if (coagentStates[name] === undefined) {
97
+ setState(options.initialState === undefined ? {} : options.initialState);
98
+ }
99
+ }, [isExternalStateManagement(options) ? JSON.stringify(options.state) : undefined]);
100
+
101
+ // Return the state and setState function
102
+ return {
103
+ name,
104
+ nodeName: coagentState.nodeName,
105
+ state,
106
+ setState,
107
+ running: coagentState.running,
108
+ start: () => {
109
+ startAgent(name);
110
+ },
111
+ stop: () => {
112
+ stopAgent(name);
113
+ },
114
+ };
115
+ }
116
+
117
+ function startAgent(name: string) {
118
+ const { setAgentSession } = useCopilotContext();
119
+ setAgentSession({
120
+ agentName: name,
121
+ });
122
+ }
123
+
124
+ function stopAgent(name: string) {
125
+ const { agentSession, setAgentSession } = useCopilotContext();
126
+ if (agentSession && agentSession.agentName === name) {
127
+ setAgentSession(null);
128
+ } else {
129
+ console.warn(`No agent session found for ${name}`);
130
+ }
131
+ }
132
+
133
+ // <CopilotKit agent="lockedInAgentName" />
@@ -27,7 +27,7 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
27
27
  actions[idRef.current].handler = action.handler as any;
28
28
  if (typeof action.render === "function") {
29
29
  if (chatComponentsCache.current !== null) {
30
- chatComponentsCache.current[action.name] = action.render;
30
+ chatComponentsCache.current.actions[action.name] = action.render;
31
31
  }
32
32
  }
33
33
  }
@@ -39,7 +39,7 @@ export function useCopilotAction<const T extends Parameter[] | [] = []>(
39
39
  }
40
40
  setAction(idRef.current, action as any);
41
41
  if (chatComponentsCache.current !== null && action.render !== undefined) {
42
- chatComponentsCache.current[action.name] = action.render;
42
+ chatComponentsCache.current.actions[action.name] = action.render;
43
43
  }
44
44
  return () => {
45
45
  // NOTE: For now, we don't remove the chatComponentsCache entry when the action is removed.