@copilotkit/react-core 1.1.1-feat-runtime-remote-actions.4 → 1.1.1-feat-runtime-remote-actions.5

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 (129) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/{chunk-2MQX7BJL.mjs → chunk-6GOM3DN7.mjs} +2 -2
  3. package/dist/{chunk-IF6P5ZXR.mjs → chunk-6UNB66M3.mjs} +38 -10
  4. package/dist/chunk-6UNB66M3.mjs.map +1 -0
  5. package/dist/{chunk-73KBO5JG.mjs → chunk-73YBF52D.mjs} +2 -2
  6. package/dist/chunk-BWYAGPEF.mjs +1 -0
  7. package/dist/{chunk-DZH3HSXW.mjs → chunk-CHOQ5C7K.mjs} +35 -8
  8. package/dist/chunk-CHOQ5C7K.mjs.map +1 -0
  9. package/dist/{chunk-33ERMMNX.mjs → chunk-DU7PVINC.mjs} +2 -2
  10. package/dist/chunk-IQH77T4S.mjs +44 -0
  11. package/dist/chunk-IQH77T4S.mjs.map +1 -0
  12. package/dist/{chunk-DB4VWZ5Q.mjs → chunk-LTA2O5WH.mjs} +11 -6
  13. package/dist/chunk-LTA2O5WH.mjs.map +1 -0
  14. package/dist/chunk-MTOHRBPJ.mjs +87 -0
  15. package/dist/chunk-MTOHRBPJ.mjs.map +1 -0
  16. package/dist/{chunk-52M7642J.mjs → chunk-PPYZB3IY.mjs} +52 -31
  17. package/dist/chunk-PPYZB3IY.mjs.map +1 -0
  18. package/dist/{chunk-H4XENJME.mjs → chunk-SYJIZLOI.mjs} +2 -2
  19. package/dist/{chunk-3K7JAFGM.mjs → chunk-TFSMXQYS.mjs} +2 -2
  20. package/dist/components/copilot-provider/copilotkit-props.d.ts +4 -0
  21. package/dist/components/copilot-provider/copilotkit-props.js.map +1 -1
  22. package/dist/components/copilot-provider/copilotkit.js +46 -13
  23. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  24. package/dist/components/copilot-provider/copilotkit.mjs +2 -2
  25. package/dist/components/copilot-provider/index.js +46 -13
  26. package/dist/components/copilot-provider/index.js.map +1 -1
  27. package/dist/components/copilot-provider/index.mjs +2 -2
  28. package/dist/components/index.js +46 -13
  29. package/dist/components/index.js.map +1 -1
  30. package/dist/components/index.mjs +2 -2
  31. package/dist/context/copilot-context.d.ts +18 -8
  32. package/dist/context/copilot-context.js +10 -5
  33. package/dist/context/copilot-context.js.map +1 -1
  34. package/dist/context/copilot-context.mjs +1 -1
  35. package/dist/context/index.d.ts +2 -1
  36. package/dist/context/index.js +10 -5
  37. package/dist/context/index.js.map +1 -1
  38. package/dist/context/index.mjs +1 -1
  39. package/dist/hooks/index.d.ts +4 -2
  40. package/dist/hooks/index.js +205 -89
  41. package/dist/hooks/index.js.map +1 -1
  42. package/dist/hooks/index.mjs +17 -17
  43. package/dist/hooks/use-chat.d.ts +24 -7
  44. package/dist/hooks/use-chat.js +51 -30
  45. package/dist/hooks/use-chat.js.map +1 -1
  46. package/dist/hooks/use-chat.mjs +1 -1
  47. package/dist/hooks/use-coagent-action.d.ts +5 -0
  48. package/dist/hooks/{use-copilot-chat-ui.js → use-coagent-action.js} +48 -22
  49. package/dist/hooks/use-coagent-action.js.map +1 -0
  50. package/dist/hooks/use-coagent-action.mjs +9 -0
  51. package/dist/hooks/use-coagent.d.ts +14 -18
  52. package/dist/hooks/use-coagent.js +184 -17
  53. package/dist/hooks/use-coagent.js.map +1 -1
  54. package/dist/hooks/use-coagent.mjs +6 -20
  55. package/dist/hooks/use-coagent.mjs.map +1 -1
  56. package/dist/hooks/use-copilot-action.js +10 -5
  57. package/dist/hooks/use-copilot-action.js.map +1 -1
  58. package/dist/hooks/use-copilot-action.mjs +2 -2
  59. package/dist/hooks/use-copilot-chat.js +89 -37
  60. package/dist/hooks/use-copilot-chat.js.map +1 -1
  61. package/dist/hooks/use-copilot-chat.mjs +4 -4
  62. package/dist/hooks/use-copilot-readable.js +10 -5
  63. package/dist/hooks/use-copilot-readable.js.map +1 -1
  64. package/dist/hooks/use-copilot-readable.mjs +2 -2
  65. package/dist/hooks/use-make-copilot-document-readable.js +10 -5
  66. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  67. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  68. package/dist/index.d.ts +4 -2
  69. package/dist/index.js +263 -119
  70. package/dist/index.js.map +1 -1
  71. package/dist/index.mjs +21 -21
  72. package/dist/lib/copilot-task.d.ts +2 -1
  73. package/dist/lib/copilot-task.js.map +1 -1
  74. package/dist/lib/copilot-task.mjs +3 -3
  75. package/dist/lib/index.d.ts +2 -1
  76. package/dist/lib/index.js.map +1 -1
  77. package/dist/lib/index.mjs +3 -3
  78. package/dist/types/coagent-action.d.ts +17 -0
  79. package/dist/types/coagent-action.js +19 -0
  80. package/dist/types/coagent-action.js.map +1 -0
  81. package/dist/types/coagent-action.mjs +1 -0
  82. package/dist/types/coagent-state.d.ts +11 -0
  83. package/dist/types/coagent-state.js +19 -0
  84. package/dist/types/coagent-state.js.map +1 -0
  85. package/dist/types/coagent-state.mjs +1 -0
  86. package/dist/types/coagent-state.mjs.map +1 -0
  87. package/dist/utils/extract.d.ts +2 -1
  88. package/dist/utils/extract.js.map +1 -1
  89. package/dist/utils/extract.mjs +3 -3
  90. package/dist/utils/index.d.ts +2 -1
  91. package/dist/utils/index.js.map +1 -1
  92. package/dist/utils/index.mjs +3 -3
  93. package/package.json +5 -5
  94. package/src/components/copilot-provider/copilotkit-props.tsx +5 -0
  95. package/src/components/copilot-provider/copilotkit.tsx +41 -9
  96. package/src/context/copilot-context.tsx +34 -15
  97. package/src/hooks/index.ts +2 -2
  98. package/src/hooks/use-chat.ts +88 -38
  99. package/src/hooks/use-coagent-action.ts +44 -0
  100. package/src/hooks/use-coagent.ts +111 -38
  101. package/src/hooks/use-copilot-chat.ts +29 -2
  102. package/src/types/coagent-action.ts +17 -0
  103. package/src/types/coagent-state.ts +9 -0
  104. package/dist/chunk-52M7642J.mjs.map +0 -1
  105. package/dist/chunk-6YOQY4WD.mjs +0 -20
  106. package/dist/chunk-6YOQY4WD.mjs.map +0 -1
  107. package/dist/chunk-A47L32JN.mjs +0 -52
  108. package/dist/chunk-A47L32JN.mjs.map +0 -1
  109. package/dist/chunk-AIWDXM7L.mjs +0 -1
  110. package/dist/chunk-DB4VWZ5Q.mjs.map +0 -1
  111. package/dist/chunk-DZH3HSXW.mjs.map +0 -1
  112. package/dist/chunk-IF6P5ZXR.mjs.map +0 -1
  113. package/dist/hooks/use-agent-state.d.ts +0 -12
  114. package/dist/hooks/use-agent-state.js +0 -499
  115. package/dist/hooks/use-agent-state.js.map +0 -1
  116. package/dist/hooks/use-agent-state.mjs +0 -19
  117. package/dist/hooks/use-copilot-chat-ui.d.ts +0 -13
  118. package/dist/hooks/use-copilot-chat-ui.js.map +0 -1
  119. package/dist/hooks/use-copilot-chat-ui.mjs +0 -10
  120. package/src/hooks/use-agent-state.ts +0 -63
  121. package/src/hooks/use-copilot-chat-ui.ts +0 -26
  122. /package/dist/{chunk-2MQX7BJL.mjs.map → chunk-6GOM3DN7.mjs.map} +0 -0
  123. /package/dist/{chunk-73KBO5JG.mjs.map → chunk-73YBF52D.mjs.map} +0 -0
  124. /package/dist/{chunk-AIWDXM7L.mjs.map → chunk-BWYAGPEF.mjs.map} +0 -0
  125. /package/dist/{chunk-33ERMMNX.mjs.map → chunk-DU7PVINC.mjs.map} +0 -0
  126. /package/dist/{chunk-H4XENJME.mjs.map → chunk-SYJIZLOI.mjs.map} +0 -0
  127. /package/dist/{chunk-3K7JAFGM.mjs.map → chunk-TFSMXQYS.mjs.map} +0 -0
  128. /package/dist/hooks/{use-agent-state.mjs.map → use-coagent-action.mjs.map} +0 -0
  129. /package/dist/{hooks/use-copilot-chat-ui.mjs.map → types/coagent-action.mjs.map} +0 -0
