@copilotkit/react-core 0.21.0-mme-assistant-api.0 → 0.21.0-mme-function-call-labels.2

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 (121) hide show
  1. package/.turbo/turbo-build.log +146 -127
  2. package/CHANGELOG.md +26 -2
  3. package/dist/{chunk-2EP7VLPI.mjs → chunk-4VUJYN3U.mjs} +2 -2
  4. package/dist/{chunk-PHK2K7UB.mjs → chunk-5TE3LHXD.mjs} +19 -25
  5. package/dist/chunk-5TE3LHXD.mjs.map +1 -0
  6. package/dist/{chunk-UHTJLRI6.mjs → chunk-5VLCJLRQ.mjs} +7 -7
  7. package/dist/chunk-5VLCJLRQ.mjs.map +1 -0
  8. package/dist/{chunk-2YF2MC22.mjs → chunk-AEUR5JBT.mjs} +42 -22
  9. package/dist/chunk-AEUR5JBT.mjs.map +1 -0
  10. package/dist/{chunk-S7ZVOTYK.mjs → chunk-DVLYNQG4.mjs} +2 -1
  11. package/dist/chunk-DVLYNQG4.mjs.map +1 -0
  12. package/dist/chunk-IOP6JX34.mjs +1 -0
  13. package/dist/{chunk-WH4L73VS.mjs → chunk-NNUIXO74.mjs} +7 -3
  14. package/dist/chunk-NNUIXO74.mjs.map +1 -0
  15. package/dist/{chunk-KLGA2MES.mjs → chunk-OSQO6ASW.mjs} +4 -4
  16. package/dist/chunk-OSQO6ASW.mjs.map +1 -0
  17. package/dist/chunk-UQKARKHD.mjs +95 -0
  18. package/dist/chunk-UQKARKHD.mjs.map +1 -0
  19. package/dist/chunk-WCI6UGKK.mjs +13 -0
  20. package/dist/chunk-WCI6UGKK.mjs.map +1 -0
  21. package/dist/{chunk-6WZFE6II.mjs → chunk-XDKLZEPZ.mjs} +3 -3
  22. package/dist/{chunk-JVCBCB2T.mjs → chunk-ZAB22RCR.mjs} +2 -2
  23. package/dist/components/copilot-provider/copilotkit.js +13 -16
  24. package/dist/components/copilot-provider/copilotkit.js.map +1 -1
  25. package/dist/components/copilot-provider/copilotkit.mjs +3 -3
  26. package/dist/components/copilot-provider/index.js +13 -16
  27. package/dist/components/copilot-provider/index.js.map +1 -1
  28. package/dist/components/copilot-provider/index.mjs +3 -3
  29. package/dist/components/copilot-provider/standard-copilot-api-config.d.ts +1 -0
  30. package/dist/components/index.js +13 -16
  31. package/dist/components/index.js.map +1 -1
  32. package/dist/components/index.mjs +3 -3
  33. package/dist/context/copilot-context.d.ts +7 -5
  34. package/dist/context/copilot-context.js +1 -0
  35. package/dist/context/copilot-context.js.map +1 -1
  36. package/dist/context/copilot-context.mjs +1 -1
  37. package/dist/context/index.d.ts +1 -0
  38. package/dist/context/index.js +1 -0
  39. package/dist/context/index.js.map +1 -1
  40. package/dist/context/index.mjs +1 -1
  41. package/dist/hooks/index.d.ts +2 -0
  42. package/dist/hooks/index.js +149 -34
  43. package/dist/hooks/index.js.map +1 -1
  44. package/dist/hooks/index.mjs +16 -11
  45. package/dist/hooks/use-chat.d.ts +1 -0
  46. package/dist/hooks/use-chat.js +48 -20
  47. package/dist/hooks/use-chat.js.map +1 -1
  48. package/dist/hooks/use-chat.mjs +1 -1
  49. package/dist/hooks/use-copilot-action-implementation.d.ts +8 -0
  50. package/dist/hooks/use-copilot-action-implementation.js +190 -0
  51. package/dist/hooks/use-copilot-action-implementation.js.map +1 -0
  52. package/dist/hooks/use-copilot-action-implementation.mjs +12 -0
  53. package/dist/hooks/use-copilot-action-implementation.mjs.map +1 -0
  54. package/dist/hooks/use-copilot-action.d.ts +7 -0
  55. package/dist/hooks/use-copilot-action.js +148 -0
  56. package/dist/hooks/use-copilot-action.js.map +1 -0
  57. package/dist/hooks/use-copilot-action.mjs +11 -0
  58. package/dist/hooks/use-copilot-action.mjs.map +1 -0
  59. package/dist/hooks/use-copilot-chat.d.ts +1 -0
  60. package/dist/hooks/use-copilot-chat.js +40 -21
  61. package/dist/hooks/use-copilot-chat.js.map +1 -1
  62. package/dist/hooks/use-copilot-chat.mjs +5 -5
  63. package/dist/hooks/use-make-copilot-actionable.d.ts +3 -0
  64. package/dist/hooks/use-make-copilot-actionable.js +61 -6
  65. package/dist/hooks/use-make-copilot-actionable.js.map +1 -1
  66. package/dist/hooks/use-make-copilot-actionable.mjs +3 -2
  67. package/dist/hooks/use-make-copilot-document-readable.js +1 -0
  68. package/dist/hooks/use-make-copilot-document-readable.js.map +1 -1
  69. package/dist/hooks/use-make-copilot-document-readable.mjs +2 -2
  70. package/dist/hooks/use-make-copilot-readable.js +1 -0
  71. package/dist/hooks/use-make-copilot-readable.js.map +1 -1
  72. package/dist/hooks/use-make-copilot-readable.mjs +2 -2
  73. package/dist/index.d.ts +2 -0
  74. package/dist/index.js +171 -60
  75. package/dist/index.js.map +1 -1
  76. package/dist/index.mjs +25 -20
  77. package/dist/lib/copilot-task.d.ts +4 -3
  78. package/dist/lib/copilot-task.js +2 -2
  79. package/dist/lib/copilot-task.js.map +1 -1
  80. package/dist/lib/copilot-task.mjs +4 -4
  81. package/dist/lib/index.d.ts +2 -1
  82. package/dist/lib/index.js +2 -2
  83. package/dist/lib/index.js.map +1 -1
  84. package/dist/lib/index.mjs +4 -4
  85. package/dist/openai-assistants/hooks/index.js +1 -0
  86. package/dist/openai-assistants/hooks/index.js.map +1 -1
  87. package/dist/openai-assistants/hooks/index.mjs +4 -4
  88. package/dist/openai-assistants/hooks/use-copilot-chat-v2.js +1 -0
  89. package/dist/openai-assistants/hooks/use-copilot-chat-v2.js.map +1 -1
  90. package/dist/openai-assistants/hooks/use-copilot-chat-v2.mjs +4 -4
  91. package/dist/openai-assistants/index.js +1 -0
  92. package/dist/openai-assistants/index.js.map +1 -1
  93. package/dist/openai-assistants/index.mjs +4 -4
  94. package/dist/types/frontend-action.d.ts +40 -0
  95. package/dist/types/frontend-action.js +19 -0
  96. package/dist/types/frontend-action.js.map +1 -0
  97. package/dist/types/frontend-action.mjs +1 -0
  98. package/dist/types/frontend-action.mjs.map +1 -0
  99. package/dist/utils/fetch-chat-completion.d.ts +1 -0
  100. package/package.json +7 -6
  101. package/src/components/copilot-provider/copilotkit.tsx +20 -53
  102. package/src/context/copilot-context.tsx +9 -7
  103. package/src/hooks/index.ts +1 -0
  104. package/src/hooks/use-chat.ts +52 -27
  105. package/src/hooks/use-copilot-action-implementation.ts +114 -0
  106. package/src/hooks/use-copilot-action.ts +45 -0
  107. package/src/hooks/use-copilot-chat.ts +2 -1
  108. package/src/hooks/use-make-copilot-actionable.ts +6 -1
  109. package/src/lib/copilot-task.ts +6 -5
  110. package/src/types/frontend-action.ts +56 -0
  111. package/dist/chunk-2YF2MC22.mjs.map +0 -1
  112. package/dist/chunk-5UGLWBZJ.mjs +0 -1
  113. package/dist/chunk-KLGA2MES.mjs.map +0 -1
  114. package/dist/chunk-PHK2K7UB.mjs.map +0 -1
  115. package/dist/chunk-S7ZVOTYK.mjs.map +0 -1
  116. package/dist/chunk-UHTJLRI6.mjs.map +0 -1
  117. package/dist/chunk-WH4L73VS.mjs.map +0 -1
  118. /package/dist/{chunk-2EP7VLPI.mjs.map → chunk-4VUJYN3U.mjs.map} +0 -0
  119. /package/dist/{chunk-5UGLWBZJ.mjs.map → chunk-IOP6JX34.mjs.map} +0 -0
  120. /package/dist/{chunk-6WZFE6II.mjs.map → chunk-XDKLZEPZ.mjs.map} +0 -0
  121. /package/dist/{chunk-JVCBCB2T.mjs.map → chunk-ZAB22RCR.mjs.map} +0 -0
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/types/frontend-action.ts
17
+ var frontend_action_exports = {};
18
+ module.exports = __toCommonJS(frontend_action_exports);
19
+ //# sourceMappingURL=frontend-action.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/types/frontend-action.ts"],"sourcesContent":["import { Action, Parameter, MappedParameterTypes } from \"@copilotkit/shared\";\nimport React from \"react\";\n\ninterface InProgressState<T extends Parameter[] | [] = []> {\n status: \"inProgress\";\n args: Partial<MappedParameterTypes<T>>;\n result: undefined;\n}\n\ninterface ExecutingState<T extends Parameter[] | [] = []> {\n status: \"executing\";\n args: MappedParameterTypes<T>;\n result: undefined;\n}\n\ninterface CompleteState<T extends Parameter[] | [] = []> {\n status: \"complete\";\n args: MappedParameterTypes<T>;\n result: any;\n}\n\ninterface InProgressStateNoArgs<T extends Parameter[] | [] = []> {\n status: \"inProgress\";\n args: Partial<MappedParameterTypes<T>>;\n result: undefined;\n}\n\ninterface ExecutingStateNoArgs<T extends Parameter[] | [] = []> {\n status: \"executing\";\n args: MappedParameterTypes<T>;\n result: undefined;\n}\n\ninterface CompleteStateNoArgs<T extends Parameter[] | [] = []> {\n status: \"complete\";\n args: MappedParameterTypes<T>;\n result: any;\n}\n\nexport type ActionRenderProps<T extends Parameter[] | [] = []> =\n | CompleteState<T>\n | ExecutingState<T>\n | InProgressState<T>;\n\nexport type ActionRenderPropsNoArgs<T extends Parameter[] | [] = []> =\n | CompleteStateNoArgs<T>\n | ExecutingStateNoArgs<T>\n | InProgressStateNoArgs<T>;\n\nexport type FrontendAction<T extends Parameter[] | [] = []> = Action<T> & {\n render?:\n | string\n | (T extends []\n ? (props: ActionRenderPropsNoArgs<T>) => string | React.ReactElement\n : (props: ActionRenderProps<T>) => string | React.ReactElement);\n};\n"],"mappings":";;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=frontend-action.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,5 +1,6 @@
1
1
  import { Message, ToolDefinition, ChatCompletionEvent } from '@copilotkit/shared';
