@copilotkit/react-core 1.1.2 → 1.1.3-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 (135) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +32 -37
  3. package/dist/{chunk-T6L4EGTD.mjs → chunk-326LK7LX.mjs} +5 -5
  4. package/dist/chunk-326LK7LX.mjs.map +1 -0
  5. package/dist/{chunk-VFDR4MIF.mjs → chunk-A37GANOW.mjs} +11 -7
  6. package/dist/chunk-A37GANOW.mjs.map +1 -0
  7. package/dist/chunk-BWYAGPEF.mjs +1 -0
  8. package/dist/{chunk-GE7LAL6V.mjs → chunk-CKOTAKUD.mjs} +4 -3
  9. package/dist/{chunk-GE7LAL6V.mjs.map → chunk-CKOTAKUD.mjs.map} +1 -1
  10. package/dist/{chunk-KONDJRB4.mjs → chunk-CODXG6KU.mjs} +5 -5
  11. package/dist/chunk-CODXG6KU.mjs.map +1 -0
  12. package/dist/{chunk-3NHEWJ4V.mjs → chunk-J2YXDQHR.mjs} +19 -4
  13. package/dist/chunk-J2YXDQHR.mjs.map +1 -0
  14. package/dist/{chunk-UQRDVZ2N.mjs → chunk-OBBH5SHN.mjs} +4 -3
  15. package/dist/{chunk-UQRDVZ2N.mjs.map → chunk-OBBH5SHN.mjs.map} +1 -1
  16. package/dist/chunk-Q4TTTAXQ.mjs +87 -0
  17. package/dist/chunk-Q4TTTAXQ.mjs.map +1 -0
  18. package/dist/{chunk-TVR5CJ6E.mjs → chunk-RBNULK3U.mjs} +39 -5
  19. package/dist/chunk-RBNULK3U.mjs.map +1 -0
  20. package/dist/{chunk-AGGKI26A.mjs → chunk-RK27MXAR.mjs} +76 -11
  21. package/dist/chunk-RK27MXAR.mjs.map +1 -0
  22. package/dist/chunk-STUXJ3BN.mjs +44 -0
  23. package/dist/chunk-STUXJ3BN.mjs.map +1 -0
  24. package/dist/{chunk-YYZNR3CS.mjs → chunk-XBJINVNA.mjs} +72 -14
  25. package/dist/chunk-XBJINVNA.mjs.map +1 -0
  26. package/dist/components/copilot-provider/copilotkit-props.d.ts +4 -0
  27. package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
  28. package/dist/components/copilot-provider/copilotkit.d.ts +2 -1
  29. package/dist/components/copilot-provider/copilotkit.js +50 -5
  30. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  31. package/dist/components/copilot-provider/copilotkit.mjs +2 -2
  32. package/dist/components/copilot-provider/index.d.ts +1 -0
  33. package/dist/components/copilot-provider/index.js +50 -5
  34. package/dist/components/copilot-provider/index.js.map +1 -1
  35. package/dist/components/copilot-provider/index.mjs +2 -2
  36. package/dist/components/index.d.ts +1 -0
  37. package/dist/components/index.js +50 -5
  38. package/dist/components/index.js.map +1 -1
  39. package/dist/components/index.mjs +2 -2
  40. package/dist/context/copilot-context.d.ts +21 -2
  41. package/dist/context/copilot-context.js +18 -3
  42. package/dist/context/copilot-context.js.map +1 -1
  43. package/dist/context/copilot-context.mjs +1 -1
  44. package/dist/context/index.d.ts +2 -0
  45. package/dist/context/index.js +18 -3
  46. package/dist/context/index.js.map +1 -1
  47. package/dist/context/index.mjs +1 -1
  48. package/dist/hooks/index.d.ts +4 -0
  49. package/dist/hooks/index.js +288 -30
  50. package/dist/hooks/index.js.map +1 -1
  51. package/dist/hooks/index.mjs +21 -12
  52. package/dist/hooks/use-chat.d.ts +26 -4
  53. package/dist/hooks/use-chat.js +73 -9
  54. package/dist/hooks/use-chat.js.map +1 -1
  55. package/dist/hooks/use-chat.mjs +1 -1
  56. package/dist/hooks/use-coagent-action.d.ts +5 -0
  57. package/dist/hooks/use-coagent-action.js +156 -0
  58. package/dist/hooks/use-coagent-action.js.map +1 -0
  59. package/dist/hooks/use-coagent-action.mjs +9 -0
  60. package/dist/hooks/use-coagent-action.mjs.map +1 -0
  61. package/dist/hooks/use-coagent.d.ts +27 -0
  62. package/dist/hooks/use-coagent.js +219 -0
  63. package/dist/hooks/use-coagent.js.map +1 -0
  64. package/dist/hooks/use-coagent.mjs +10 -0
  65. package/dist/hooks/use-coagent.mjs.map +1 -0
  66. package/dist/hooks/use-copilot-action.js +27 -5
  67. package/dist/hooks/use-copilot-action.js.map +1 -1
  68. package/dist/hooks/use-copilot-action.mjs +2 -2
  69. package/dist/hooks/use-copilot-chat.js +158 -19
  70. package/dist/hooks/use-copilot-chat.js.map +1 -1
  71. package/dist/hooks/use-copilot-chat.mjs +4 -4
  72. package/dist/hooks/use-copilot-readable.js +21 -3
  73. package/dist/hooks/use-copilot-readable.js.map +1 -1
  74. package/dist/hooks/use-copilot-readable.mjs +2 -2
  75. package/dist/hooks/use-make-copilot-document-readable.js +21 -3
  76. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  77. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  78. package/dist/index.d.ts +5 -0
  79. package/dist/index.js +332 -41
  80. package/dist/index.js.map +1 -1
  81. package/dist/index.mjs +24 -16
  82. package/dist/lib/copilot-task.d.ts +2 -0
  83. package/dist/lib/copilot-task.js +2 -1
  84. package/dist/lib/copilot-task.js.map +1 -1
  85. package/dist/lib/copilot-task.mjs +3 -3
  86. package/dist/lib/index.d.ts +2 -0
  87. package/dist/lib/index.js +2 -1
  88. package/dist/lib/index.js.map +1 -1
  89. package/dist/lib/index.mjs +3 -3
  90. package/dist/types/coagent-action.d.ts +17 -0
  91. package/dist/types/coagent-action.js +19 -0
  92. package/dist/types/coagent-action.js.map +1 -0
  93. package/dist/types/coagent-action.mjs +1 -0
  94. package/dist/types/coagent-action.mjs.map +1 -0
  95. package/dist/types/coagent-state.d.ts +11 -0
  96. package/dist/types/coagent-state.js +19 -0
  97. package/dist/types/coagent-state.js.map +1 -0
  98. package/dist/types/coagent-state.mjs +1 -0
  99. package/dist/types/coagent-state.mjs.map +1 -0
  100. package/dist/types/frontend-action.d.ts +1 -0
  101. package/dist/types/frontend-action.js.map +1 -1
  102. package/dist/utils/extract.d.ts +2 -0
  103. package/dist/utils/extract.js +2 -1
  104. package/dist/utils/extract.js.map +1 -1
  105. package/dist/utils/extract.mjs +3 -3
  106. package/dist/utils/index.d.ts +2 -0
  107. package/dist/utils/index.js +2 -1
  108. package/dist/utils/index.js.map +1 -1
  109. package/dist/utils/index.mjs +3 -3
  110. package/package.json +5 -5
  111. package/src/components/copilot-provider/copilotkit-props.tsx +5 -0
  112. package/src/components/copilot-provider/copilotkit.tsx +45 -3
  113. package/src/context/copilot-context.tsx +44 -3
  114. package/src/hooks/index.ts +2 -0
  115. package/src/hooks/use-chat.ts +131 -8
  116. package/src/hooks/use-coagent-action.ts +44 -0
  117. package/src/hooks/use-coagent.ts +133 -0
  118. package/src/hooks/use-copilot-action.ts +9 -5
  119. package/src/hooks/use-copilot-chat.ts +80 -8
  120. package/src/hooks/use-copilot-readable.ts +3 -3
  121. package/src/hooks/use-make-copilot-document-readable.ts +3 -3
  122. package/src/lib/copilot-task.ts +1 -0
  123. package/src/types/coagent-action.ts +17 -0
  124. package/src/types/coagent-state.ts +9 -0
  125. package/src/types/frontend-action.ts +1 -0
  126. package/src/utils/extract.ts +1 -0
  127. package/dist/chunk-3NHEWJ4V.mjs.map +0 -1
  128. package/dist/chunk-5JB4B2SV.mjs +0 -1
  129. package/dist/chunk-AGGKI26A.mjs.map +0 -1
  130. package/dist/chunk-KONDJRB4.mjs.map +0 -1
  131. package/dist/chunk-T6L4EGTD.mjs.map +0 -1
  132. package/dist/chunk-TVR5CJ6E.mjs.map +0 -1
  133. package/dist/chunk-VFDR4MIF.mjs.map +0 -1
  134. package/dist/chunk-YYZNR3CS.mjs.map +0 -1
  135. /package/dist/{chunk-5JB4B2SV.mjs.map → chunk-BWYAGPEF.mjs.map} +0 -0
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "publishConfig": {
10
10
  "access": "public"
11
11
  },