@@ -36,6 +36,7 @@ import {
36
36
  CopilotApiConfig,
37
37
  InChatRenderFunction,
38
38
  ChatComponentsCache,
39
+ AgentSession,
39
40
  } from "../../context/copilot-context";
40
41
  import useTree from "../../hooks/use-tree";
41
42
  import { CopilotChatSuggestionConfiguration, DocumentPointer } from "../../types";
@@ -50,7 +51,8 @@ import { AgentStateMessage, Message } from "@copilotkit/runtime-client-gql";
50
51
  import { FrontendAction } from "../../types/frontend-action";
51
52
  import useFlatCategoryStore from "../../hooks/use-flat-category-store";
52
53
  import { CopilotKitProps } from "./copilotkit-props";
53
- import { CopilotChatUI } from "../../hooks/use-copilot-chat-ui";
54
+ import { CoagentAction } from "../../types/coagent-action";
55
+ import { CoagentState } from "../../types/coagent-state";
54
56
 
55
57
  export function CopilotKit({ children, ...props }: CopilotKitProps) {
56
58
  // Compute all the functions and properties that we need to pass
@@ -65,7 +67,11 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
65
67
  const chatApiEndpoint = props.runtimeUrl || COPILOT_CLOUD_CHAT_URL;
66
68
 
67
69
  const [actions, setActions] = useState<Record<string, FrontendAction<any>>>({});
68
- const chatComponentsCache = useRef<ChatComponentsCache>({ actions: {}, chatUI: {} });
70
+ const [coagentActions, setCoagentActions] = useState<Record<string, CoagentAction<any>>>({});
71
+ const chatComponentsCache = useRef<ChatComponentsCache>({
72
+ actions: {},
73
+ coagentActions: {},
74
+ });
69
75
  const { addElement, removeElement, printTree } = useTree();
70
76
  const [messages, setMessages] = useState<Message[]>([]);
71
77
  const [isLoading, setIsLoading] = useState(false);
@@ -94,6 +100,23 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
94
100
  });
