forked from CopilotKit/CopilotKit
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathuse-copilot-readable.ts
More file actions
135 lines (127 loc) · 3.88 KB
/
Copy pathuse-copilot-readable.ts
File metadata and controls
135 lines (127 loc) · 3.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
/**
* `useCopilotReadable` is a React hook that provides app-state and other information
* to the Copilot. Optionally, the hook can also handle hierarchical state within your
* application, passing these parent-child relationships to the Copilot.
*
* ## Usage
*
* ### Simple Usage
*
* In its most basic usage, useCopilotReadable accepts a single string argument
* representing any piece of app state, making it available for the Copilot to use
* as context when responding to user input.
*
* ```tsx
* import { useCopilotReadable } from "@copilotkit/react-core";
*
* export function MyComponent() {
* const [employees, setEmployees] = useState([]);
*
* useCopilotReadable({
* description: "The list of employees",
* value: employees,
* });
* }
* ```
*
* ### Nested Components
*
* Optionally, you can maintain the hierarchical structure of information by passing
* `parentId`. This allows you to use `useCopilotReadable` in nested components:
*
* ```tsx /employeeContextId/1 {17,23}
* import { useCopilotReadable } from "@copilotkit/react-core";
*
* function Employee(props: EmployeeProps) {
* const { employeeName, workProfile, metadata } = props;
*
* // propagate any information to copilot
* const employeeContextId = useCopilotReadable({
* description: "Employee name",
* value: employeeName
* });
*
* // Pass a parentID to maintain a hierarchical structure.
* // Especially useful with child React components, list elements, etc.
* useCopilotReadable({
* description: "Work profile",
* value: workProfile.description(),
* parentId: employeeContextId
* });
*
* useCopilotReadable({
* description: "Employee metadata",
* value: metadata.description(),
* parentId: employeeContextId
* });
*
* return (
* // Render as usual...
* );
* }
* ```
*/
import { useCopilotKit } from "../v2";
import { useEffect, useRef } from "react";
/**
* Options for the useCopilotReadable hook.
*/
export interface UseCopilotReadableOptions {
/**
* The description of the information to be added to the Copilot context.
*/
description: string;
/**
* The value to be added to the Copilot context. Object values are automatically stringified.
*/
value: any;
/**
* The ID of the parent context, if any.
*/
parentId?: string;
/**
* An array of categories to control which context are visible where. Particularly useful
* with CopilotTextarea (see `useMakeAutosuggestionFunction`)
*/
categories?: string[];
/**
* Whether the context is available to the Copilot.
*/
available?: "enabled" | "disabled";
/**
* A custom conversion function to use to serialize the value to a string. If not provided, the value
* will be serialized using `JSON.stringify`.
*/
convert?: (description: string, value: any) => string;
}
/**
* Adds the given information to the Copilot context to make it readable by Copilot.
*/
export function useCopilotReadable(
{ description, value, convert, available }: UseCopilotReadableOptions,
dependencies?: any[],
): string | undefined {
const { copilotkit } = useCopilotKit();
const ctxIdRef = useRef<string | undefined>(undefined);
useEffect(() => {
if (!copilotkit) return;
const found = Object.entries(copilotkit.context).find(([id, ctxItem]) => {
return JSON.stringify({ description, value }) == JSON.stringify(ctxItem);
});
if (found) {
ctxIdRef.current = found[0];
if (available === "disabled") copilotkit.removeContext(ctxIdRef.current);
return;
}
if (!found && available === "disabled") return;
ctxIdRef.current = copilotkit.addContext({
description,
value: (convert ?? JSON.stringify)(value),
});
return () => {
if (!ctxIdRef.current) return;
copilotkit.removeContext(ctxIdRef.current);
};
}, [description, value, convert]);
return ctxIdRef.current;
}