12
- "version": "1.1.2",
12
+ "version": "1.1.3-feat-runtime-remote-actions.0",
13
13
  "sideEffects": false,
14
14
  "main": "./dist/index.js",
15
15
  "module": "./dist/index.mjs",
@@ -36,14 +36,14 @@
36
36
  "tsup": "^6.7.0",
37
37
  "typescript": "^5.2.3",
38
38
  "@types/react-dom": "^18.2.4",
39
- "eslint-config-custom": "1.1.1",
40
- "tsconfig": "1.1.1"
39
+ "eslint-config-custom": "1.1.2-feat-runtime-remote-actions.0",
40
+ "tsconfig": "1.1.2-feat-runtime-remote-actions.0"
41
41
  },
42
42
  "dependencies": {
43
43
  "@scarf/scarf": "^1.3.0",
44
44
  "untruncate-json": "^0.0.1",
45
- "@copilotkit/runtime-client-gql": "1.1.2",
46
- "@copilotkit/shared": "1.1.2"
45
+ "@copilotkit/runtime-client-gql": "1.1.3-feat-runtime-remote-actions.0",
46
+ "@copilotkit/shared": "1.1.3-feat-runtime-remote-actions.0"
47
47
  },
48
48
  "keywords": [
49
49
  "copilotkit",
@@ -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,12 +187,21 @@ 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);
161
198
 