95
101
  }, []);
96
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
+
97
120
  const getContextString = useCallback(
98
121
  (documents: DocumentPointer[], categories: string[]) => {
99
122
  const documentsString = documents
@@ -208,9 +231,15 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
208
231
  });
209
232
  };
210
233
 
211
- const [agentStates, setAgentStates] = useState<Record<string, AgentStateMessage | null>>({});
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
+ }
212
241
 
213
- const [chatUI, setChatUI] = useState<CopilotChatUI[]>([]);
242
+ const [agentSession, setAgentSession] = useState<AgentSession | null>(initialAgentSession);
214
243
 
215
244
  return (
216
245
  <CopilotContext.Provider
@@ -220,6 +249,9 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
220
249
  getFunctionCallHandler,
221
250
  setAction,
222
251
  removeAction,
252
+ coagentActions,
253
+ setCoagentAction,
254
+ removeCoagentAction,
223
255
  getContextString,
224
256
  addContext,
225
257
  removeContext,
@@ -237,10 +269,10 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
237
269
  chatInstructions,
238
270
  setChatInstructions,
239
271
  showDevConsole: props.showDevConsole === undefined ? "auto" : props.showDevConsole,
240
- agentStates,
241
- setAgentStates,
242
- chatUI,
243
- setChatUI,
272
+ coagentStates,
273
+ setCoagentStates,
274
+ agentSession,
275
+ setAgentSession,
244
276
  }}