2
2
  import { CopilotApiConfig } from '../context/copilot-context.js';
3
+ import '../types/frontend-action.js';
3
4
  import 'react';
4
5
  import '../hooks/use-tree.js';
5
6
  import '../types/document-pointer.js';
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "0.21.0-mme-assistant-api.0",
7
+ "version": "0.21.0-mme-function-call-labels.2",
8
8
  "sideEffects": false,
9
9
  "main": "./dist/index.js",
10
10
  "module": "./dist/index.mjs",
@@ -19,18 +19,19 @@
19
19
  "devDependencies": {
20
20
  "@types/jest": "^29.5.4",
21
21
  "@types/react": "^18.2.5",
22
- "eslint": "^7.32.0",
22
+ "eslint": "^8.56.0",
23
23
  "jest": "^29.6.4",
24
24
  "react": "^18.2.0",
25
25
  "ts-jest": "^29.1.1",
26
26
  "tsup": "^6.7.0",
27
- "typescript": "^5.1.3",
28
- "eslint-config-custom": "0.6.0-mme-assistant-api.0",
29
- "tsconfig": "0.10.0-mme-assistant-api.0"
27
+ "typescript": "^5.2.3",
28
+ "eslint-config-custom": "0.6.0-mme-function-call-labels.2",
29
+ "tsconfig": "0.10.0-mme-function-call-labels.2"
30
30
  },