162
199
  export function useCopilotContext(): CopilotContextParams {
163
- return React.useContext(CopilotContext);
200
+ const context = React.useContext(CopilotContext);
201
+ if (context === emptyCopilotContext) {
202
+ throw new Error("Remember to wrap your app in a `<CopilotKit> {...} </CopilotKit>` !!!");
203
+ }
204
+ return context;
164
205
  }
165
206
 
166
207
  function returnAndThrowInDebug<T>(value: T): T {
@@ -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,
@@ -17,9 +17,13 @@ import {
17
17
  MessageRole,
18
18
  Role,
19
19
  CopilotRequestType,
20
+ AgentStateMessage,
20
21
  } from "@copilotkit/runtime-client-gql";
21
22
 
22
23
  import { CopilotApiConfig } from "../context";
24
+ import { FrontendAction } from "../types/frontend-action";
25
+ import { CoagentState } from "../types/coagent-state";
26
+ import { AgentSession } from "../context/copilot-context";
23
27
 
24
28
  export type UseChatOptions = {
25
29
  /**
@@ -32,10 +36,16 @@ export type UseChatOptions = {
32
36
  * automatically to the API and will be used to update the chat.
33
37
  */
34
38
  onFunctionCall?: FunctionCallHandler;
39
+
40
+ /**
41
+ * Callback function to be called when a coagent action is received.
42
+ */
43
+ onCoagentAction?: CoagentActionHandler;
44
+
35
45
  /**
36
46
  * Function definitions to be sent to the API.
37
47
  */
38
- actions: Action[];
48
+ actions: FrontendAction<any>[];
39
49
 
40
50
  /**
41
51
  * The CopilotKit API configuration.
@@ -65,6 +75,26 @@ export type UseChatOptions = {
65
75
  * setState-powered method to update the isChatLoading value
66
76
  */
67
77
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
78
+
79
+ /**
80
+ * The current list of coagent states.
81
+ */
82
+ coagentStates: Record<string, CoagentState>;
83
+
84
+ /**
85
+ * setState-powered method to update the agent states
86
+ */
87
+ setCoagentStates: React.Dispatch<React.SetStateAction<Record<string, CoagentState>>>;
88
+
89
+ /**
90
+ * The current agent session.
91
+ */
92
+ agentSession: AgentSession | null;
93
+
94
+ /**
95
+ * setState-powered method to update the agent session
96
+ */
97
+ setAgentSession: React.Dispatch<React.SetStateAction<AgentSession | null>>;
68
98
  };
69
99
 
70
100
  export type UseChatHelpers = {
@@ -97,11 +127,19 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
97
127
  isLoading,
98
128
  actions,
99
129
  onFunctionCall,
130
+ onCoagentAction,
131
+ setCoagentStates,
132
+ coagentStates,
133
+ agentSession,
134
+ setAgentSession,
100
135
  } = options;
136
+
101
137
  const abortControllerRef = useRef<AbortController>();
102
138
  const threadIdRef = useRef<string | null>(null);
103
139
  const runIdRef = useRef<string | null>(null);
140
+
104
141
  const publicApiKey = copilotConfig.publicApiKey;
142
+
105
143
  const headers = {
106
144
  ...(copilotConfig.headers || {}),
107
145
  ...(publicApiKey ? { [COPILOT_CLOUD_PUBLIC_API_KEY_HEADER]: publicApiKey } : {}),
@@ -143,6 +181,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
143
181
  description: action.description || "",
144
182
  jsonSchema: JSON.stringify(actionParametersToJsonSchema(action.parameters || [])),
145
183
  })),