245
277
  >
246
278
  {children}
@@ -263,7 +295,7 @@ function entryPointsToFunctionCallHandler(actions: FrontendAction<any>[]): Funct
263
295
  await new Promise<void>((resolve, reject) => {
264
296
  flushSync(async () => {
265
297
  try {
266
- result = await action.handler(args);
298
+ result = await action.handler?.(args);
267
299
  resolve();
268
300
  } catch (error) {
269
301
  reject(error);
@@ -1,11 +1,12 @@
1
1
  import { CopilotCloudConfig, FunctionCallHandler } from "@copilotkit/shared";
2
- import { AgentStateMessage, Message } from "@copilotkit/runtime-client-gql";
2
+ import { Message } from "@copilotkit/runtime-client-gql";
3
3
  import { ActionRenderProps, FrontendAction } from "../types/frontend-action";
4
4
  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 { CopilotChatUI } from "../hooks/use-copilot-chat-ui";
8
+ import { CoagentAction, CoagentActionRenderProps } from "../types/coagent-action";
9
+ import { CoagentState } from "../types/coagent-state";
9
10
 
10
11
  /**
11
12
  * Interface for the configuration of the Copilot API.
@@ -68,10 +69,19 @@ export interface CopilotApiConfig {
68
69
  }
69
70
 
70
71
  export type InChatRenderFunction = (props: ActionRenderProps<any>) => string | JSX.Element;
72
+ export type CoagentInChatRenderFunction = (
73
+ props: CoagentActionRenderProps<any>,
74
+ ) => string | JSX.Element;
71
75
 
72
76
  export interface ChatComponentsCache {
73
77
  actions: Record<string, InChatRenderFunction | string>;
74
- chatUI: Record<string, Function | string>;
78
+ coagentActions: Record<string, CoagentInChatRenderFunction | string>;
79
+ }
80
+
81
+ export interface AgentSession {
82
+ agentName: string;
83
+ threadId?: string;
84
+ nodeName?: string;
75
85
  }
76
86
 
77
87
  export interface CopilotContextParams {
@@ -79,6 +89,12 @@ export interface CopilotContextParams {
79
89
  actions: Record<string, FrontendAction<any>>;
80
90
  setAction: (id: string, action: FrontendAction<any>) => void;
81
91
  removeAction: (id: string) => void;
92
+
93
+ // coagent actions
94
+ coagentActions: Record<string, CoagentAction<any>>;
95
+ setCoagentAction: (id: string, action: CoagentAction<any>) => void;
96
+ removeCoagentAction: (id: string) => void;
97
+
82
98
  chatComponentsCache: React.RefObject<ChatComponentsCache>;
83
99
 
84
100
  getFunctionCallHandler: (
@@ -117,13 +133,11 @@ export interface CopilotContextParams {
117
133
 
118
134
  showDevConsole: boolean | "auto";
119
135
 
120
- // agent states
121
- agentStates: Record<string, AgentStateMessage | null>;
122
- setAgentStates: React.Dispatch<React.SetStateAction<Record<string, AgentStateMessage | null>>>;
123
-
124
- // chat ui
125
- chatUI: CopilotChatUI[];
126
- setChatUI: React.Dispatch<React.SetStateAction<CopilotChatUI[]>>;
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>>;
127
141
  }
128
142
 
129
143
  const emptyCopilotContext: CopilotContextParams = {
@@ -131,7 +145,11 @@ const emptyCopilotContext: CopilotContextParams = {
131
145
  setAction: () => {},
132
146
  removeAction: () => {},
133
147
 
134
- chatComponentsCache: { current: { actions: {}, chatUI: {} } },
148
+ coagentActions: {},
149
+ setCoagentAction: () => {},
150
+ removeCoagentAction: () => {},
151
+
152
+ chatComponentsCache: { current: { actions: {}, coagentActions: {} } },
135
153
  getContextString: (documents: DocumentPointer[], categories: string[]) =>
136
154
  returnAndThrowInDebug(""),
137
155
  addContext: () => "",
@@ -169,10 +187,11 @@ const emptyCopilotContext: CopilotContextParams = {
169
187
  addChatSuggestionConfiguration: () => {},
170
188
  removeChatSuggestionConfiguration: () => {},
171
189
  showDevConsole: "auto",
172
- agentStates: {},
173
- setAgentStates: () => {},
174
- chatUI: [],
175
- setChatUI: () => {},
190
+ coagentStates: {},
191
+ setCoagentStates: () => {},
192
+
193
+ agentSession: null,
194
+ setAgentSession: () => {},
176
195
  };
177
196
 
178
197
  export const CopilotContext = React.createContext<CopilotContextParams>(emptyCopilotContext);
@@ -3,8 +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";
9
- export { useAgentState } from "./use-agent-state";
10
- export { useCopilotChatUI } from "./use-copilot-chat-ui";
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,
@@ -21,6 +21,9 @@ import {
21
21
  } from "@copilotkit/runtime-client-gql";
22
22
 
23
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";
24
27
 
25
28
  export type UseChatOptions = {
26
29
  /**
@@ -33,10 +36,16 @@ export type UseChatOptions = {
33
36
  * automatically to the API and will be used to update the chat.
34
37
  */
35
38
  onFunctionCall?: FunctionCallHandler;
39
+
40
+ /**
41
+ * Callback function to be called when a coagent action is received.
42
+ */
43
+ onCoagentAction?: CoagentActionHandler;
44
+
36
45
  /**
37
46
  * Function definitions to be sent to the API.
38
47
  */
39
- actions: Action[];
48
+ actions: FrontendAction<any>[];
40
49
 
41
50
  /**
42
51
  * The CopilotKit API configuration.
@@ -67,10 +76,25 @@ export type UseChatOptions = {
67
76
  */
68
77
  setIsLoading: React.Dispatch<React.SetStateAction<boolean>>;
69
78
 
79
+ /**
80
+ * The current list of coagent states.
81
+ */
82
+ coagentStates: Record<string, CoagentState>;
83
+
70
84
  /**
71
85
  * setState-powered method to update the agent states
72
86
  */
73
- setAgentStates: React.Dispatch<React.SetStateAction<Record<string, AgentStateMessage | null>>>;
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>>;
74
98
  };
75
99
 
76
100
  export type UseChatHelpers = {
@@ -92,12 +116,6 @@ export type UseChatHelpers = {
92
116
  stop: () => void;
93
117
  };
94
118
 
95
- interface AgentSession {
96
- threadId: string;
97
- agentName: string;
98
- nodeName: string;
99
- }
100
-
101
119
  export function useChat(options: UseChatOptions): UseChatHelpers {
102
120
  const {
103
121
  messages,
@@ -109,13 +127,16 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
109
127
  isLoading,
110
128
  actions,
111
129
  onFunctionCall,
112
- setAgentStates,
130
+ onCoagentAction,
131
+ setCoagentStates,
132
+ coagentStates,
133
+ agentSession,
134
+ setAgentSession,
113
135
  } = options;
114
136
 
115
137
  const abortControllerRef = useRef<AbortController>();
116
138
  const threadIdRef = useRef<string | null>(null);
117
139
  const runIdRef = useRef<string | null>(null);
118
- const agentSessionRef = useRef<AgentSession | null>(null);
119
140
 
120
141
  const publicApiKey = copilotConfig.publicApiKey;
121
142
 
@@ -185,15 +206,15 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
185
206
  metadata: {
186
207
  requestType: CopilotRequestType.Chat,
187
208
  },
188
- ...(agentSessionRef.current
209
+ ...(agentSession
189
210
  ? {
190
- agentSession: {
191
- threadId: agentSessionRef.current.threadId,
192
- agentName: agentSessionRef.current.agentName,
193
- nodeName: agentSessionRef.current.nodeName,
194
- },
211
+ agentSession,
195
212
  }
196
213
  : {}),
214
+ agentStates: Object.values(coagentStates).map((state) => ({
215
+ agentName: state.name,
216
+ state: JSON.stringify(state.state),
217
+ })),
197
218
  },
198
219
  properties: copilotConfig.properties,
199
220
  signal: abortControllerRef.current?.signal,
@@ -205,7 +226,8 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
205
226
 
206
227
  const reader = stream.getReader();
207
228
 
208
- let results: { [id: string]: string } = {};
229
+ let actionResults: { [id: string]: string } = {};
230
+ let executedCoagentActions: string[] = [];
209
231
 
210
232
  try {
211
233
  while (true) {
@@ -250,22 +272,25 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
250
272
 
251
273
  if (message instanceof AgentStateMessage) {
252
274
  if (message.running) {
253
- setAgentStates((prevAgentStates) => ({
275
+ setCoagentStates((prevAgentStates) => ({
254
276
  ...prevAgentStates,
255
- [message.agentName]: message,
277
+ [message.agentName]: {
278
+ name: message.agentName,
279
+ state: message.state,
280
+ running: message.running,
281
+ active: message.active,
282
+ threadId: message.threadId,
283
+ nodeName: message.nodeName,
284
+ runId: message.runId,
285
+ },
256
286
  }));
257
- agentSessionRef.current = {
287
+ setAgentSession({
258
288
  threadId: message.threadId,
259
289
  agentName: message.agentName,
260
290
  nodeName: message.nodeName,
261
- };
262
- } else {
263
- setAgentStates((prevAgentStates) => {
264
- const newAgentStates = { ...prevAgentStates };
265
- delete newAgentStates[message.agentName];
266
- return newAgentStates;
267
291
  });
268
- agentSessionRef.current = null;
292
+ } else {
293
+ setAgentSession(null);
269
294
  }
270
295
  }
271
296
 
@@ -276,7 +301,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
276
301
  message.scope === "client" &&
277
302
  onFunctionCall
278
303
  ) {
279
- if (!(message.id in results)) {
304
+ if (!(message.id in actionResults)) {
280
305
  // Do not execute a function call if guardrails are enabled but the status is not known
281
306
  if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
282
307
  break;
@@ -287,18 +312,38 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
287
312
  name: message.name,
288
313
  args: message.arguments,
289
314
  });
290
- results[message.id] = result;
315
+ actionResults[message.id] = result;
291
316
  }
292
317
 
293
318
  // add the result message
294
319
  newMessages.push(
295
320
  new ResultMessage({
296
- result: ResultMessage.encodeResult(results[message.id]),
321
+ result: ResultMessage.encodeResult(actionResults[message.id]),
297
322
  actionExecutionId: message.id,
298
323
  actionName: message.name,
299
324
  }),
300
325
  );
301
326
  }
327
+
328
+ // execute coagent actions
329
+ if (
330
+ message instanceof AgentStateMessage &&
331
+ !message.active &&
332
+ !executedCoagentActions.includes(message.id) &&
333
+ onCoagentAction
334
+ ) {
335
+ // Do not execute a coagent action if guardrails are enabled but the status is not known
336
+ if (guardrailsEnabled && value.generateCopilotResponse.status === undefined) {
337
+ break;
338
+ }
339
+ // execute coagent action
340
+ await onCoagentAction({
341
+ name: message.agentName,
342
+ nodeName: message.nodeName,
343
+ state: message.state,
344
+ });
345
+ executedCoagentActions.push(message.id);
346
+ }
302
347
  }
303
348
  }
304
349
 
@@ -308,11 +353,16 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
308
353
  const filteredMessages = [...previousMessages, ...newMessages].reduce(
309
354
  (acc: Message[], message: Message) => {
310
355
  if (
311
- message instanceof AgentStateMessage && // Check if the current message is an AgentStateMessage
312
- acc.length > 0 && // Ensure there is at least one message in the accumulator
313
- acc[acc.length - 1] instanceof AgentStateMessage && // Check if the last message in the accumulator is also an AgentStateMessage
314
- (acc[acc.length - 1] as AgentStateMessage).agentName === message.agentName && // Check if the agentName is the same
315
- (acc[acc.length - 1] as AgentStateMessage).nodeName === message.nodeName // Check if the nodeName is the same
356
+ // If the current message is an AgentStateMessage
357
+ message instanceof AgentStateMessage &&
358
+ // And there is at least one message in the accumulator
359
+ acc.length > 0 &&
360
+ // And the last message in the accumulator is also an AgentStateMessage
361
+ acc[acc.length - 1] instanceof AgentStateMessage &&
362
+ // And the agentName, nodeName, and runId are the same
363
+ (acc[acc.length - 1] as AgentStateMessage).agentName === message.agentName &&
364
+ (acc[acc.length - 1] as AgentStateMessage).nodeName === message.nodeName &&
365
+ (acc[acc.length - 1] as AgentStateMessage).runId === message.runId
316
366
  ) {
317
367
  // If the conditions are met, replace the last message in the accumulator with the current message
318
368
  acc[acc.length - 1] = message;
@@ -320,7 +370,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
320
370
  // Otherwise, add the current message to the accumulator
321
371
  acc.push(message);
322
372
  }
323
- return acc; // Return the accumulator for the next iteration
373
+ return acc;
324
374
  },
325
375
  [],
326
376
  );
@@ -332,7 +382,7 @@ export function useChat(options: UseChatOptions): UseChatHelpers {
332
382
 
333
383
  if (
334
384
  // if we have client side results
335
- Object.values(results).length ||
385
+ Object.values(actionResults).length ||
336
386
  // or the last message we received is a result
337
387
  (newMessages.length && newMessages[newMessages.length - 1] instanceof ResultMessage)
338
388
  ) {
@@ -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
+ }
@@ -1,40 +1,28 @@
1
- import { useState } from "react";
1
+ import { useEffect } from "react";
2
+ import { useCopilotContext } from "../context";
3
+ import { CoagentState } from "../types/coagent-state";
2
4
 
3
- export function useCoagent<T = any>(options: UseCoagentOptions<T>): UseCoagentReturnType<T> {
4
- throw new Error("Not implemented");
5
+ interface WithInternalStateManagementAndInitial<T> {
6
+ name: string;
7
+ initialState: T;
5
8
  }
6
9
 
7
- const [appState, setAppState] = useState({
8
- story: "dasfsdf",
9
- });
10
-
11
- const [story, setStory] = useState({
12
- story: "dasfsdf",
13
- });
14
-
15
- const { nodeName } = useCoagent({
16
- name: "myAgent",
17
- });
18
-
19
- // what do we need from useCoagent?
20
- // - nodeName
21
- // - threadId
22
- // - running
23
- // - state
24
-
25
- export function useCopilotAction<T = any>(coagentAction: CoagentAction<T>) {
26
- throw new Error("Not implemented");
10
+ interface WithInternalStateManagement {
11
+ name: string;
12
+ initialState?: any; // Optional initialState with default type any
27
13
  }
28
14
 
29
- // <CopilotKit agent="lockedInAgentName" />
30
-
31
- export interface UseCoagentOptions<T> {
15
+ interface WithExternalStateManagement<T> {
32
16
  name: string;
33
- initialState?: T;
34
- state?: T;
35
- setState?: (newState: T | ((prevState: T | undefined) => T)) => void;
17
+ state: T;
18
+ setState: (newState: T | ((prevState: T | undefined) => T)) => void;
36
19
  }
37
20
 
21
+ type UseCoagentOptions<T> =
22
+ | WithInternalStateManagementAndInitial<T>
23
+ | WithInternalStateManagement
24
+ | WithExternalStateManagement<T>;
25
+
38
26
  export interface UseCoagentReturnType<T> {
39
27
  name: string;
40
28
  nodeName?: string;
@@ -46,15 +34,100 @@ export interface UseCoagentReturnType<T> {
46
34
  stop: () => void;
47
35
  }
48
36
 
49
- export interface CoagentActionRenderProps<T> {
50
- status: "executing" | "complete" | "in_progress";
51
- args: T;
52
- result: any;
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
+ });
53
122
  }
54
123
 
55
- export interface CoagentAction<T> {
56
- name: string;
57
- nodeName?: string;
58
- handler?: (args: T) => any | Promise<any>;
59
- render?: (props: CoagentActionRenderProps<T>) => string | React.ReactElement;
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
+ }
60
131
  }
132
+
133
+ // <CopilotKit agent="lockedInAgentName" />