@copilotkit/react-core 1.57.0 → 1.57.1-canary.1778272612
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.
- package/dist/{copilotkit-CPe2-340.mjs → copilotkit-3XTEoVQO.mjs} +1367 -1200
- package/dist/copilotkit-3XTEoVQO.mjs.map +1 -0
- package/dist/{copilotkit-DFaI4j2r.d.mts → copilotkit-BCJ2yvV6.d.mts} +68 -8
- package/dist/copilotkit-BCJ2yvV6.d.mts.map +1 -0
- package/dist/{copilotkit-Dg4r4Gi_.d.cts → copilotkit-CBbSvze0.d.cts} +68 -8
- package/dist/copilotkit-CBbSvze0.d.cts.map +1 -0
- package/dist/{copilotkit-DGbvw8n2.cjs → copilotkit-Dnj9pi4m.cjs} +1369 -1196
- package/dist/copilotkit-Dnj9pi4m.cjs.map +1 -0
- package/dist/index.cjs +2 -5
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -5
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +733 -610
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/context.cjs +135 -0
- package/dist/v2/context.cjs.map +1 -0
- package/dist/v2/context.d.cts +148 -0
- package/dist/v2/context.d.cts.map +1 -0
- package/dist/v2/context.d.mts +148 -0
- package/dist/v2/context.d.mts.map +1 -0
- package/dist/v2/context.mjs +129 -0
- package/dist/v2/context.mjs.map +1 -0
- package/dist/v2/headless.cjs +1043 -0
- package/dist/v2/headless.cjs.map +1 -0
- package/dist/v2/headless.d.cts +605 -0
- package/dist/v2/headless.d.cts.map +1 -0
- package/dist/v2/headless.d.mts +512 -0
- package/dist/v2/headless.d.mts.map +1 -0
- package/dist/v2/headless.mjs +997 -0
- package/dist/v2/headless.mjs.map +1 -0
- package/dist/v2/index.cjs +2 -1
- package/dist/v2/index.css +1 -1
- package/dist/v2/index.d.cts +2 -2
- package/dist/v2/index.d.mts +2 -2
- package/dist/v2/index.mjs +2 -2
- package/dist/v2/index.umd.js +1385 -1204
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +14 -6
- package/src/hooks/__tests__/use-copilot-chat-internal-connect.test.tsx +5 -6
- package/src/hooks/use-copilot-chat_internal.ts +0 -1
- package/src/v2/components/chat/CopilotChat.tsx +2 -1
- package/src/v2/components/chat/CopilotChatMessageView.tsx +24 -9
- package/src/v2/components/chat/CopilotChatView.tsx +2 -2
- package/src/v2/components/chat/CopilotSidebar.tsx +5 -1
- package/src/v2/components/chat/CopilotSidebarView.tsx +24 -10
- package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +1 -3
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +29 -25
- package/src/v2/components/chat/__tests__/CopilotSidebarView.position.test.tsx +159 -0
- package/src/v2/components/chat/__tests__/MCPAppsUiMessage.e2e.test.tsx +5 -60
- package/src/v2/components/index.ts +1 -0
- package/src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx +286 -0
- package/src/v2/components/intelligence-indicator/__tests__/IntelligenceIndicator.e2e.test.tsx +464 -0
- package/src/v2/components/intelligence-indicator/index.ts +2 -0
- package/src/v2/context.ts +62 -0
- package/src/v2/headless.ts +42 -0
- package/src/v2/hooks/__tests__/standard-schema.test.tsx +2 -2
- package/src/v2/hooks/__tests__/use-agent-context.test.tsx +3 -3
- package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +3 -3
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +85 -85
- package/src/v2/hooks/__tests__/use-interrupt.test.tsx +2 -2
- package/src/v2/hooks/__tests__/use-render-tool.test.tsx +2 -2
- package/src/v2/hooks/__tests__/use-threads.test.tsx +2 -2
- package/src/v2/hooks/__tests__/zod-regression.test.tsx +2 -2
- package/src/v2/hooks/use-agent-context.tsx +1 -1
- package/src/v2/hooks/use-agent.tsx +9 -118
- package/src/v2/hooks/use-configure-suggestions.tsx +1 -1
- package/src/v2/hooks/use-default-render-tool.tsx +18 -1
- package/src/v2/hooks/use-frontend-tool.tsx +2 -2
- package/src/v2/hooks/use-human-in-the-loop.tsx +1 -1
- package/src/v2/hooks/use-interrupt.tsx +1 -1
- package/src/v2/hooks/use-render-activity-message.tsx +3 -11
- package/src/v2/hooks/use-render-custom-messages.tsx +1 -6
- package/src/v2/hooks/use-render-tool-call.tsx +36 -6
- package/src/v2/hooks/use-render-tool.tsx +2 -2
- package/src/v2/hooks/use-suggestions.tsx +1 -1
- package/src/v2/hooks/use-threads.tsx +1 -1
- package/src/v2/providers/CopilotKitProvider.tsx +19 -59
- package/src/v2/styles/globals.css +118 -0
- package/tsdown.config.ts +75 -0
- package/dist/copilotkit-CPe2-340.mjs.map +0 -1
- package/dist/copilotkit-DFaI4j2r.d.mts.map +0 -1
- package/dist/copilotkit-DGbvw8n2.cjs.map +0 -1
- package/dist/copilotkit-Dg4r4Gi_.d.cts.map +0 -1
- package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +0 -333
|
@@ -0,0 +1,1043 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
2
|
+
//#region \0rolldown/runtime.js
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __copyProps = (to, from, except, desc) => {
|
|
10
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
11
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
12
|
+
key = keys[i];
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
14
|
+
__defProp(to, key, {
|
|
15
|
+
get: ((k) => from[k]).bind(null, key),
|
|
16
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
24
|
+
value: mod,
|
|
25
|
+
enumerable: true
|
|
26
|
+
}) : target, mod));
|
|
27
|
+
|
|
28
|
+
//#endregion
|
|
29
|
+
let _copilotkit_react_core_v2_context = require("@copilotkit/react-core/v2/context");
|
|
30
|
+
let react = require("react");
|
|
31
|
+
react = __toESM(react);
|
|
32
|
+
let _copilotkit_shared = require("@copilotkit/shared");
|
|
33
|
+
let tailwind_merge = require("tailwind-merge");
|
|
34
|
+
let react_jsx_runtime = require("react/jsx-runtime");
|
|
35
|
+
let _ag_ui_client = require("@ag-ui/client");
|
|
36
|
+
let _copilotkit_core = require("@copilotkit/core");
|
|
37
|
+
|
|
38
|
+
//#region src/v2/lib/slots.tsx
|
|
39
|
+
/**
|
|
40
|
+
* Shallow equality comparison for objects.
|
|
41
|
+
*/
|
|
42
|
+
function shallowEqual(obj1, obj2) {
|
|
43
|
+
const keys1 = Object.keys(obj1);
|
|
44
|
+
const keys2 = Object.keys(obj2);
|
|
45
|
+
if (keys1.length !== keys2.length) return false;
|
|
46
|
+
for (const key of keys1) if (obj1[key] !== obj2[key]) return false;
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Returns true only for plain JS objects (`{}`), excluding arrays, Dates,
|
|
51
|
+
* class instances, and other exotic objects that happen to have typeof "object".
|
|
52
|
+
*/
|
|
53
|
+
function isPlainObject(obj) {
|
|
54
|
+
return obj !== null && typeof obj === "object" && Object.prototype.toString.call(obj) === "[object Object]";
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Returns the same reference as long as the value is shallowly equal to the
|
|
58
|
+
* previous render's value.
|
|
59
|
+
*
|
|
60
|
+
* - Identical references bail out immediately (O(1)).
|
|
61
|
+
* - Plain objects ({}) are shallow-compared key-by-key.
|
|
62
|
+
* - Arrays, Dates, class instances, functions, and primitives are compared by
|
|
63
|
+
* reference only — shallowEqual is never called on non-plain objects, which
|
|
64
|
+
* avoids incorrect equality for e.g. [1,2] vs [1,2] (different arrays).
|
|
65
|
+
*
|
|
66
|
+
* Typical use: stabilize inline slot props so MemoizedSlotWrapper's shallow
|
|
67
|
+
* equality check isn't defeated by a new object reference on every render.
|
|
68
|
+
*/
|
|
69
|
+
function useShallowStableRef(value) {
|
|
70
|
+
const ref = (0, react.useRef)(value);
|
|
71
|
+
if (ref.current === value) return ref.current;
|
|
72
|
+
if (isPlainObject(ref.current) && isPlainObject(value)) {
|
|
73
|
+
if (shallowEqual(ref.current, value)) return ref.current;
|
|
74
|
+
}
|
|
75
|
+
ref.current = value;
|
|
76
|
+
return ref.current;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Check if a value is a React component type (function, class, forwardRef, memo, etc.)
|
|
80
|
+
*/
|
|
81
|
+
function isReactComponentType(value) {
|
|
82
|
+
if (typeof value === "function") return true;
|
|
83
|
+
if (value && typeof value === "object" && "$$typeof" in value && !react.default.isValidElement(value)) return true;
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Internal function to render a slot value as a React element (non-memoized).
|
|
88
|
+
*/
|
|
89
|
+
function renderSlotElement(slot, DefaultComponent, props) {
|
|
90
|
+
if (typeof slot === "string") {
|
|
91
|
+
const existingClassName = props.className;
|
|
92
|
+
return react.default.createElement(DefaultComponent, {
|
|
93
|
+
...props,
|
|
94
|
+
className: (0, tailwind_merge.twMerge)(existingClassName, slot)
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (isReactComponentType(slot)) return react.default.createElement(slot, props);
|
|
98
|
+
if (slot && typeof slot === "object" && !react.default.isValidElement(slot)) return react.default.createElement(DefaultComponent, {
|
|
99
|
+
...props,
|
|
100
|
+
...slot
|
|
101
|
+
});
|
|
102
|
+
return react.default.createElement(DefaultComponent, props);
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Internal memoized wrapper component for renderSlot.
|
|
106
|
+
* Uses forwardRef to support ref forwarding.
|
|
107
|
+
*/
|
|
108
|
+
const MemoizedSlotWrapper = react.default.memo(react.default.forwardRef(function MemoizedSlotWrapper(props, ref) {
|
|
109
|
+
const { $slot, $component, ...rest } = props;
|
|
110
|
+
return renderSlotElement($slot, $component, ref !== null ? {
|
|
111
|
+
...rest,
|
|
112
|
+
ref
|
|
113
|
+
} : rest);
|
|
114
|
+
}), (prev, next) => {
|
|
115
|
+
if (prev.$slot !== next.$slot) return false;
|
|
116
|
+
if (prev.$component !== next.$component) return false;
|
|
117
|
+
const { $slot: _ps, $component: _pc, ...prevRest } = prev;
|
|
118
|
+
const { $slot: _ns, $component: _nc, ...nextRest } = next;
|
|
119
|
+
return shallowEqual(prevRest, nextRest);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
//#endregion
|
|
123
|
+
//#region src/v2/providers/CopilotChatConfigurationProvider.tsx
|
|
124
|
+
const CopilotChatDefaultLabels = {
|
|
125
|
+
chatInputPlaceholder: "Type a message...",
|
|
126
|
+
chatInputToolbarStartTranscribeButtonLabel: "Transcribe",
|
|
127
|
+
chatInputToolbarCancelTranscribeButtonLabel: "Cancel",
|
|
128
|
+
chatInputToolbarFinishTranscribeButtonLabel: "Finish",
|
|
129
|
+
chatInputToolbarAddButtonLabel: "Add attachments",
|
|
130
|
+
chatInputToolbarToolsButtonLabel: "Tools",
|
|
131
|
+
assistantMessageToolbarCopyCodeLabel: "Copy",
|
|
132
|
+
assistantMessageToolbarCopyCodeCopiedLabel: "Copied",
|
|
133
|
+
assistantMessageToolbarCopyMessageLabel: "Copy",
|
|
134
|
+
assistantMessageToolbarThumbsUpLabel: "Good response",
|
|
135
|
+
assistantMessageToolbarThumbsDownLabel: "Bad response",
|
|
136
|
+
assistantMessageToolbarReadAloudLabel: "Read aloud",
|
|
137
|
+
assistantMessageToolbarRegenerateLabel: "Regenerate",
|
|
138
|
+
userMessageToolbarCopyMessageLabel: "Copy",
|
|
139
|
+
userMessageToolbarEditMessageLabel: "Edit",
|
|
140
|
+
chatDisclaimerText: "AI can make mistakes. Please verify important information.",
|
|
141
|
+
chatToggleOpenLabel: "Open chat",
|
|
142
|
+
chatToggleCloseLabel: "Close chat",
|
|
143
|
+
modalHeaderTitle: "CopilotKit Chat",
|
|
144
|
+
welcomeMessageText: "How can I help you today?"
|
|
145
|
+
};
|
|
146
|
+
const CopilotChatConfiguration = (0, react.createContext)(null);
|
|
147
|
+
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
|
|
148
|
+
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
149
|
+
const stableLabels = useShallowStableRef(labels);
|
|
150
|
+
const mergedLabels = (0, react.useMemo)(() => ({
|
|
151
|
+
...CopilotChatDefaultLabels,
|
|
152
|
+
...parentConfig?.labels,
|
|
153
|
+
...stableLabels
|
|
154
|
+
}), [stableLabels, parentConfig?.labels]);
|
|
155
|
+
const resolvedAgentId = agentId ?? parentConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
156
|
+
const resolvedThreadId = (0, react.useMemo)(() => {
|
|
157
|
+
if (threadId) return threadId;
|
|
158
|
+
if (parentConfig?.threadId) return parentConfig.threadId;
|
|
159
|
+
return (0, _copilotkit_shared.randomUUID)();
|
|
160
|
+
}, [threadId, parentConfig?.threadId]);
|
|
161
|
+
const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
|
|
162
|
+
const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
|
|
163
|
+
const hasExplicitDefault = isModalDefaultOpen !== void 0;
|
|
164
|
+
const setAndSync = (0, react.useCallback)((open) => {
|
|
165
|
+
setInternalModalOpen(open);
|
|
166
|
+
parentConfig?.setModalOpen(open);
|
|
167
|
+
}, [parentConfig?.setModalOpen]);
|
|
168
|
+
const isMounted = (0, react.useRef)(false);
|
|
169
|
+
(0, react.useEffect)(() => {
|
|
170
|
+
if (!hasExplicitDefault) return;
|
|
171
|
+
if (!isMounted.current) {
|
|
172
|
+
isMounted.current = true;
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if (parentConfig?.isModalOpen === void 0) return;
|
|
176
|
+
setInternalModalOpen(parentConfig.isModalOpen);
|
|
177
|
+
}, [parentConfig?.isModalOpen, hasExplicitDefault]);
|
|
178
|
+
const resolvedIsModalOpen = hasExplicitDefault ? internalModalOpen : parentConfig?.isModalOpen ?? internalModalOpen;
|
|
179
|
+
const resolvedSetModalOpen = hasExplicitDefault ? setAndSync : parentConfig?.setModalOpen ?? setInternalModalOpen;
|
|
180
|
+
const configurationValue = (0, react.useMemo)(() => ({
|
|
181
|
+
labels: mergedLabels,
|
|
182
|
+
agentId: resolvedAgentId,
|
|
183
|
+
threadId: resolvedThreadId,
|
|
184
|
+
hasExplicitThreadId: resolvedHasExplicitThreadId,
|
|
185
|
+
isModalOpen: resolvedIsModalOpen,
|
|
186
|
+
setModalOpen: resolvedSetModalOpen
|
|
187
|
+
}), [
|
|
188
|
+
mergedLabels,
|
|
189
|
+
resolvedAgentId,
|
|
190
|
+
resolvedThreadId,
|
|
191
|
+
resolvedHasExplicitThreadId,
|
|
192
|
+
resolvedIsModalOpen,
|
|
193
|
+
resolvedSetModalOpen
|
|
194
|
+
]);
|
|
195
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfiguration.Provider, {
|
|
196
|
+
value: configurationValue,
|
|
197
|
+
children
|
|
198
|
+
});
|
|
199
|
+
};
|
|
200
|
+
const useCopilotChatConfiguration = () => {
|
|
201
|
+
return (0, react.useContext)(CopilotChatConfiguration);
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
//#endregion
|
|
205
|
+
//#region src/v2/hooks/use-agent.tsx
|
|
206
|
+
let UseAgentUpdate = /* @__PURE__ */ function(UseAgentUpdate) {
|
|
207
|
+
UseAgentUpdate["OnMessagesChanged"] = "OnMessagesChanged";
|
|
208
|
+
UseAgentUpdate["OnStateChanged"] = "OnStateChanged";
|
|
209
|
+
UseAgentUpdate["OnRunStatusChanged"] = "OnRunStatusChanged";
|
|
210
|
+
return UseAgentUpdate;
|
|
211
|
+
}({});
|
|
212
|
+
const ALL_UPDATES = [
|
|
213
|
+
UseAgentUpdate.OnMessagesChanged,
|
|
214
|
+
UseAgentUpdate.OnStateChanged,
|
|
215
|
+
UseAgentUpdate.OnRunStatusChanged
|
|
216
|
+
];
|
|
217
|
+
function useAgent({ agentId, updates, throttleMs } = {}) {
|
|
218
|
+
agentId ??= _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
219
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
220
|
+
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
221
|
+
const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
|
|
222
|
+
const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
223
|
+
const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
224
|
+
const agent = (0, react.useMemo)(() => {
|
|
225
|
+
const existing = copilotkit.getAgent(agentId);
|
|
226
|
+
if (existing) {
|
|
227
|
+
provisionalAgentCache.current.delete(agentId);
|
|
228
|
+
return existing;
|
|
229
|
+
}
|
|
230
|
+
const isRuntimeConfigured = copilotkit.runtimeUrl !== void 0;
|
|
231
|
+
const status = copilotkit.runtimeConnectionStatus;
|
|
232
|
+
if (isRuntimeConfigured && (status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Disconnected || status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connecting)) {
|
|
233
|
+
const cached = provisionalAgentCache.current.get(agentId);
|
|
234
|
+
if (cached) {
|
|
235
|
+
cached.headers = { ...copilotkit.headers };
|
|
236
|
+
return cached;
|
|
237
|
+
}
|
|
238
|
+
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
239
|
+
runtimeUrl: copilotkit.runtimeUrl,
|
|
240
|
+
agentId,
|
|
241
|
+
transport: copilotkit.runtimeTransport,
|
|
242
|
+
runtimeMode: "pending"
|
|
243
|
+
});
|
|
244
|
+
provisional.headers = { ...copilotkit.headers };
|
|
245
|
+
provisionalAgentCache.current.set(agentId, provisional);
|
|
246
|
+
return provisional;
|
|
247
|
+
}
|
|
248
|
+
if (isRuntimeConfigured && status === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
249
|
+
const cached = provisionalAgentCache.current.get(agentId);
|
|
250
|
+
if (cached) {
|
|
251
|
+
cached.headers = { ...copilotkit.headers };
|
|
252
|
+
return cached;
|
|
253
|
+
}
|
|
254
|
+
const provisional = new _copilotkit_core.ProxiedCopilotRuntimeAgent({
|
|
255
|
+
runtimeUrl: copilotkit.runtimeUrl,
|
|
256
|
+
agentId,
|
|
257
|
+
transport: copilotkit.runtimeTransport,
|
|
258
|
+
runtimeMode: "pending"
|
|
259
|
+
});
|
|
260
|
+
provisional.headers = { ...copilotkit.headers };
|
|
261
|
+
provisionalAgentCache.current.set(agentId, provisional);
|
|
262
|
+
return provisional;
|
|
263
|
+
}
|
|
264
|
+
const knownAgents = Object.keys(copilotkit.agents ?? {});
|
|
265
|
+
const runtimePart = isRuntimeConfigured ? `runtimeUrl=${copilotkit.runtimeUrl}` : "no runtimeUrl";
|
|
266
|
+
throw new Error(`useAgent: Agent '${agentId}' not found after runtime sync (${runtimePart}). ` + (knownAgents.length ? `Known agents: [${knownAgents.join(", ")}]` : "No agents registered.") + " Verify your runtime /info and/or agents__unsafe_dev_only.");
|
|
267
|
+
}, [
|
|
268
|
+
agentId,
|
|
269
|
+
copilotkit.agents,
|
|
270
|
+
copilotkit.runtimeConnectionStatus,
|
|
271
|
+
copilotkit.runtimeUrl,
|
|
272
|
+
copilotkit.runtimeTransport,
|
|
273
|
+
JSON.stringify(copilotkit.headers)
|
|
274
|
+
]);
|
|
275
|
+
(0, react.useEffect)(() => {
|
|
276
|
+
if (updateFlags.length === 0) return;
|
|
277
|
+
let active = true;
|
|
278
|
+
const handlers = {};
|
|
279
|
+
let batchScheduled = false;
|
|
280
|
+
const batchedForceUpdate = () => {
|
|
281
|
+
if (!active) return;
|
|
282
|
+
if (!batchScheduled) {
|
|
283
|
+
batchScheduled = true;
|
|
284
|
+
queueMicrotask(() => {
|
|
285
|
+
batchScheduled = false;
|
|
286
|
+
if (active) forceUpdate();
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = batchedForceUpdate;
|
|
291
|
+
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
292
|
+
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
293
|
+
handlers.onRunInitialized = batchedForceUpdate;
|
|
294
|
+
handlers.onRunFinalized = batchedForceUpdate;
|
|
295
|
+
handlers.onRunFailed = batchedForceUpdate;
|
|
296
|
+
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
297
|
+
}
|
|
298
|
+
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
299
|
+
return () => {
|
|
300
|
+
active = false;
|
|
301
|
+
subscription.unsubscribe();
|
|
302
|
+
};
|
|
303
|
+
}, [
|
|
304
|
+
agent,
|
|
305
|
+
forceUpdate,
|
|
306
|
+
throttleMs,
|
|
307
|
+
providerThrottleMs,
|
|
308
|
+
updateFlags
|
|
309
|
+
]);
|
|
310
|
+
(0, react.useEffect)(() => {
|
|
311
|
+
if (agent instanceof _ag_ui_client.HttpAgent) agent.headers = { ...copilotkit.headers };
|
|
312
|
+
}, [agent, JSON.stringify(copilotkit.headers)]);
|
|
313
|
+
return { agent };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/v2/hooks/use-frontend-tool.tsx
|
|
318
|
+
const EMPTY_DEPS = [];
|
|
319
|
+
function useFrontendTool(tool, deps) {
|
|
320
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
321
|
+
const extraDeps = deps ?? EMPTY_DEPS;
|
|
322
|
+
(0, react.useEffect)(() => {
|
|
323
|
+
const name = tool.name;
|
|
324
|
+
if (copilotkit.getTool({
|
|
325
|
+
toolName: name,
|
|
326
|
+
agentId: tool.agentId
|
|
327
|
+
})) {
|
|
328
|
+
console.warn(`Tool '${name}' already exists for agent '${tool.agentId || "global"}'. Overriding with latest registration.`);
|
|
329
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
330
|
+
}
|
|
331
|
+
copilotkit.addTool(tool);
|
|
332
|
+
if (tool.render) copilotkit.addHookRenderToolCall({
|
|
333
|
+
name,
|
|
334
|
+
args: tool.parameters,
|
|
335
|
+
agentId: tool.agentId,
|
|
336
|
+
render: tool.render
|
|
337
|
+
});
|
|
338
|
+
return () => {
|
|
339
|
+
copilotkit.removeTool(name, tool.agentId);
|
|
340
|
+
};
|
|
341
|
+
}, [
|
|
342
|
+
tool.name,
|
|
343
|
+
tool.available,
|
|
344
|
+
copilotkit,
|
|
345
|
+
JSON.stringify(extraDeps)
|
|
346
|
+
]);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
//#endregion
|
|
350
|
+
//#region src/v2/hooks/use-component.tsx
|
|
351
|
+
/**
|
|
352
|
+
* Registers a React component as a frontend tool renderer in chat.
|
|
353
|
+
*
|
|
354
|
+
* This hook is a convenience wrapper around `useFrontendTool` that:
|
|
355
|
+
* - builds a model-facing tool description,
|
|
356
|
+
* - forwards optional schema parameters (any Standard Schema V1 compatible library),
|
|
357
|
+
* - renders your component with tool call parameters.
|
|
358
|
+
*
|
|
359
|
+
* Use this when you want to display a typed visual component for a tool call
|
|
360
|
+
* without manually wiring a full frontend tool object.
|
|
361
|
+
*
|
|
362
|
+
* When `parameters` is provided, render props are inferred from the schema.
|
|
363
|
+
* When omitted, the render component may accept any props.
|
|
364
|
+
*
|
|
365
|
+
* @typeParam TSchema - Schema describing tool parameters, or `undefined` when no schema is given.
|
|
366
|
+
* @param config - Tool registration config.
|
|
367
|
+
* @param deps - Optional dependencies to refresh registration (same semantics as `useEffect`).
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* ```tsx
|
|
371
|
+
* // Without parameters — render accepts any props
|
|
372
|
+
* useComponent({
|
|
373
|
+
* name: "showGreeting",
|
|
374
|
+
* render: ({ message }: { message: string }) => <div>{message}</div>,
|
|
375
|
+
* });
|
|
376
|
+
* ```
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* ```tsx
|
|
380
|
+
* // With parameters — render props inferred from schema
|
|
381
|
+
* useComponent({
|
|
382
|
+
* name: "showWeatherCard",
|
|
383
|
+
* parameters: z.object({ city: z.string() }),
|
|
384
|
+
* render: ({ city }) => <div>{city}</div>,
|
|
385
|
+
* });
|
|
386
|
+
* ```
|
|
387
|
+
*
|
|
388
|
+
* @example
|
|
389
|
+
* ```tsx
|
|
390
|
+
* useComponent(
|
|
391
|
+
* {
|
|
392
|
+
* name: "renderProfile",
|
|
393
|
+
* parameters: z.object({ userId: z.string() }),
|
|
394
|
+
* render: ProfileCard,
|
|
395
|
+
* agentId: "support-agent",
|
|
396
|
+
* },
|
|
397
|
+
* [selectedAgentId],
|
|
398
|
+
* );
|
|
399
|
+
* ```
|
|
400
|
+
*/
|
|
401
|
+
function useComponent(config, deps) {
|
|
402
|
+
const prefix = `Use this tool to display the "${config.name}" component in the chat. This tool renders a visual UI component for the user.`;
|
|
403
|
+
const fullDescription = config.description ? `${prefix}\n\n${config.description}` : prefix;
|
|
404
|
+
useFrontendTool({
|
|
405
|
+
name: config.name,
|
|
406
|
+
description: fullDescription,
|
|
407
|
+
parameters: config.parameters,
|
|
408
|
+
render: ({ args }) => {
|
|
409
|
+
const Component = config.render;
|
|
410
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Component, { ...args });
|
|
411
|
+
},
|
|
412
|
+
agentId: config.agentId
|
|
413
|
+
}, deps);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
//#endregion
|
|
417
|
+
//#region src/v2/hooks/use-human-in-the-loop.tsx
|
|
418
|
+
function useHumanInTheLoop(tool, deps) {
|
|
419
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
420
|
+
const resolvePromiseRef = (0, react.useRef)(null);
|
|
421
|
+
const respond = (0, react.useCallback)(async (result) => {
|
|
422
|
+
if (resolvePromiseRef.current) {
|
|
423
|
+
resolvePromiseRef.current(result);
|
|
424
|
+
resolvePromiseRef.current = null;
|
|
425
|
+
}
|
|
426
|
+
}, []);
|
|
427
|
+
const handler = (0, react.useCallback)(async () => {
|
|
428
|
+
return new Promise((resolve) => {
|
|
429
|
+
resolvePromiseRef.current = resolve;
|
|
430
|
+
});
|
|
431
|
+
}, []);
|
|
432
|
+
const RenderComponent = (0, react.useCallback)((props) => {
|
|
433
|
+
const ToolComponent = tool.render;
|
|
434
|
+
if (props.status === "inProgress") {
|
|
435
|
+
const enhancedProps = {
|
|
436
|
+
...props,
|
|
437
|
+
name: tool.name,
|
|
438
|
+
description: tool.description || "",
|
|
439
|
+
respond: void 0
|
|
440
|
+
};
|
|
441
|
+
return react.default.createElement(ToolComponent, enhancedProps);
|
|
442
|
+
} else if (props.status === "executing") {
|
|
443
|
+
const enhancedProps = {
|
|
444
|
+
...props,
|
|
445
|
+
name: tool.name,
|
|
446
|
+
description: tool.description || "",
|
|
447
|
+
respond
|
|
448
|
+
};
|
|
449
|
+
return react.default.createElement(ToolComponent, enhancedProps);
|
|
450
|
+
} else if (props.status === "complete") {
|
|
451
|
+
const enhancedProps = {
|
|
452
|
+
...props,
|
|
453
|
+
name: tool.name,
|
|
454
|
+
description: tool.description || "",
|
|
455
|
+
respond: void 0
|
|
456
|
+
};
|
|
457
|
+
return react.default.createElement(ToolComponent, enhancedProps);
|
|
458
|
+
}
|
|
459
|
+
return react.default.createElement(ToolComponent, props);
|
|
460
|
+
}, [
|
|
461
|
+
tool.render,
|
|
462
|
+
tool.name,
|
|
463
|
+
tool.description,
|
|
464
|
+
respond
|
|
465
|
+
]);
|
|
466
|
+
useFrontendTool({
|
|
467
|
+
...tool,
|
|
468
|
+
handler,
|
|
469
|
+
render: RenderComponent
|
|
470
|
+
}, deps);
|
|
471
|
+
(0, react.useEffect)(() => {
|
|
472
|
+
return () => {
|
|
473
|
+
copilotkit.removeHookRenderToolCall(tool.name, tool.agentId);
|
|
474
|
+
};
|
|
475
|
+
}, [
|
|
476
|
+
copilotkit,
|
|
477
|
+
tool.name,
|
|
478
|
+
tool.agentId
|
|
479
|
+
]);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
//#endregion
|
|
483
|
+
//#region src/v2/hooks/use-interrupt.tsx
|
|
484
|
+
const INTERRUPT_EVENT_NAME = "on_interrupt";
|
|
485
|
+
function isPromiseLike(value) {
|
|
486
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && typeof Reflect.get(value, "then") === "function";
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* Handles agent interrupts (`on_interrupt`) with optional filtering, preprocessing, and resume behavior.
|
|
490
|
+
*
|
|
491
|
+
* The hook listens to custom events on the active agent, stores interrupt payloads per run,
|
|
492
|
+
* and surfaces a render callback once the run finalizes. Call `resolve` from your UI to resume
|
|
493
|
+
* execution with user-provided data.
|
|
494
|
+
*
|
|
495
|
+
* - `renderInChat: true` (default): the element is published into `<CopilotChat>` and this hook returns `void`.
|
|
496
|
+
* - `renderInChat: false`: the hook returns the interrupt element so you can place it anywhere in your component tree.
|
|
497
|
+
*
|
|
498
|
+
* `event.value` is typed as `any` since the interrupt payload shape depends on your agent.
|
|
499
|
+
* Type-narrow it in your callbacks (e.g. `handler`, `enabled`, `render`) as needed.
|
|
500
|
+
*
|
|
501
|
+
* @typeParam TResult - Inferred from `handler` return type. Exposed as `result` in `render`.
|
|
502
|
+
* @param config - Interrupt configuration (renderer, optional handler/filter, and render mode).
|
|
503
|
+
* @returns When `renderInChat` is `false`, returns the interrupt element (or `null` when idle).
|
|
504
|
+
* Otherwise returns `void` and publishes the element into chat. In `render`, `result` is always
|
|
505
|
+
* either the handler's resolved return value or `null` (including when no handler is provided,
|
|
506
|
+
* when filtering skips the interrupt, or when handler execution fails).
|
|
507
|
+
*
|
|
508
|
+
* @example
|
|
509
|
+
* ```tsx
|
|
510
|
+
* import { useInterrupt } from "@copilotkit/react-core/v2";
|
|
511
|
+
*
|
|
512
|
+
* function InterruptUI() {
|
|
513
|
+
* useInterrupt({
|
|
514
|
+
* render: ({ event, resolve }) => (
|
|
515
|
+
* <div>
|
|
516
|
+
* <p>{event.value.question}</p>
|
|
517
|
+
* <button onClick={() => resolve({ approved: true })}>Approve</button>
|
|
518
|
+
* <button onClick={() => resolve({ approved: false })}>Reject</button>
|
|
519
|
+
* </div>
|
|
520
|
+
* ),
|
|
521
|
+
* });
|
|
522
|
+
*
|
|
523
|
+
* return null;
|
|
524
|
+
* }
|
|
525
|
+
* ```
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ```tsx
|
|
529
|
+
* import { useInterrupt } from "@copilotkit/react-core/v2";
|
|
530
|
+
*
|
|
531
|
+
* function CustomPanel() {
|
|
532
|
+
* const interruptElement = useInterrupt({
|
|
533
|
+
* renderInChat: false,
|
|
534
|
+
* enabled: (event) => event.value.startsWith("approval:"),
|
|
535
|
+
* handler: async ({ event }) => ({ label: event.value.toUpperCase() }),
|
|
536
|
+
* render: ({ event, result, resolve }) => (
|
|
537
|
+
* <aside>
|
|
538
|
+
* <strong>{result?.label ?? ""}</strong>
|
|
539
|
+
* <button onClick={() => resolve({ value: event.value })}>Continue</button>
|
|
540
|
+
* </aside>
|
|
541
|
+
* ),
|
|
542
|
+
* });
|
|
543
|
+
*
|
|
544
|
+
* return <>{interruptElement}</>;
|
|
545
|
+
* }
|
|
546
|
+
* ```
|
|
547
|
+
*/
|
|
548
|
+
function useInterrupt(config) {
|
|
549
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
550
|
+
const { agent } = useAgent({ agentId: config.agentId });
|
|
551
|
+
const [pendingEvent, setPendingEvent] = (0, react.useState)(null);
|
|
552
|
+
const pendingEventRef = (0, react.useRef)(pendingEvent);
|
|
553
|
+
pendingEventRef.current = pendingEvent;
|
|
554
|
+
const [handlerResult, setHandlerResult] = (0, react.useState)(null);
|
|
555
|
+
(0, react.useEffect)(() => {
|
|
556
|
+
let localInterrupt = null;
|
|
557
|
+
const subscription = agent.subscribe({
|
|
558
|
+
onCustomEvent: ({ event }) => {
|
|
559
|
+
if (event.name === INTERRUPT_EVENT_NAME) localInterrupt = {
|
|
560
|
+
name: event.name,
|
|
561
|
+
value: event.value
|
|
562
|
+
};
|
|
563
|
+
},
|
|
564
|
+
onRunStartedEvent: () => {
|
|
565
|
+
localInterrupt = null;
|
|
566
|
+
setPendingEvent(null);
|
|
567
|
+
},
|
|
568
|
+
onRunFinalized: () => {
|
|
569
|
+
if (localInterrupt) {
|
|
570
|
+
setPendingEvent(localInterrupt);
|
|
571
|
+
localInterrupt = null;
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
onRunFailed: () => {
|
|
575
|
+
localInterrupt = null;
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
return () => subscription.unsubscribe();
|
|
579
|
+
}, [agent]);
|
|
580
|
+
const resolve = (0, react.useCallback)((response) => {
|
|
581
|
+
setPendingEvent(null);
|
|
582
|
+
copilotkit.runAgent({
|
|
583
|
+
agent,
|
|
584
|
+
forwardedProps: { command: {
|
|
585
|
+
resume: response,
|
|
586
|
+
interruptEvent: pendingEventRef.current?.value
|
|
587
|
+
} }
|
|
588
|
+
});
|
|
589
|
+
}, [agent, copilotkit]);
|
|
590
|
+
(0, react.useEffect)(() => {
|
|
591
|
+
if (!pendingEvent) {
|
|
592
|
+
setHandlerResult(null);
|
|
593
|
+
return;
|
|
594
|
+
}
|
|
595
|
+
if (config.enabled && !config.enabled(pendingEvent)) {
|
|
596
|
+
setHandlerResult(null);
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
const handler = config.handler;
|
|
600
|
+
if (!handler) {
|
|
601
|
+
setHandlerResult(null);
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
let cancelled = false;
|
|
605
|
+
const maybePromise = handler({
|
|
606
|
+
event: pendingEvent,
|
|
607
|
+
resolve
|
|
608
|
+
});
|
|
609
|
+
if (isPromiseLike(maybePromise)) Promise.resolve(maybePromise).then((resolved) => {
|
|
610
|
+
if (!cancelled) setHandlerResult(resolved);
|
|
611
|
+
}).catch(() => {
|
|
612
|
+
if (!cancelled) setHandlerResult(null);
|
|
613
|
+
});
|
|
614
|
+
else setHandlerResult(maybePromise);
|
|
615
|
+
return () => {
|
|
616
|
+
cancelled = true;
|
|
617
|
+
};
|
|
618
|
+
}, [
|
|
619
|
+
pendingEvent,
|
|
620
|
+
config.enabled,
|
|
621
|
+
config.handler,
|
|
622
|
+
resolve
|
|
623
|
+
]);
|
|
624
|
+
const element = (0, react.useMemo)(() => {
|
|
625
|
+
if (!pendingEvent) return null;
|
|
626
|
+
if (config.enabled && !config.enabled(pendingEvent)) return null;
|
|
627
|
+
return config.render({
|
|
628
|
+
event: pendingEvent,
|
|
629
|
+
result: handlerResult,
|
|
630
|
+
resolve
|
|
631
|
+
});
|
|
632
|
+
}, [
|
|
633
|
+
pendingEvent,
|
|
634
|
+
handlerResult,
|
|
635
|
+
config.enabled,
|
|
636
|
+
config.render,
|
|
637
|
+
resolve
|
|
638
|
+
]);
|
|
639
|
+
(0, react.useEffect)(() => {
|
|
640
|
+
if (config.renderInChat === false) return;
|
|
641
|
+
copilotkit.setInterruptElement(element);
|
|
642
|
+
return () => copilotkit.setInterruptElement(null);
|
|
643
|
+
}, [
|
|
644
|
+
element,
|
|
645
|
+
config.renderInChat,
|
|
646
|
+
copilotkit
|
|
647
|
+
]);
|
|
648
|
+
if (config.renderInChat === false) return element;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
//#endregion
|
|
652
|
+
//#region src/v2/hooks/use-suggestions.tsx
|
|
653
|
+
function useSuggestions({ agentId } = {}) {
|
|
654
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
655
|
+
const config = useCopilotChatConfiguration();
|
|
656
|
+
const resolvedAgentId = (0, react.useMemo)(() => agentId ?? config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID, [agentId, config?.agentId]);
|
|
657
|
+
const [suggestions, setSuggestions] = (0, react.useState)(() => {
|
|
658
|
+
return copilotkit.getSuggestions(resolvedAgentId).suggestions;
|
|
659
|
+
});
|
|
660
|
+
const [isLoading, setIsLoading] = (0, react.useState)(() => {
|
|
661
|
+
return copilotkit.getSuggestions(resolvedAgentId).isLoading;
|
|
662
|
+
});
|
|
663
|
+
(0, react.useEffect)(() => {
|
|
664
|
+
const result = copilotkit.getSuggestions(resolvedAgentId);
|
|
665
|
+
setSuggestions(result.suggestions);
|
|
666
|
+
setIsLoading(result.isLoading);
|
|
667
|
+
}, [copilotkit, resolvedAgentId]);
|
|
668
|
+
(0, react.useEffect)(() => {
|
|
669
|
+
const subscription = copilotkit.subscribe({
|
|
670
|
+
onSuggestionsChanged: ({ agentId: changedAgentId, suggestions }) => {
|
|
671
|
+
if (changedAgentId !== resolvedAgentId) return;
|
|
672
|
+
setSuggestions(suggestions);
|
|
673
|
+
},
|
|
674
|
+
onSuggestionsStartedLoading: ({ agentId: changedAgentId }) => {
|
|
675
|
+
if (changedAgentId !== resolvedAgentId) return;
|
|
676
|
+
setIsLoading(true);
|
|
677
|
+
},
|
|
678
|
+
onSuggestionsFinishedLoading: ({ agentId: changedAgentId }) => {
|
|
679
|
+
if (changedAgentId !== resolvedAgentId) return;
|
|
680
|
+
setIsLoading(false);
|
|
681
|
+
},
|
|
682
|
+
onSuggestionsConfigChanged: () => {
|
|
683
|
+
const result = copilotkit.getSuggestions(resolvedAgentId);
|
|
684
|
+
setSuggestions(result.suggestions);
|
|
685
|
+
setIsLoading(result.isLoading);
|
|
686
|
+
}
|
|
687
|
+
});
|
|
688
|
+
return () => {
|
|
689
|
+
subscription.unsubscribe();
|
|
690
|
+
};
|
|
691
|
+
}, [copilotkit, resolvedAgentId]);
|
|
692
|
+
return {
|
|
693
|
+
suggestions,
|
|
694
|
+
reloadSuggestions: (0, react.useCallback)(() => {
|
|
695
|
+
copilotkit.reloadSuggestions(resolvedAgentId);
|
|
696
|
+
}, [copilotkit, resolvedAgentId]),
|
|
697
|
+
clearSuggestions: (0, react.useCallback)(() => {
|
|
698
|
+
copilotkit.clearSuggestions(resolvedAgentId);
|
|
699
|
+
}, [copilotkit, resolvedAgentId]),
|
|
700
|
+
isLoading
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
//#endregion
|
|
705
|
+
//#region src/v2/hooks/use-configure-suggestions.tsx
|
|
706
|
+
function useConfigureSuggestions(config, deps) {
|
|
707
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
708
|
+
const chatConfig = useCopilotChatConfiguration();
|
|
709
|
+
const extraDeps = deps ?? [];
|
|
710
|
+
const resolvedConsumerAgentId = (0, react.useMemo)(() => chatConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID, [chatConfig?.agentId]);
|
|
711
|
+
const rawConsumerAgentId = (0, react.useMemo)(() => config ? config.consumerAgentId : void 0, [config]);
|
|
712
|
+
const normalizationCacheRef = (0, react.useRef)({
|
|
713
|
+
serialized: null,
|
|
714
|
+
config: null
|
|
715
|
+
});
|
|
716
|
+
const { normalizedConfig, serializedConfig } = (0, react.useMemo)(() => {
|
|
717
|
+
if (!config) {
|
|
718
|
+
normalizationCacheRef.current = {
|
|
719
|
+
serialized: null,
|
|
720
|
+
config: null
|
|
721
|
+
};
|
|
722
|
+
return {
|
|
723
|
+
normalizedConfig: null,
|
|
724
|
+
serializedConfig: null
|
|
725
|
+
};
|
|
726
|
+
}
|
|
727
|
+
if (config.available === "disabled") {
|
|
728
|
+
normalizationCacheRef.current = {
|
|
729
|
+
serialized: null,
|
|
730
|
+
config: null
|
|
731
|
+
};
|
|
732
|
+
return {
|
|
733
|
+
normalizedConfig: null,
|
|
734
|
+
serializedConfig: null
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
let built;
|
|
738
|
+
if (isDynamicConfig(config)) built = { ...config };
|
|
739
|
+
else {
|
|
740
|
+
const normalizedSuggestions = normalizeStaticSuggestions(config.suggestions);
|
|
741
|
+
built = {
|
|
742
|
+
...config,
|
|
743
|
+
suggestions: normalizedSuggestions
|
|
744
|
+
};
|
|
745
|
+
}
|
|
746
|
+
const serialized = JSON.stringify(built);
|
|
747
|
+
const cache = normalizationCacheRef.current;
|
|
748
|
+
if (cache.serialized === serialized && cache.config) return {
|
|
749
|
+
normalizedConfig: cache.config,
|
|
750
|
+
serializedConfig: serialized
|
|
751
|
+
};
|
|
752
|
+
normalizationCacheRef.current = {
|
|
753
|
+
serialized,
|
|
754
|
+
config: built
|
|
755
|
+
};
|
|
756
|
+
return {
|
|
757
|
+
normalizedConfig: built,
|
|
758
|
+
serializedConfig: serialized
|
|
759
|
+
};
|
|
760
|
+
}, [
|
|
761
|
+
config,
|
|
762
|
+
resolvedConsumerAgentId,
|
|
763
|
+
...extraDeps
|
|
764
|
+
]);
|
|
765
|
+
const latestConfigRef = (0, react.useRef)(null);
|
|
766
|
+
latestConfigRef.current = normalizedConfig;
|
|
767
|
+
const previousSerializedConfigRef = (0, react.useRef)(null);
|
|
768
|
+
const targetAgentId = (0, react.useMemo)(() => {
|
|
769
|
+
if (!normalizedConfig) return resolvedConsumerAgentId;
|
|
770
|
+
const consumer = normalizedConfig.consumerAgentId;
|
|
771
|
+
if (!consumer || consumer === "*") return resolvedConsumerAgentId;
|
|
772
|
+
return consumer;
|
|
773
|
+
}, [normalizedConfig, resolvedConsumerAgentId]);
|
|
774
|
+
const isGlobalConfig = rawConsumerAgentId === void 0 || rawConsumerAgentId === "*";
|
|
775
|
+
const isDynamicConfigType = (0, react.useMemo)(() => !!normalizedConfig && "instructions" in normalizedConfig, [normalizedConfig]);
|
|
776
|
+
const requestReload = (0, react.useCallback)(() => {
|
|
777
|
+
if (!normalizedConfig) return;
|
|
778
|
+
if (isGlobalConfig) {
|
|
779
|
+
const seen = /* @__PURE__ */ new Set();
|
|
780
|
+
const agents = Object.values(copilotkit.agents ?? {});
|
|
781
|
+
for (const entry of agents) {
|
|
782
|
+
const agentId = entry.agentId;
|
|
783
|
+
if (!agentId) continue;
|
|
784
|
+
seen.add(agentId);
|
|
785
|
+
if (!entry.isRunning) copilotkit.reloadSuggestions(agentId);
|
|
786
|
+
}
|
|
787
|
+
if (targetAgentId && !seen.has(targetAgentId)) copilotkit.reloadSuggestions(targetAgentId);
|
|
788
|
+
return;
|
|
789
|
+
}
|
|
790
|
+
if (!targetAgentId) return;
|
|
791
|
+
copilotkit.reloadSuggestions(targetAgentId);
|
|
792
|
+
}, [
|
|
793
|
+
copilotkit,
|
|
794
|
+
isGlobalConfig,
|
|
795
|
+
normalizedConfig,
|
|
796
|
+
targetAgentId
|
|
797
|
+
]);
|
|
798
|
+
(0, react.useEffect)(() => {
|
|
799
|
+
if (!serializedConfig || !latestConfigRef.current) return;
|
|
800
|
+
const id = copilotkit.addSuggestionsConfig(latestConfigRef.current);
|
|
801
|
+
requestReload();
|
|
802
|
+
return () => {
|
|
803
|
+
copilotkit.removeSuggestionsConfig(id);
|
|
804
|
+
};
|
|
805
|
+
}, [
|
|
806
|
+
copilotkit,
|
|
807
|
+
serializedConfig,
|
|
808
|
+
requestReload
|
|
809
|
+
]);
|
|
810
|
+
(0, react.useEffect)(() => {
|
|
811
|
+
if (!normalizedConfig) {
|
|
812
|
+
previousSerializedConfigRef.current = null;
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
if (serializedConfig && previousSerializedConfigRef.current === serializedConfig) return;
|
|
816
|
+
if (serializedConfig) previousSerializedConfigRef.current = serializedConfig;
|
|
817
|
+
requestReload();
|
|
818
|
+
}, [
|
|
819
|
+
normalizedConfig,
|
|
820
|
+
requestReload,
|
|
821
|
+
serializedConfig
|
|
822
|
+
]);
|
|
823
|
+
(0, react.useEffect)(() => {
|
|
824
|
+
if (!normalizedConfig || extraDeps.length === 0) return;
|
|
825
|
+
requestReload();
|
|
826
|
+
}, [
|
|
827
|
+
extraDeps.length,
|
|
828
|
+
normalizedConfig,
|
|
829
|
+
requestReload,
|
|
830
|
+
...extraDeps
|
|
831
|
+
]);
|
|
832
|
+
(0, react.useEffect)(() => {
|
|
833
|
+
if (!normalizedConfig || !isDynamicConfigType) return;
|
|
834
|
+
if (!targetAgentId) return;
|
|
835
|
+
if (!!copilotkit.getAgent(targetAgentId)) return;
|
|
836
|
+
const subscription = copilotkit.subscribe({ onAgentsChanged: () => {
|
|
837
|
+
if (copilotkit.getAgent(targetAgentId)) {
|
|
838
|
+
requestReload();
|
|
839
|
+
subscription.unsubscribe();
|
|
840
|
+
}
|
|
841
|
+
} });
|
|
842
|
+
return () => {
|
|
843
|
+
subscription.unsubscribe();
|
|
844
|
+
};
|
|
845
|
+
}, [
|
|
846
|
+
copilotkit,
|
|
847
|
+
normalizedConfig,
|
|
848
|
+
isDynamicConfigType,
|
|
849
|
+
targetAgentId,
|
|
850
|
+
requestReload
|
|
851
|
+
]);
|
|
852
|
+
}
|
|
853
|
+
function isDynamicConfig(config) {
|
|
854
|
+
return "instructions" in config;
|
|
855
|
+
}
|
|
856
|
+
function normalizeStaticSuggestions(suggestions) {
|
|
857
|
+
return suggestions.map((suggestion) => ({
|
|
858
|
+
...suggestion,
|
|
859
|
+
isLoading: suggestion.isLoading ?? false
|
|
860
|
+
}));
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
//#endregion
|
|
864
|
+
//#region src/v2/hooks/use-agent-context.tsx
|
|
865
|
+
function useAgentContext(context) {
|
|
866
|
+
const { description, value } = context;
|
|
867
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
868
|
+
const stringValue = (0, react.useMemo)(() => {
|
|
869
|
+
if (typeof value === "string") return value;
|
|
870
|
+
return JSON.stringify(value);
|
|
871
|
+
}, [value]);
|
|
872
|
+
(0, react.useLayoutEffect)(() => {
|
|
873
|
+
if (!copilotkit) return;
|
|
874
|
+
const id = copilotkit.addContext({
|
|
875
|
+
description,
|
|
876
|
+
value: stringValue
|
|
877
|
+
});
|
|
878
|
+
return () => {
|
|
879
|
+
copilotkit.removeContext(id);
|
|
880
|
+
};
|
|
881
|
+
}, [
|
|
882
|
+
description,
|
|
883
|
+
stringValue,
|
|
884
|
+
copilotkit
|
|
885
|
+
]);
|
|
886
|
+
}
|
|
887
|
+
|
|
888
|
+
//#endregion
|
|
889
|
+
//#region src/v2/hooks/use-threads.tsx
|
|
890
|
+
function useThreadStoreSelector(store, selector) {
|
|
891
|
+
return (0, react.useSyncExternalStore)((0, react.useCallback)((onStoreChange) => {
|
|
892
|
+
const subscription = store.select(selector).subscribe(onStoreChange);
|
|
893
|
+
return () => subscription.unsubscribe();
|
|
894
|
+
}, [store, selector]), () => selector(store.getState()));
|
|
895
|
+
}
|
|
896
|
+
/**
|
|
897
|
+
* React hook for listing and managing Intelligence platform threads.
|
|
898
|
+
*
|
|
899
|
+
* On mount the hook fetches the thread list for the runtime-authenticated user
|
|
900
|
+
* and the given `agentId`. When the Intelligence platform exposes a WebSocket
|
|
901
|
+
* URL, it also opens a realtime subscription so the `threads` array stays
|
|
902
|
+
* current without polling — thread creates, renames, archives, and deletes
|
|
903
|
+
* from any client are reflected immediately.
|
|
904
|
+
*
|
|
905
|
+
* Mutation methods (`renameThread`, `archiveThread`, `deleteThread`) return
|
|
906
|
+
* promises that resolve once the platform confirms the operation and reject
|
|
907
|
+
* with an `Error` on failure.
|
|
908
|
+
*
|
|
909
|
+
* @param input - Agent identifier and optional list controls.
|
|
910
|
+
* @returns Thread list state and stable mutation callbacks.
|
|
911
|
+
*
|
|
912
|
+
* @example
|
|
913
|
+
* ```tsx
|
|
914
|
+
* import { useThreads } from "@copilotkit/react-core";
|
|
915
|
+
*
|
|
916
|
+
* function ThreadList() {
|
|
917
|
+
* const { threads, isLoading, renameThread, deleteThread } = useThreads({
|
|
918
|
+
* agentId: "agent-1",
|
|
919
|
+
* });
|
|
920
|
+
*
|
|
921
|
+
* if (isLoading) return <p>Loading…</p>;
|
|
922
|
+
*
|
|
923
|
+
* return (
|
|
924
|
+
* <ul>
|
|
925
|
+
* {threads.map((t) => (
|
|
926
|
+
* <li key={t.id}>
|
|
927
|
+
* {t.name ?? "Untitled"}
|
|
928
|
+
* <button onClick={() => renameThread(t.id, "New name")}>Rename</button>
|
|
929
|
+
* <button onClick={() => deleteThread(t.id)}>Delete</button>
|
|
930
|
+
* </li>
|
|
931
|
+
* ))}
|
|
932
|
+
* </ul>
|
|
933
|
+
* );
|
|
934
|
+
* }
|
|
935
|
+
* ```
|
|
936
|
+
*/
|
|
937
|
+
function useThreads({ agentId, includeArchived, limit }) {
|
|
938
|
+
const { copilotkit } = (0, _copilotkit_react_core_v2_context.useCopilotKit)();
|
|
939
|
+
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
940
|
+
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
941
|
+
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
|
|
942
|
+
id,
|
|
943
|
+
agentId,
|
|
944
|
+
name,
|
|
945
|
+
archived,
|
|
946
|
+
createdAt,
|
|
947
|
+
updatedAt,
|
|
948
|
+
...lastRunAt !== void 0 ? { lastRunAt } : {}
|
|
949
|
+
})), [coreThreads]);
|
|
950
|
+
const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
|
|
951
|
+
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
952
|
+
const hasMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectHasNextPage);
|
|
953
|
+
const isFetchingMoreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectIsFetchingNextPage);
|
|
954
|
+
const headersKey = (0, react.useMemo)(() => {
|
|
955
|
+
return JSON.stringify(Object.entries(copilotkit.headers ?? {}).sort(([left], [right]) => left.localeCompare(right)));
|
|
956
|
+
}, [copilotkit.headers]);
|
|
957
|
+
const runtimeError = (0, react.useMemo)(() => {
|
|
958
|
+
if (copilotkit.runtimeUrl) return null;
|
|
959
|
+
return /* @__PURE__ */ new Error("Runtime URL is not configured");
|
|
960
|
+
}, [copilotkit.runtimeUrl]);
|
|
961
|
+
const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
|
|
962
|
+
const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
|
|
963
|
+
const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
|
|
964
|
+
const error = runtimeError ?? storeError;
|
|
965
|
+
(0, react.useEffect)(() => {
|
|
966
|
+
store.start();
|
|
967
|
+
return () => {
|
|
968
|
+
store.stop();
|
|
969
|
+
};
|
|
970
|
+
}, [store]);
|
|
971
|
+
const runtimeStatus = copilotkit.runtimeConnectionStatus;
|
|
972
|
+
(0, react.useEffect)(() => {
|
|
973
|
+
copilotkit.registerThreadStore(agentId, store);
|
|
974
|
+
return () => {
|
|
975
|
+
copilotkit.unregisterThreadStore(agentId);
|
|
976
|
+
};
|
|
977
|
+
}, [
|
|
978
|
+
copilotkit,
|
|
979
|
+
agentId,
|
|
980
|
+
store
|
|
981
|
+
]);
|
|
982
|
+
(0, react.useEffect)(() => {
|
|
983
|
+
if (!copilotkit.runtimeUrl) {
|
|
984
|
+
store.setContext(null);
|
|
985
|
+
return;
|
|
986
|
+
}
|
|
987
|
+
if (runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
|
|
988
|
+
const context = {
|
|
989
|
+
runtimeUrl: copilotkit.runtimeUrl,
|
|
990
|
+
headers: { ...copilotkit.headers },
|
|
991
|
+
wsUrl: copilotkit.intelligence?.wsUrl,
|
|
992
|
+
agentId,
|
|
993
|
+
includeArchived,
|
|
994
|
+
limit
|
|
995
|
+
};
|
|
996
|
+
store.setContext(context);
|
|
997
|
+
setHasDispatchedContext(true);
|
|
998
|
+
}, [
|
|
999
|
+
store,
|
|
1000
|
+
copilotkit.runtimeUrl,
|
|
1001
|
+
runtimeStatus,
|
|
1002
|
+
headersKey,
|
|
1003
|
+
copilotkit.intelligence?.wsUrl,
|
|
1004
|
+
agentId,
|
|
1005
|
+
includeArchived,
|
|
1006
|
+
limit
|
|
1007
|
+
]);
|
|
1008
|
+
const renameThread = (0, react.useCallback)((threadId, name) => store.renameThread(threadId, name), [store]);
|
|
1009
|
+
const archiveThread = (0, react.useCallback)((threadId) => store.archiveThread(threadId), [store]);
|
|
1010
|
+
const deleteThread = (0, react.useCallback)((threadId) => store.deleteThread(threadId), [store]);
|
|
1011
|
+
return {
|
|
1012
|
+
threads,
|
|
1013
|
+
isLoading,
|
|
1014
|
+
error,
|
|
1015
|
+
hasMoreThreads,
|
|
1016
|
+
isFetchingMoreThreads,
|
|
1017
|
+
fetchMoreThreads: (0, react.useCallback)(() => store.fetchNextPage(), [store]),
|
|
1018
|
+
renameThread,
|
|
1019
|
+
archiveThread,
|
|
1020
|
+
deleteThread
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
//#endregion
|
|
1025
|
+
exports.CopilotChatConfigurationProvider = CopilotChatConfigurationProvider;
|
|
1026
|
+
exports.CopilotChatDefaultLabels = CopilotChatDefaultLabels;
|
|
1027
|
+
Object.defineProperty(exports, 'CopilotKitCoreReact', {
|
|
1028
|
+
enumerable: true,
|
|
1029
|
+
get: function () {
|
|
1030
|
+
return _copilotkit_react_core_v2_context.CopilotKitCoreReact;
|
|
1031
|
+
}
|
|
1032
|
+
});
|
|
1033
|
+
exports.useAgent = useAgent;
|
|
1034
|
+
exports.useAgentContext = useAgentContext;
|
|
1035
|
+
exports.useComponent = useComponent;
|
|
1036
|
+
exports.useConfigureSuggestions = useConfigureSuggestions;
|
|
1037
|
+
exports.useCopilotChatConfiguration = useCopilotChatConfiguration;
|
|
1038
|
+
exports.useFrontendTool = useFrontendTool;
|
|
1039
|
+
exports.useHumanInTheLoop = useHumanInTheLoop;
|
|
1040
|
+
exports.useInterrupt = useInterrupt;
|
|
1041
|
+
exports.useSuggestions = useSuggestions;
|
|
1042
|
+
exports.useThreads = useThreads;
|
|
1043
|
+
//# sourceMappingURL=headless.cjs.map
|