184
+ url: window.location.href,
146
185
  },
147
186
  threadId: threadIdRef.current,
148
187
  runId: runIdRef.current,
@@ -168,6 +207,15 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
168
207
  metadata: {
169
208
  requestType: CopilotRequestType.Chat,
170
209
  },
210
+ ...(agentSession
211
+ ? {
212
+ agentSession,
213
+ }
214
+ : {}),
215
+ agentStates: Object.values(coagentStates).map((state) => ({
216
+ agentName: state.name,
217
+ state: JSON.stringify(state.state),
218
+ })),
171
219
  },
172
220
  properties: copilotConfig.properties,
173
221
  signal: abortControllerRef.current?.signal,
@@ -179,7 +227,8 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
179
227
 
180
228
  const reader = stream.getReader();
181
229
 
182
- let results: { [id: string]: string } = {};
230
+ let actionResults: { [id: string]: string } = {};
231
+ let executedCoagentActions: string[] = [];
183
232
 
184
233
  try {
185
234
  while (true) {
@@ -222,13 +271,38 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
222
271
  for (const message of messages) {
223
272
  newMessages.push(message);
224
273
 
274
+ if (message instanceof AgentStateMessage) {
275
+ if (message.running) {
276
+ setCoagentStates((prevAgentStates) => ({
277
+ ...prevAgentStates,
278
+ [message.agentName]: {
279
+ name: message.agentName,
280
+ state: message.state,
281
+ running: message.running,
282
+ active: message.active,
283
+ threadId: message.threadId,
284
+ nodeName: message.nodeName,
285
+ runId: message.runId,
286
+ },
287
+ }));
288
+ setAgentSession({
289
+ threadId: message.threadId,
290
+ agentName: message.agentName,
291
+ nodeName: message.nodeName,
292
+ });
293
+ } else {
294
+ setAgentSession(null);
295
+ }
296
+ }
297
+
298
+ // execute regular action executions
225
299
  if (
226
300
  message instanceof ActionExecutionMessage &&
227
301
  message.status.code !== MessageStatusCode.Pending &&
228
302
  message.scope === "client" &&
229
303
  onFunctionCall
230
304
  ) {
231
- if (!(message.id in results)) {
305
+ if (!(message.id in actionResults)) {
232
306
  // Do not execute a function call if guardrails are enabled but the status is not known
233
307
  if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
234
308
  break;
@@ -239,29 +313,77 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
239
313
  name: message.name,
240
314
  args: message.arguments,
241
315
  });
242
- results[message.id] = result;
316
+ actionResults[message.id] = result;
243
317
  }
244
318
 
245
319
  // add the result message
246
320
  newMessages.push(
247
321
  new ResultMessage({
248
- result: ResultMessage.encodeResult(results[message.id]),
322
+ result: ResultMessage.encodeResult(actionResults[message.id]),
249
323
  actionExecutionId: message.id,
250
324
  actionName: message.name,
251
325
  }),
252
326
  );
253
327
  }
328
+
329
+ // execute coagent actions
330
+ if (
331
+ message instanceof AgentStateMessage &&
332
+ !message.active &&
333
+ !executedCoagentActions.includes(message.id) &&
334
+ onCoagentAction
335
+ ) {
336
+ // Do not execute a coagent action if guardrails are enabled but the status is not known
337
+ if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
338
+ break;
339
+ }
340
+ // execute coagent action
341
+ await onCoagentAction({
342
+ name: message.agentName,
343
+ nodeName: message.nodeName,
344
+ state: message.state,
345
+ });
346
+ executedCoagentActions.push(message.id);
347
+ }
254
348
  }