31
31
  "dependencies": {
32
32
  "nanoid": "^4.0.2",
33
- "@copilotkit/shared": "0.5.0-mme-assistant-api.0"
33
+ "untruncate-json": "^0.0.1",
34
+ "@copilotkit/shared": "0.5.0-mme-function-call-labels.2"
34
35
  },
35
36
  "scripts": {
36
37
  "build": "tsup --clean",
@@ -1,15 +1,11 @@
1
1
  "use client";
2
2
 
3
- import { FunctionDefinition } from "@copilotkit/shared";
4
- import { useCallback, useState } from "react";
3
+ import { Ref, useCallback, useRef, useState } from "react";
5
4
  import { CopilotContext, CopilotApiConfig } from "../../context/copilot-context";
6
5
  import useTree from "../../hooks/use-tree";
7
6
  import { DocumentPointer } from "../../types";
8
- import {
9
- FunctionCallHandler,
10
- AnnotatedFunction,
11
- annotatedFunctionToChatCompletionFunction,
12
- } from "@copilotkit/shared";
7
+ import { FunctionCallHandler, actionToChatCompletionFunction } from "@copilotkit/shared";
8
+ import { FrontendAction } from "../../types/frontend-action";
13
9
  import useFlatCategoryStore from "../../hooks/use-flat-category-store";
14
10
  import { StandardCopilotApiConfig } from "./standard-copilot-api-config";
15
11
  import { CopilotKitProps } from "./copilotkit-props";
@@ -56,8 +52,8 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
56
52
  // Compute all the functions and properties that we need to pass
57
53
  // to the CopilotContext.
58
54
 
59
- const [entryPoints, setEntryPoints] = useState<Record<string, AnnotatedFunction<any[]>>>({});
60
-
55
+ const [entryPoints, setEntryPoints] = useState<Record<string, FrontendAction<any>>>({});
56
+ const chatComponentsCache = useRef<Record<string, Function | string>>({});
61
57
  const { addElement, removeElement, printTree } = useTree();
62
58
 
63
59
  const {
@@ -66,7 +62,7 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
66
62
  allElements: allDocuments,
67
63
  } = useFlatCategoryStore<DocumentPointer>();
68
64
 
69
- const setEntryPoint = useCallback((id: string, entryPoint: AnnotatedFunction<any[]>) => {
65
+ const setEntryPoint = useCallback((id: string, entryPoint: FrontendAction<any>) => {
70
66
  setEntryPoints((prevPoints) => {
71
67
  return {
72
68
  ...prevPoints,
@@ -117,14 +113,14 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
117
113
  );
118
114
 
119
115
  const getChatCompletionFunctionDescriptions = useCallback(
120
- (customEntryPoints?: Record<string, AnnotatedFunction<any[]>>) => {
116
+ (customEntryPoints?: Record<string, FrontendAction<any>>) => {
121
117
  return entryPointsToChatCompletionFunctions(Object.values(customEntryPoints || entryPoints));
122
118
  },
123
119
  [entryPoints],
124
120
  );
125
121
 
126
122
  const getFunctionCallHandler = useCallback(
127
- (customEntryPoints?: Record<string, AnnotatedFunction<any[]>>) => {
123
+ (customEntryPoints?: Record<string, FrontendAction<any>>) => {
128
124
  return entryPointsToFunctionCallHandler(Object.values(customEntryPoints || entryPoints));
129
125
  },
130
126
  [entryPoints],
@@ -166,6 +162,7 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
166
162
  <CopilotContext.Provider
167
163
  value={{
168
164
  entryPoints,
165
+ chatComponentsCache,
169
166
  getChatCompletionFunctionDescriptions,
170
167
  getFunctionCallHandler,
171
168
  setEntryPoint,
@@ -186,54 +183,24 @@ export function CopilotKit({ children, ...props }: CopilotKitProps) {
186
183
 
187
184
  export const defaultCopilotContextCategories = ["global"];
188
185
 
189
- function entryPointsToFunctionCallHandler(
190
- entryPoints: AnnotatedFunction<any[]>[],
191
- ): FunctionCallHandler {
186
+ function entryPointsToChatCompletionFunctions(actions: FrontendAction<any>[]): ToolDefinition[] {
187
+ return actions.map(actionToChatCompletionFunction);
188
+ }
189
+
190
+ function entryPointsToFunctionCallHandler(actions: FrontendAction<any>[]): FunctionCallHandler {
192
191
  return async (chatMessages, functionCall) => {
193
- let entrypointsByFunctionName: Record<string, AnnotatedFunction<any[]>> = {};
194
- for (let entryPoint of entryPoints) {
195
- entrypointsByFunctionName[entryPoint.name] = entryPoint;
192
+ let actionsByFunctionName: Record<string, FrontendAction<any>> = {};
193
+ for (let action of actions) {
194
+ actionsByFunctionName[action.name] = action;
196
195
  }
197
196
 
198
- const entryPointFunction = entrypointsByFunctionName[functionCall.name || ""];
199
- if (entryPointFunction) {
197
+ const action = actionsByFunctionName[functionCall.name || ""];
198
+ if (action) {
200
199
  let functionCallArguments: Record<string, any>[] = [];
201
200
  if (functionCall.arguments) {
202
201
  functionCallArguments = JSON.parse(functionCall.arguments);
203
202
  }
204
-
205
- const paramsInCorrectOrder: any[] = [];
206
- for (let arg of entryPointFunction.argumentAnnotations) {
207
- paramsInCorrectOrder.push(
208
- functionCallArguments[arg.name as keyof typeof functionCallArguments],
209
- );
210
- }
211
-
212
- await entryPointFunction.implementation(...paramsInCorrectOrder);
213
-
214
- // commented out becasue for now we don't want to return anything
215
- // const result = await entryPointFunction.implementation(
216
- // ...parsedFunctionCallArguments
217
- // );
218
- // const functionResponse: ChatRequest = {
219
- // messages: [
220
- // ...chatMessages,
221
- // {
222
- // id: nanoid(),
223
- // name: functionCall.name,
224
- // role: 'function' as const,
225
- // content: JSON.stringify(result),
226
- // },
227
- // ],
228
- // };
229
-
230
- // return functionResponse;
203
+ return await action.handler(functionCallArguments);
231
204
  }
232
205
  };
233
206
  }
234
-
235
- function entryPointsToChatCompletionFunctions(
236
- entryPoints: AnnotatedFunction<any[]>[],
237
- ): ToolDefinition[] {
238
- return entryPoints.map(annotatedFunctionToChatCompletionFunction);
239
- }
@@ -1,7 +1,8 @@
1
1
  "use client";
2
2
 
3
- import { FunctionCallHandler, AnnotatedFunction, ToolDefinition } from "@copilotkit/shared";
4
- import React from "react";
3
+ import { FunctionCallHandler, ToolDefinition } from "@copilotkit/shared";
4
+ import { FrontendAction } from "../types/frontend-action";
5
+ import React, { Ref } from "react";
5
6
  import { TreeNodeId } from "../hooks/use-tree";
6
7
  import { DocumentPointer } from "../types";
7
8
 
@@ -58,14 +59,15 @@ export interface CopilotApiConfig {
58
59
 
59
60
  export interface CopilotContextParams {
60
61
  // function-calling
61
- entryPoints: Record<string, AnnotatedFunction<any[]>>;
62
- setEntryPoint: (id: string, entryPoint: AnnotatedFunction<any[]>) => void;
62
+ entryPoints: Record<string, FrontendAction<any>>;
63
+ setEntryPoint: (id: string, entryPoint: FrontendAction<any>) => void;
63
64
  removeEntryPoint: (id: string) => void;
65
+ chatComponentsCache: React.RefObject<Record<string, Function | string>>;
64
66
  getChatCompletionFunctionDescriptions: (
65
- customEntryPoints?: Record<string, AnnotatedFunction<any[]>>,
67
+ customEntryPoints?: Record<string, FrontendAction<any>>,
66
68
  ) => ToolDefinition[];
67
69
  getFunctionCallHandler: (
68
- customEntryPoints?: Record<string, AnnotatedFunction<any[]>>,
70
+ customEntryPoints?: Record<string, FrontendAction<any>>,
69
71
  ) => FunctionCallHandler;
70
72
 
71
73
  // text context
@@ -88,7 +90,7 @@ const emptyCopilotContext: CopilotContextParams = {
88
90
  removeEntryPoint: () => {},
89
91
  getChatCompletionFunctionDescriptions: () => returnAndThrowInDebug([]),
90
92
  getFunctionCallHandler: () => returnAndThrowInDebug(async () => {}),
91
-
93
+ chatComponentsCache: { current: {} },
92
94
  getContextString: (documents: DocumentPointer[], categories: string[]) =>
93
95
  returnAndThrowInDebug(""),
94
96
  addContext: () => "",
@@ -3,6 +3,7 @@ export type { UseCopilotChatOptions } from "./use-copilot-chat";
3
3
  export type { UseCopilotChatReturn } from "./use-copilot-chat";
4
4
 
5
5
  export { useMakeCopilotActionable } from "./use-make-copilot-actionable";
6
+ export { useCopilotAction } from "./use-copilot-action";
6
7
  export { useMakeCopilotReadable } from "./use-make-copilot-readable";
7
8
  export { useMakeCopilotDocumentReadable } from "./use-make-copilot-document-readable";
8
9
  export { type UseChatHelpers } from "./use-chat";
@@ -1,8 +1,16 @@
1
1
  import { useRef, useState } from "react";
2
- import { Message, ToolDefinition, FunctionCallHandler, encodeResult } from "@copilotkit/shared";
2
+ import {
3
+ Message,
4
+ ToolDefinition,
5
+ FunctionCallHandler,
6
+ encodeResult,
7
+ FunctionCall,
8
+ } from "@copilotkit/shared";
9
+
3
10
  import { nanoid } from "nanoid";
4
11
  import { fetchAndDecodeChatCompletion } from "../utils/fetch-chat-completion";
5
12
  import { CopilotApiConfig } from "../context";
13
+ import untruncateJson from "untruncate-json";
6
14
 
7
15
  export type UseChatOptions = {
8
16
  /**
@@ -176,7 +184,7 @@ export function useChat(options: UseChatOptionsWithCopilotConfig): UseChatHelper
176
184
 
177
185
  // After receiving a result, feed back the new messages to GPT
178
186
  feedback = true;
179
- } else if (value.type === "function") {
187
+ } else if (value.type === "function" || value.type === "partial") {
180
188
  // Create a new message if the previous one is not empty
181
189
  if (
182
190
  currentMessage.content != "" ||
@@ -191,36 +199,53 @@ export function useChat(options: UseChatOptionsWithCopilotConfig): UseChatHelper
191
199
  };
192
200
  newMessages.push(currentMessage);
193
201
  }
194
- currentMessage.function_call = {
195
- name: value.name,
196
- arguments: JSON.stringify(value.arguments),
197
- scope: value.scope,
198
- };
202
+ if (value.type === "function") {
203
+ currentMessage.function_call = {
204
+ name: value.name,
205
+ arguments: JSON.stringify(value.arguments),
206
+ scope: value.scope,
207
+ };
208
+ } else if (value.type === "partial") {
209
+ let partialArguments: any = {};
210
+ try {
211
+ partialArguments = JSON.parse(untruncateJson(value.arguments));
212
+ } catch (e) {}
213
+
214
+ currentMessage.partialFunctionCall = {
215
+ name: value.name,
216
+ arguments: partialArguments,
217
+ };
218
+ }
199
219
 
200
220
  newMessages[newMessages.length - 1] = currentMessage;
201
221
  setMessages([...messages, ...newMessages]);
202
222
 
203
- // Execute the function call
204
- try {
205
- if (options.onFunctionCall && value.scope === "client") {
206
- const result = await options.onFunctionCall(messages, currentMessage.function_call);
207
-
208
- currentMessage = {
209
- id: nanoid(),
210
- role: "function",
211
- content: encodeResult(result),
212
- name: currentMessage.function_call!.name!,
213
- };
214
- newMessages.push(currentMessage);
215
- setMessages([...messages, ...newMessages]);
216
-
217
- // After a function call, feed back the new messages to GPT
218
- feedback = true;
223
+ if (value.type === "function") {
224
+ // Execute the function call
225
+ try {
226
+ if (options.onFunctionCall && value.scope === "client") {
227
+ const result = await options.onFunctionCall(
228
+ messages,
229
+ currentMessage.function_call as FunctionCall,
230
+ );
231
+
232
+ currentMessage = {
233
+ id: nanoid(),
234
+ role: "function",
235
+ content: encodeResult(result),
236
+ name: (currentMessage.function_call! as FunctionCall).name!,
237
+ };
238
+ newMessages.push(currentMessage);
239
+ setMessages([...messages, ...newMessages]);
240
+
241
+ // After a function call, feed back the new messages to GPT
242
+ feedback = true;
243
+ }
244
+ } catch (error) {
245
+ console.error("Failed to execute function call", error);
246
+ // TODO: Handle error
247
+ // this should go to the message itself
219
248
  }
220
- } catch (error) {
221
- console.error("Failed to execute function call", error);
222
- // TODO: Handle error
223
- // this should go to the message itself
224
249
  }
225
250
  }
226
251
  }
@@ -0,0 +1,114 @@
1
+ "use client";
2
+
3
+ import { AnnotatedFunction, Parameter } from "@copilotkit/shared";
4
+ import { useRef, useContext, useEffect } from "react";
5
+ import { FrontendAction } from "../types/frontend-action";
6
+ import { CopilotContext } from "../context/copilot-context";
7
+ import { nanoid } from "nanoid";
8
+
9
+ // We implement useCopilotActionImplementation dependency handling so that
10
+ // the developer has the option to not provide any dependencies.
11
+ // In this case, we assume they want to update the handler on each rerender.
12
+ // To avoid getting stuck in an infinite loop, we update the handler directly,
13
+ // skipping React state updates.
14
+ // This is ok in this case, because the handler is not part of any UI that
15
+ // needs to be updated.
16
+ // useCallback, useMemo or other memoization techniques are not suitable here,
17
+ // because they will cause a infinite rerender loop.
18
+ export function useCopilotActionImplementation<T extends Array<any> = []>(
19
+ action: FrontendAction<T>,
20
+ dependencies?: any[],
21
+ ): void {
22
+ const { setEntryPoint, removeEntryPoint, entryPoints, chatComponentsCache } =
23
+ useContext(CopilotContext);
24
+ const idRef = useRef<string>(nanoid());
25
+
26
+ // If the developer doesn't provide dependencies, we assume they want to
27
+ // update handler and render function when the action object changes.
28
+ // This ensures that any captured variables in the handler are up to date.
29
+ if (dependencies === undefined) {
30
+ if (entryPoints[idRef.current]) {
31
+ entryPoints[idRef.current].handler = action.handler;
32
+ if (typeof action.render === "function") {
33
+ if (chatComponentsCache.current !== null) {
34
+ chatComponentsCache.current[action.name] = action.render;
35
+ }
36
+ }
37
+ }
38
+ }
39
+
40
+ useEffect(() => {
41
+ setEntryPoint(idRef.current, action);
42
+ if (chatComponentsCache.current !== null && action.render !== undefined) {
43
+ chatComponentsCache.current[action.name] = action.render;
44
+ }
45
+ return () => {
46
+ // NOTE: For now, we don't remove the chatComponentsCache entry when the action is removed.
47
+ // This is because we currently don't have access to the messages array in CopilotContext.
48
+ removeEntryPoint(idRef.current);
49
+ };
50
+ }, [
51
+ setEntryPoint,
52
+ removeEntryPoint,
53
+ action.description,
54
+ action.name,
55
+ // This should be faster than deep equality checking
56
+ // In addition, all major JS engines guarantee the order of object keys
57
+ JSON.stringify(action.parameters),
58
+ // include render only if it's a string
59
+ typeof action.render === "string" ? action.render : undefined,
60
+ // dependencies set by the developer
61
+ ...(dependencies || []),
62
+ ]);
63
+ }
64
+
65
+ export function annotatedFunctionToAction(
66
+ annotatedFunction: AnnotatedFunction<any[]>,
67
+ ): FrontendAction<any> {
68
+ const parameters: Parameter[] = annotatedFunction.argumentAnnotations.map((annotation) => {
69
+ switch (annotation.type) {
70
+ case "string":
71
+ case "number":
72
+ case "boolean":
73
+ case "object":
74
+ return {
75
+ name: annotation.name,
76
+ description: annotation.description,
77
+ type: annotation.type,
78
+ required: annotation.required,
79
+ };
80
+ case "array":
81
+ let type;
82
+ if (annotation.items.type === "string") {
83
+ type = "string[]";
84
+ } else if (annotation.items.type === "number") {
85
+ type = "number[]";
86
+ } else if (annotation.items.type === "boolean") {
87
+ type = "boolean[]";
88
+ } else if (annotation.items.type === "object") {
89
+ type = "object[]";
90
+ } else {
91
+ type = "string[]";
92
+ }
93
+ return {
94
+ name: annotation.name,
95
+ description: annotation.description,
96
+ type: type as any,
97
+ required: annotation.required,
98
+ };
99
+ }
100
+ });
101
+
102
+ return {
103
+ name: annotatedFunction.name,
104
+ description: annotatedFunction.description,
105
+ parameters: parameters,
106
+ handler: (args) => {
107
+ const paramsInCorrectOrder: any[] = [];
108
+ for (let arg of annotatedFunction.argumentAnnotations) {
109
+ paramsInCorrectOrder.push(args[arg.name]);
110
+ }
111
+ return annotatedFunction.implementation(...paramsInCorrectOrder);
112
+ },
113
+ };
114
+ }
@@ -0,0 +1,45 @@
1
+ "use client";
2
+
3
+ import { Parameter } from "@copilotkit/shared";
4
+ import { FrontendAction } from "../types/frontend-action";
5
+ import { useCopilotActionImplementation } from "./use-copilot-action-implementation";
6
+
7
+ // Prettier chokes on the `const` in the function signature
8
+ // To have the main implementation checked by prettier, we split
9
+ // this into a separate file
10
+ // prettier-ignore
11
+ export function useCopilotAction<const T extends Parameter[] | [] = []>(action: FrontendAction<T>, dependencies?: any[]): void {
12
+ return useCopilotActionImplementation(action, dependencies);
13
+ }
14
+
15
+ // Usage Example:
16
+ // useCopilotAction({
17
+ // name: "myAction",
18
+ // parameters: [
19
+ // { name: "arg1", type: "string", enum: ["option1", "option2", "option3"], required: false },
20
+ // { name: "arg2", type: "number" },
21
+ // {
22
+ // name: "arg3",
23
+ // type: "object",
24
+ // attributes: [
25
+ // { name: "nestedArg1", type: "boolean" },
26
+ // { name: "xyz", required: false },
27
+ // ],
28
+ // },
29
+ // { name: "arg4", type: "number[]" },
30
+ // ],
31
+ // handler: ({ arg1, arg2, arg3, arg4 }) => {
32
+ // const x = arg3.nestedArg1;
33
+ // const z = arg3.xyz;
34
+ // console.log(arg1, arg2, arg3);
35
+ // },
36
+ // });
37
+
38
+ // useCopilotAction({
39
+ // name: "myAction",
40
+ // handler: () => {
41
+ // console.log("No parameters provided.");
42
+ // },
43
+ // });
44
+
45
+ // https://community.openai.com/t/function-call-complex-arrays-as-parameters/295648/3
@@ -61,7 +61,8 @@ export function useCopilotChat({
61
61
  });
62
62
 
63
63
  const visibleMessages = messages.filter(
64
- (message) => message.role === "user" || message.role === "assistant",
64
+ (message) =>
65
+ message.role === "user" || message.role === "assistant" || message.role === "function",
65
66
  );
66
67
 
67
68
  return {
@@ -4,7 +4,11 @@ import { useRef, useContext, useEffect, useMemo } from "react";
4
4
  import { CopilotContext } from "../context/copilot-context";
5
5
  import { AnnotatedFunction } from "@copilotkit/shared";
6
6
  import { nanoid } from "nanoid";
7
+ import { annotatedFunctionToAction } from "./use-copilot-action-implementation";
7
8
 
9
+ /**
10
+ * @deprecated Use the useCopilotAction function instead.
11
+ */
8
12
  export function useMakeCopilotActionable<ActionInput extends any[]>(
9
13
  annotatedFunction: AnnotatedFunction<ActionInput>,
10
14
  dependencies: any[],
@@ -23,7 +27,8 @@ export function useMakeCopilotActionable<ActionInput extends any[]>(
23
27
  );
24
28
 
25
29
  useEffect(() => {
26
- setEntryPoint(idRef.current, memoizedAnnotatedFunction as AnnotatedFunction<any[]>);
30
+ const action = annotatedFunctionToAction(memoizedAnnotatedFunction as AnnotatedFunction<any[]>);
31
+ setEntryPoint(idRef.current, action);
27
32
 
28
33
  return () => {
29
34
  removeEntryPoint(idRef.current);
@@ -1,4 +1,5 @@
1
- import { AnnotatedFunction, FunctionCall, Message } from "@copilotkit/shared";
1
+ import { FunctionCall, Message } from "@copilotkit/shared";
2
+ import { FrontendAction } from "../types/frontend-action";
2
3
  import { CopilotContextParams } from "../context";
3
4
  import { defaultCopilotContextCategories } from "../components";
4
5
  import { fetchAndDecodeChatCompletion } from "../utils/fetch-chat-completion";
@@ -11,7 +12,7 @@ export interface CopilotTaskConfig {
11
12
  /**
12
13
  * Action definitions to be sent to the API.
13
14
  */
14
- actions?: AnnotatedFunction<any[]>[];
15
+ actions?: FrontendAction<any>[];
15
16
  /**
16
17
  * Whether to include the copilot readable context in the task.
17
18
  */
@@ -25,13 +26,13 @@ export interface CopilotTaskConfig {
25
26
 
26
27
  export class CopilotTask<T = any> {
27
28
  private instructions: string;
28
- private functions: AnnotatedFunction<any[]>[];
29
+ private actions: FrontendAction<any>[];
29
30
  private includeCopilotReadable: boolean;
30
31
  private includeCopilotActionable: boolean;
31
32
 
32
33
  constructor(config: CopilotTaskConfig) {
33
34
  this.instructions = config.instructions;
34
- this.functions = config.actions || [];
35
+ this.actions = config.actions || [];
35
36
  this.includeCopilotReadable = config.includeCopilotReadable || true;
36
37
  this.includeCopilotActionable = config.includeCopilotActionable || true;
37
38
  }
@@ -40,7 +41,7 @@ export class CopilotTask<T = any> {
40
41
  const entryPoints = this.includeCopilotActionable ? Object.assign({}, context.entryPoints) : {};
41
42
 
42
43
  // merge functions into entry points
43
- for (const fn of this.functions) {
44
+ for (const fn of this.actions) {
44
45
  entryPoints[fn.name] = fn;
45
46
  }
46
47
 
@@ -0,0 +1,56 @@
1
+ import { Action, Parameter, MappedParameterTypes } from "@copilotkit/shared";
2
+ import React from "react";
3
+
4
+ interface InProgressState<T extends Parameter[] | [] = []> {
5
+ status: "inProgress";
6
+ args: Partial<MappedParameterTypes<T>>;
7
+ result: undefined;
8
+ }
9
+
10
+ interface ExecutingState<T extends Parameter[] | [] = []> {
11
+ status: "executing";
12
+ args: MappedParameterTypes<T>;
13
+ result: undefined;
14
+ }
15
+
16
+ interface CompleteState<T extends Parameter[] | [] = []> {
17
+ status: "complete";
18
+ args: MappedParameterTypes<T>;
19
+ result: any;
20
+ }
21
+
22
+ interface InProgressStateNoArgs<T extends Parameter[] | [] = []> {
23
+ status: "inProgress";
24
+ args: Partial<MappedParameterTypes<T>>;
25
+ result: undefined;
26
+ }
27
+
28
+ interface ExecutingStateNoArgs<T extends Parameter[] | [] = []> {
29
+ status: "executing";
30
+ args: MappedParameterTypes<T>;
31
+ result: undefined;
32
+ }
33
+
34
+ interface CompleteStateNoArgs<T extends Parameter[] | [] = []> {
35
+ status: "complete";
36
+ args: MappedParameterTypes<T>;
37
+ result: any;
38
+ }
39
+
40
+ export type ActionRenderProps<T extends Parameter[] | [] = []> =
41
+ | CompleteState<T>
42
+ | ExecutingState<T>
43
+ | InProgressState<T>;
44
+
45
+ export type ActionRenderPropsNoArgs<T extends Parameter[] | [] = []> =
46
+ | CompleteStateNoArgs<T>
47
+ | ExecutingStateNoArgs<T>
48
+ | InProgressStateNoArgs<T>;
49
+
50
+ export type FrontendAction<T extends Parameter[] | [] = []> = Action<T> & {
51
+ render?:
52
+ | string
53
+ | (T extends []
54
+ ? (props: ActionRenderPropsNoArgs<T>) => string | React.ReactElement
55
+ : (props: ActionRenderProps<T>) => string | React.ReactElement);
56
+ };