255
349
  }
256
350
 
257
351
  if (newMessages.length > 0) {
258
- setMessages([...previousMessages, ...newMessages]);
352
+ // Construct filteredMessages inline to remove adjacent AgentStateMessage instances
353
+ // with the same agentName, keeping only the last one.
354
+ const filteredMessages = [...previousMessages, ...newMessages].reduce(
355
+ (acc: Message[], message: Message) => {
356
+ if (
357
+ // If the current message is an AgentStateMessage
358
+ message instanceof AgentStateMessage &&
359
+ // And there is at least one message in the accumulator
360
+ acc.length > 0 &&
361
+ // And the last message in the accumulator is also an AgentStateMessage
362
+ acc[acc.length - 1] instanceof AgentStateMessage &&
363
+ // And the agentName, nodeName, and runId are the same
364
+ (acc[acc.length - 1] as AgentStateMessage).agentName === message.agentName &&
365
+ (acc[acc.length - 1] as AgentStateMessage).nodeName === message.nodeName &&
366
+ (acc[acc.length - 1] as AgentStateMessage).runId === message.runId
367
+ ) {
368
+ // If the conditions are met, replace the last message in the accumulator with the current message
369
+ acc[acc.length - 1] = message;
370
+ } else {
371
+ // Otherwise, add the current message to the accumulator
372
+ acc.push(message);
373
+ }
374
+ return acc;
375
+ },
376
+ [],
377
+ );
378
+
379
+ // Update the state with the filtered messages
380
+ setMessages(filteredMessages);
259
381
  }
260
382
  }
261
383
 
262
384
  if (
263
385
  // if we have client side results
264
- Object.values(results).length ||
386
+ Object.values(actionResults).length ||
265
387
  // or the last message we received is a result
266
388
  (newMessages.length && newMessages[newMessages.length - 1] instanceof ResultMessage)
267
389
  ) {
@@ -288,6 +410,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
288
410
  if (isLoading) {
289
411
  return;
290
412
  }
413
+
291
414
  const newMessages = [...messages, message];
292
415
  setMessages(newMessages);
293
416
  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" />