@copilotkit/react-core 1.59.2 → 1.59.4
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-D16eCFkt.d.cts → copilotkit-CtqalfG8.d.cts} +381 -58
- package/dist/copilotkit-CtqalfG8.d.cts.map +1 -0
- package/dist/{copilotkit-CEJz6krE.d.mts → copilotkit-D42EuTt0.d.mts} +381 -58
- package/dist/copilotkit-D42EuTt0.d.mts.map +1 -0
- package/dist/{copilotkit-B5RsC6la.mjs → copilotkit-DoIlZQqa.mjs} +564 -124
- package/dist/copilotkit-DoIlZQqa.mjs.map +1 -0
- package/dist/{copilotkit-IQO0VDZb.cjs → copilotkit-LdQ8w20l.cjs} +606 -124
- package/dist/copilotkit-LdQ8w20l.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/v2/index.cjs +8 -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 +570 -123
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/dist/copilotkit-B5RsC6la.mjs.map +0 -1
- package/dist/copilotkit-CEJz6krE.d.mts.map +0 -1
- package/dist/copilotkit-D16eCFkt.d.cts.map +0 -1
- package/dist/copilotkit-IQO0VDZb.cjs.map +0 -1
|
@@ -234,9 +234,9 @@ const useCopilotChatConfiguration = () => {
|
|
|
234
234
|
|
|
235
235
|
//#endregion
|
|
236
236
|
//#region src/v2/lib/utils.ts
|
|
237
|
-
const twMerge$
|
|
237
|
+
const twMerge$8 = (0, tailwind_merge.extendTailwindMerge)({ prefix: "cpk" });
|
|
238
238
|
function cn(...inputs) {
|
|
239
|
-
return twMerge$
|
|
239
|
+
return twMerge$8((0, clsx.clsx)(inputs));
|
|
240
240
|
}
|
|
241
241
|
|
|
242
242
|
//#endregion
|
|
@@ -794,7 +794,7 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
794
794
|
}
|
|
795
795
|
if (e.key === "Enter" && !e.shiftKey) {
|
|
796
796
|
e.preventDefault();
|
|
797
|
-
if (isProcessing) onStop?.();
|
|
797
|
+
if (isProcessing && !canSend) onStop?.();
|
|
798
798
|
else send();
|
|
799
799
|
}
|
|
800
800
|
};
|
|
@@ -4811,6 +4811,175 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4811
4811
|
};
|
|
4812
4812
|
}
|
|
4813
4813
|
|
|
4814
|
+
//#endregion
|
|
4815
|
+
//#region src/v2/lib/record-annotation.ts
|
|
4816
|
+
/**
|
|
4817
|
+
* Low-level function that posts an arbitrary annotation to the CopilotKit
|
|
4818
|
+
* runtime's general annotation endpoint (`POST /annotate`).
|
|
4819
|
+
*
|
|
4820
|
+
* This is the single transport entry point for all annotation types. Higher-
|
|
4821
|
+
* level hooks (e.g. `useLearnFromUserAction`) build the `type`/`payload` pair
|
|
4822
|
+
* for their specific annotation shape and delegate the HTTP call here.
|
|
4823
|
+
*
|
|
4824
|
+
* The function uses the same transport as `useLearnFromUserAction`:
|
|
4825
|
+
* - `runtimeUrl` from `copilotkit.runtimeUrl` (BFF proxies to the platform)
|
|
4826
|
+
* - `headers` from `copilotkit.headers` (customer auth forwarded to BFF)
|
|
4827
|
+
* - `clientEventId` auto-generated via `randomUUID()` when omitted
|
|
4828
|
+
* - `userId` is resolved server-side by the runtime; the client never sends it
|
|
4829
|
+
* - Errors propagate to the caller (fire-and-propagate, not fire-and-forget)
|
|
4830
|
+
*
|
|
4831
|
+
* @param args - Transport dependencies plus annotation fields.
|
|
4832
|
+
* @returns The platform result containing the annotation row `id` and a
|
|
4833
|
+
* `duplicate` flag.
|
|
4834
|
+
* @throws When the network request fails or the runtime returns a non-2xx
|
|
4835
|
+
* status. Callers that want fire-and-forget behavior should `.catch`
|
|
4836
|
+
* at the call site.
|
|
4837
|
+
*/
|
|
4838
|
+
async function recordAnnotation(args) {
|
|
4839
|
+
const { runtimeUrl, headers, type, payload, threadId, occurredAt } = args;
|
|
4840
|
+
const body = {
|
|
4841
|
+
type,
|
|
4842
|
+
threadId,
|
|
4843
|
+
clientEventId: args.clientEventId ?? (0, _copilotkit_shared.randomUUID)(),
|
|
4844
|
+
...payload !== void 0 ? { payload } : {},
|
|
4845
|
+
...occurredAt !== void 0 ? { occurredAt } : {}
|
|
4846
|
+
};
|
|
4847
|
+
const response = await fetch(`${runtimeUrl}/annotate`, {
|
|
4848
|
+
method: "POST",
|
|
4849
|
+
headers: {
|
|
4850
|
+
"Content-Type": "application/json",
|
|
4851
|
+
...headers
|
|
4852
|
+
},
|
|
4853
|
+
body: JSON.stringify(body)
|
|
4854
|
+
});
|
|
4855
|
+
if (!response.ok) {
|
|
4856
|
+
const text = await response.text().catch(() => "");
|
|
4857
|
+
throw new Error(`recordAnnotation: request failed (${response.status})${text ? `: ${text}` : ""}`);
|
|
4858
|
+
}
|
|
4859
|
+
const text = await response.text();
|
|
4860
|
+
if (!text) throw new Error(`recordAnnotation: runtime ${runtimeUrl}/annotate returned ${response.status} with an empty body`);
|
|
4861
|
+
try {
|
|
4862
|
+
return JSON.parse(text);
|
|
4863
|
+
} catch {
|
|
4864
|
+
throw new Error(`recordAnnotation: runtime ${runtimeUrl}/annotate returned a non-JSON body (status ${response.status})`);
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
//#endregion
|
|
4869
|
+
//#region src/v2/hooks/use-learn-from-user-action.tsx
|
|
4870
|
+
/**
|
|
4871
|
+
* Record a user UI interaction in the Intelligence platform's user-actions
|
|
4872
|
+
* stream. The platform's auto-curated knowledge base agent reads these
|
|
4873
|
+
* (alongside finished agent runs) and writes free-form Obsidian-flavored
|
|
4874
|
+
* markdown to `/project`, where any agent in the same project can later
|
|
4875
|
+
* read it via the `copilotkit_knowledge_base_shell` MCP tool.
|
|
4876
|
+
*
|
|
4877
|
+
* The hook returns a stable function. Calling it issues a request to the
|
|
4878
|
+
* customer's CopilotKit runtime (`POST ${runtimeUrl}/annotate`), which
|
|
4879
|
+
* resolves the Intel user from the BFF's auth and forwards to the
|
|
4880
|
+
* platform — the Intel API key never reaches the browser.
|
|
4881
|
+
*
|
|
4882
|
+
* If `clientEventId` is omitted `recordAnnotation` generates a UUID per call,
|
|
4883
|
+
* so a naive double-call (e.g. React 18 strict-mode double-mount, or a retry
|
|
4884
|
+
* after a network blip on a fresh Promise) is naturally safe. Supply your
|
|
4885
|
+
* own key when a single semantic event must remain idempotent across
|
|
4886
|
+
* multiple `learnFromUserAction(...)` calls.
|
|
4887
|
+
*
|
|
4888
|
+
* @example
|
|
4889
|
+
* ```tsx
|
|
4890
|
+
* import { useLearnFromUserAction } from "@copilotkit/react-core";
|
|
4891
|
+
*
|
|
4892
|
+
* function SettingsPage({ threadId }) {
|
|
4893
|
+
* const learnFromUserAction = useLearnFromUserAction();
|
|
4894
|
+
*
|
|
4895
|
+
* const onRename = (oldName: string, newName: string) => {
|
|
4896
|
+
* void learnFromUserAction({
|
|
4897
|
+
* threadId,
|
|
4898
|
+
* title: "Renamed project",
|
|
4899
|
+
* data: { previous: { name: oldName }, next: { name: newName } },
|
|
4900
|
+
* });
|
|
4901
|
+
* };
|
|
4902
|
+
* }
|
|
4903
|
+
* ```
|
|
4904
|
+
*/
|
|
4905
|
+
function useLearnFromUserAction() {
|
|
4906
|
+
const { copilotkit } = useCopilotKit();
|
|
4907
|
+
return (0, react.useCallback)(async (input) => {
|
|
4908
|
+
const runtimeUrl = copilotkit.runtimeUrl;
|
|
4909
|
+
if (!runtimeUrl) throw new Error("useLearnFromUserAction: runtimeUrl is not configured. Set it on <CopilotKitProvider runtimeUrl=...>.");
|
|
4910
|
+
const payload = {
|
|
4911
|
+
...input.title !== void 0 ? { title: input.title } : {},
|
|
4912
|
+
...input.description !== void 0 ? { description: input.description } : {},
|
|
4913
|
+
...input.data !== void 0 ? { data: input.data } : {}
|
|
4914
|
+
};
|
|
4915
|
+
return recordAnnotation({
|
|
4916
|
+
runtimeUrl,
|
|
4917
|
+
headers: copilotkit.headers ?? {},
|
|
4918
|
+
type: "user_action",
|
|
4919
|
+
payload: Object.keys(payload).length > 0 ? payload : void 0,
|
|
4920
|
+
threadId: input.threadId,
|
|
4921
|
+
clientEventId: input.clientEventId,
|
|
4922
|
+
occurredAt: input.occurredAt
|
|
4923
|
+
});
|
|
4924
|
+
}, [copilotkit]);
|
|
4925
|
+
}
|
|
4926
|
+
|
|
4927
|
+
//#endregion
|
|
4928
|
+
//#region src/v2/hooks/use-learn-from-user-action-in-current-thread.tsx
|
|
4929
|
+
/**
|
|
4930
|
+
* Record a user UI interaction against the **current chat's** thread. The
|
|
4931
|
+
* `threadId` is sourced from the surrounding
|
|
4932
|
+
* `<CopilotChatConfigurationProvider>` (the same provider `<CopilotChat>`,
|
|
4933
|
+
* `<CopilotSidebar>`, and friends set up), so callers in a chat-aware
|
|
4934
|
+
* subtree don't need to thread an id through manually.
|
|
4935
|
+
*
|
|
4936
|
+
* Throws on **call** (not on mount) when there is no chat-config provider
|
|
4937
|
+
* in scope — matches the "throw on call when runtimeUrl is missing"
|
|
4938
|
+
* behavior of {@link useLearnFromUserAction}. Mounting the hook in a branch
|
|
4939
|
+
* that never fires is harmless.
|
|
4940
|
+
*
|
|
4941
|
+
* The recorder does NOT accept a `threadId` override. If you need to
|
|
4942
|
+
* record against an explicit thread, use {@link useLearnFromUserAction}
|
|
4943
|
+
* directly — two hooks, two crisp contracts, no mode confusion.
|
|
4944
|
+
*
|
|
4945
|
+
* This hook always uses `config.threadId`, regardless of whether the
|
|
4946
|
+
* surrounding chat config minted it internally or received one from
|
|
4947
|
+
* the caller. Auto-minted threads simply mean the action lands under
|
|
4948
|
+
* a thread the platform never saw — the writer agent still distills
|
|
4949
|
+
* user-action-only threads (it does not require the thread to exist
|
|
4950
|
+
* in `cpki.threads`), so the loop keeps learning.
|
|
4951
|
+
*
|
|
4952
|
+
* @example
|
|
4953
|
+
* ```tsx
|
|
4954
|
+
* import { useLearnFromUserActionInCurrentThread } from "@copilotkit/react-core";
|
|
4955
|
+
*
|
|
4956
|
+
* function SettingsPanel() {
|
|
4957
|
+
* const learnFromUserAction = useLearnFromUserActionInCurrentThread();
|
|
4958
|
+
*
|
|
4959
|
+
* const onRename = (oldName: string, newName: string) => {
|
|
4960
|
+
* void learnFromUserAction({
|
|
4961
|
+
* title: "Renamed project",
|
|
4962
|
+
* data: { previous: { name: oldName }, next: { name: newName } },
|
|
4963
|
+
* });
|
|
4964
|
+
* };
|
|
4965
|
+
*
|
|
4966
|
+
* // ...
|
|
4967
|
+
* }
|
|
4968
|
+
* ```
|
|
4969
|
+
*/
|
|
4970
|
+
function useLearnFromUserActionInCurrentThread() {
|
|
4971
|
+
const config = useCopilotChatConfiguration();
|
|
4972
|
+
const learnFromUserAction = useLearnFromUserAction();
|
|
4973
|
+
return (0, react.useCallback)(async (input) => {
|
|
4974
|
+
const threadId = config?.threadId;
|
|
4975
|
+
if (!threadId) throw new Error("useLearnFromUserActionInCurrentThread: no CopilotChatConfigurationProvider in scope. Wrap the call site in <CopilotChat>, <CopilotSidebar>, or <CopilotChatConfigurationProvider>, or use `useLearnFromUserAction()` and pass `threadId` explicitly.");
|
|
4976
|
+
return learnFromUserAction({
|
|
4977
|
+
...input,
|
|
4978
|
+
threadId
|
|
4979
|
+
});
|
|
4980
|
+
}, [config?.threadId, learnFromUserAction]);
|
|
4981
|
+
}
|
|
4982
|
+
|
|
4814
4983
|
//#endregion
|
|
4815
4984
|
//#region src/v2/hooks/use-attachments.tsx
|
|
4816
4985
|
/**
|
|
@@ -4969,6 +5138,153 @@ function useAttachments({ config }) {
|
|
|
4969
5138
|
};
|
|
4970
5139
|
}
|
|
4971
5140
|
|
|
5141
|
+
//#endregion
|
|
5142
|
+
//#region src/v2/hooks/use-learning-containers.tsx
|
|
5143
|
+
/** The default learning containers value. Matches the backend default. */
|
|
5144
|
+
const DEFAULT_CONTAINERS = ["project"];
|
|
5145
|
+
/**
|
|
5146
|
+
* Declaratively keeps a thread's learning containers in sync by emitting
|
|
5147
|
+
* `set_learning_containers` annotations via the CopilotKit runtime annotate
|
|
5148
|
+
* endpoint (`POST ${runtimeUrl}/annotate`).
|
|
5149
|
+
*
|
|
5150
|
+
* **Emit rules:**
|
|
5151
|
+
* - On mount with `["project"]` (the backend default) → does NOT emit.
|
|
5152
|
+
* Absence of an annotation equals the default, so the round-trip is skipped.
|
|
5153
|
+
* - On mount with any other value → emits immediately.
|
|
5154
|
+
* - On any subsequent content change (including a switch back to
|
|
5155
|
+
* `["project"]`) → emits (a deliberate switch is always recorded).
|
|
5156
|
+
* - On unmount or threadId change → emits a reset to `["project"]`
|
|
5157
|
+
* so the backend is left in a clean state for the next consumer.
|
|
5158
|
+
* Changing `learningContainers` within the same thread does NOT reset the
|
|
5159
|
+
* thread; only the new value is emitted.
|
|
5160
|
+
*
|
|
5161
|
+
* Content-equality is evaluated via `JSON.stringify` so a fresh array literal
|
|
5162
|
+
* with the same items does NOT trigger a redundant emit.
|
|
5163
|
+
*
|
|
5164
|
+
* If `runtimeUrl` is absent, all emits are silently skipped.
|
|
5165
|
+
*
|
|
5166
|
+
* @example
|
|
5167
|
+
* ```tsx
|
|
5168
|
+
* function ThreadPane({ threadId, userScope }: Props) {
|
|
5169
|
+
* useLearningContainers({
|
|
5170
|
+
* threadId,
|
|
5171
|
+
* learningContainers: [userScope],
|
|
5172
|
+
* });
|
|
5173
|
+
* // ...
|
|
5174
|
+
* }
|
|
5175
|
+
* ```
|
|
5176
|
+
*/
|
|
5177
|
+
function useLearningContainers({ threadId, learningContainers }) {
|
|
5178
|
+
const { copilotkit } = useCopilotKit();
|
|
5179
|
+
/**
|
|
5180
|
+
* Tracks the last-synced container list so content-identical rerenders
|
|
5181
|
+
* (fresh array, same values) do not fire a redundant emit.
|
|
5182
|
+
* `null` = nothing synced yet (initial state or after a threadId reset).
|
|
5183
|
+
*/
|
|
5184
|
+
const lastSyncedRef = (0, react.useRef)(null);
|
|
5185
|
+
/** Guards the missing-runtimeUrl warning so it fires at most once per hook instance. */
|
|
5186
|
+
const warnedMissingUrlRef = (0, react.useRef)(false);
|
|
5187
|
+
const runtimeUrlRef = (0, react.useRef)(copilotkit.runtimeUrl);
|
|
5188
|
+
const headersRef = (0, react.useRef)(copilotkit.headers ?? {});
|
|
5189
|
+
runtimeUrlRef.current = copilotkit.runtimeUrl;
|
|
5190
|
+
headersRef.current = copilotkit.headers ?? {};
|
|
5191
|
+
const key = JSON.stringify(learningContainers);
|
|
5192
|
+
const defaultKey = JSON.stringify(DEFAULT_CONTAINERS);
|
|
5193
|
+
(0, react.useEffect)(() => {
|
|
5194
|
+
const runtimeUrl = copilotkit.runtimeUrl;
|
|
5195
|
+
const headers = copilotkit.headers ?? {};
|
|
5196
|
+
/**
|
|
5197
|
+
* Fire-and-forget emit; errors must not surface in render.
|
|
5198
|
+
* Failures are logged as warnings so they are diagnosable without
|
|
5199
|
+
* propagating into the React render cycle.
|
|
5200
|
+
*/
|
|
5201
|
+
const emit = (containers) => {
|
|
5202
|
+
if (!runtimeUrl) {
|
|
5203
|
+
if (!warnedMissingUrlRef.current) {
|
|
5204
|
+
warnedMissingUrlRef.current = true;
|
|
5205
|
+
console.warn("useLearningContainers: runtimeUrl not configured; learning-container sync disabled");
|
|
5206
|
+
}
|
|
5207
|
+
return;
|
|
5208
|
+
}
|
|
5209
|
+
recordAnnotation({
|
|
5210
|
+
runtimeUrl,
|
|
5211
|
+
headers,
|
|
5212
|
+
type: "set_learning_containers",
|
|
5213
|
+
payload: { containers },
|
|
5214
|
+
threadId
|
|
5215
|
+
}).catch((err) => {
|
|
5216
|
+
console.warn("useLearningContainers: failed to record set_learning_containers", err);
|
|
5217
|
+
});
|
|
5218
|
+
};
|
|
5219
|
+
if (lastSyncedRef.current === null) {
|
|
5220
|
+
if (key === defaultKey) {
|
|
5221
|
+
lastSyncedRef.current = learningContainers;
|
|
5222
|
+
return;
|
|
5223
|
+
}
|
|
5224
|
+
emit(learningContainers);
|
|
5225
|
+
lastSyncedRef.current = learningContainers;
|
|
5226
|
+
} else if (key !== JSON.stringify(lastSyncedRef.current)) {
|
|
5227
|
+
emit(learningContainers);
|
|
5228
|
+
lastSyncedRef.current = learningContainers;
|
|
5229
|
+
}
|
|
5230
|
+
}, [threadId, key]);
|
|
5231
|
+
(0, react.useEffect)(() => {
|
|
5232
|
+
const capturedThreadId = threadId;
|
|
5233
|
+
return () => {
|
|
5234
|
+
const capturedRuntimeUrl = runtimeUrlRef.current;
|
|
5235
|
+
const capturedHeaders = headersRef.current;
|
|
5236
|
+
if (capturedRuntimeUrl) recordAnnotation({
|
|
5237
|
+
runtimeUrl: capturedRuntimeUrl,
|
|
5238
|
+
headers: capturedHeaders,
|
|
5239
|
+
type: "set_learning_containers",
|
|
5240
|
+
payload: { containers: DEFAULT_CONTAINERS },
|
|
5241
|
+
threadId: capturedThreadId
|
|
5242
|
+
}).catch((err) => {
|
|
5243
|
+
console.warn("useLearningContainers: failed to record set_learning_containers", err);
|
|
5244
|
+
});
|
|
5245
|
+
lastSyncedRef.current = null;
|
|
5246
|
+
};
|
|
5247
|
+
}, [threadId]);
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
//#endregion
|
|
5251
|
+
//#region src/v2/hooks/use-learning-containers-in-current-thread.tsx
|
|
5252
|
+
/**
|
|
5253
|
+
* Declaratively keeps the **current chat thread's** learning containers in
|
|
5254
|
+
* sync. The `threadId` is sourced from the surrounding
|
|
5255
|
+
* `<CopilotChatConfigurationProvider>` (the same provider `<CopilotChat>`,
|
|
5256
|
+
* `<CopilotSidebar>`, and friends set up), so callers in a chat-aware
|
|
5257
|
+
* subtree don't need to thread an id through manually.
|
|
5258
|
+
*
|
|
5259
|
+
* **Throws on render** when there is no chat-config provider in scope or
|
|
5260
|
+
* when the provider does not yet have an active `threadId`. Mount the hook
|
|
5261
|
+
* inside a subtree that is guaranteed to have a thread context.
|
|
5262
|
+
*
|
|
5263
|
+
* If you need to manage an explicit thread, use {@link useLearningContainers}
|
|
5264
|
+
* directly — two hooks, two crisp contracts, no mode confusion.
|
|
5265
|
+
*
|
|
5266
|
+
* @throws When no `CopilotChatConfigurationProvider` is in scope or when the
|
|
5267
|
+
* active `threadId` is absent/empty.
|
|
5268
|
+
*
|
|
5269
|
+
* @example
|
|
5270
|
+
* ```tsx
|
|
5271
|
+
* function ThreadPanel({ scope }: Props) {
|
|
5272
|
+
* useLearningContainersInCurrentThread({
|
|
5273
|
+
* learningContainers: [scope],
|
|
5274
|
+
* });
|
|
5275
|
+
* // ...
|
|
5276
|
+
* }
|
|
5277
|
+
* ```
|
|
5278
|
+
*/
|
|
5279
|
+
function useLearningContainersInCurrentThread({ learningContainers }) {
|
|
5280
|
+
const threadId = useCopilotChatConfiguration()?.threadId;
|
|
5281
|
+
if (!threadId) throw new Error("useLearningContainersInCurrentThread must be used within a thread context (no active threadId). Wrap the component in <CopilotChat>, <CopilotSidebar>, or <CopilotChatConfigurationProvider>, or use `useLearningContainers()` and pass `threadId` explicitly.");
|
|
5282
|
+
useLearningContainers({
|
|
5283
|
+
threadId,
|
|
5284
|
+
learningContainers
|
|
5285
|
+
});
|
|
5286
|
+
}
|
|
5287
|
+
|
|
4972
5288
|
//#endregion
|
|
4973
5289
|
//#region src/v2/components/chat/CopilotChatToolCallsView.tsx
|
|
4974
5290
|
function CopilotChatToolCallsView({ message, messages = [] }) {
|
|
@@ -5741,33 +6057,174 @@ CopilotChatSuggestionView.displayName = "CopilotChatSuggestionView";
|
|
|
5741
6057
|
*/
|
|
5742
6058
|
const ScrollElementContext = react.default.createContext(null);
|
|
5743
6059
|
|
|
6060
|
+
//#endregion
|
|
6061
|
+
//#region src/v2/components/intelligence-indicator/IntelligenceIndicatorView.tsx
|
|
6062
|
+
/**
|
|
6063
|
+
* The presentational "CopilotKit Intelligence" face — the default
|
|
6064
|
+
* rendered by the {@link IntelligenceIndicator} brain and the default
|
|
6065
|
+
* value for the `intelligenceIndicator` slot.
|
|
6066
|
+
*
|
|
6067
|
+
* Single-element three-stage design:
|
|
6068
|
+
* 1. **In-progress.** Glassmorphism pill chrome around a 270° arc icon
|
|
6069
|
+
* and the label. The arc has a single continuous visible stroke
|
|
6070
|
+
* (one `stroke-dasharray` dash + one gap, summing to the path
|
|
6071
|
+
* length) and the whole SVG rotates — so the viewer sees one
|
|
6072
|
+
* C-shaped arc spinning around the visual center.
|
|
6073
|
+
* 2. **Icon morph (~250 ms).** On status flip the single icon path
|
|
6074
|
+
* interpolates from the arc to a checkmark via CSS `d:` while the
|
|
6075
|
+
* dashed stroke transitions to solid (filling in the gap that was
|
|
6076
|
+
* the spinner's open portion). The SVG rotation animation is
|
|
6077
|
+
* removed; the snap back to identity is masked by the simultaneous
|
|
6078
|
+
* shape change. Chrome and text stay at full opacity throughout.
|
|
6079
|
+
* 3. **Settle (~400 ms, starts at +250 ms).** Chrome (background,
|
|
6080
|
+
* border, shadow, backdrop-blur) fades to zero opacity. The label
|
|
6081
|
+
* and icon stroke color transitions from saturated purple to a
|
|
6082
|
+
* true-neutral gray at 0.8 alpha — no hue cast, reads as "settled
|
|
6083
|
+
* history metadata." The label simultaneously skews to ~10° (a
|
|
6084
|
+
* transform-based italic feel that interpolates smoothly with the
|
|
6085
|
+
* color, rather than the discrete `font-style: italic` snap that
|
|
6086
|
+
* would cause a layout pop). The label text stays put — only its
|
|
6087
|
+
* color and slant change — so there is no "bump" where the brand
|
|
6088
|
+
* text disappears and reappears.
|
|
6089
|
+
*
|
|
6090
|
+
* Hard sequence: stage 3 has a 250 ms transition-delay so it waits
|
|
6091
|
+
* for stage 2 to finish. Total settle time ~650 ms in production.
|
|
6092
|
+
*
|
|
6093
|
+
* Both shapes are 3-segment cubic Bézier paths with matched command
|
|
6094
|
+
* structure (one `M` plus three `C`s), which is what makes the d
|
|
6095
|
+
* morph interpolate as a continuous shape change rather than snapping.
|
|
6096
|
+
*
|
|
6097
|
+
* The label is identical in both states (default "CopilotKit
|
|
6098
|
+
* Intelligence"). The static check icon carries the "done" semantic;
|
|
6099
|
+
* the color + slant transition does the "settle" work without needing
|
|
6100
|
+
* any wording change.
|
|
6101
|
+
*
|
|
6102
|
+
* Customize via the `intelligenceIndicator` slot on `CopilotChat`:
|
|
6103
|
+
* a className string restyles the wrapper, a props object tweaks
|
|
6104
|
+
* the default (`{ label }`), and a component replaces it entirely
|
|
6105
|
+
* with full control over visuals and timing.
|
|
6106
|
+
*/
|
|
6107
|
+
function IntelligenceIndicatorView({ message, status, label, className, ...rest }) {
|
|
6108
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6109
|
+
className: (0, tailwind_merge.twMerge)("cpk-intelligence-indicator", className),
|
|
6110
|
+
role: "status",
|
|
6111
|
+
"aria-live": "polite",
|
|
6112
|
+
"data-testid": `cpk-intelligence-indicator-${message.id}`,
|
|
6113
|
+
"data-status": status,
|
|
6114
|
+
title: label,
|
|
6115
|
+
...rest,
|
|
6116
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6117
|
+
className: "cpk-intelligence-indicator__chrome",
|
|
6118
|
+
"aria-hidden": "true"
|
|
6119
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
6120
|
+
className: "cpk-intelligence-indicator__content",
|
|
6121
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
|
|
6122
|
+
className: "cpk-intelligence-indicator__icon",
|
|
6123
|
+
viewBox: "0 0 24 24",
|
|
6124
|
+
width: "14",
|
|
6125
|
+
height: "14",
|
|
6126
|
+
"aria-hidden": "true",
|
|
6127
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { className: "cpk-intelligence-indicator__icon-path" })
|
|
6128
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6129
|
+
className: "cpk-intelligence-indicator__label",
|
|
6130
|
+
children: label
|
|
6131
|
+
})]
|
|
6132
|
+
})]
|
|
6133
|
+
});
|
|
6134
|
+
}
|
|
6135
|
+
|
|
5744
6136
|
//#endregion
|
|
5745
6137
|
//#region src/v2/components/intelligence-indicator/IntelligenceIndicator.tsx
|
|
5746
6138
|
/**
|
|
5747
6139
|
* Grace window before showing the spinner. A matching tool call must
|
|
5748
6140
|
* remain unresolved (no `tool`-role result message in `agent.messages`)
|
|
5749
|
-
* for at least this long before the
|
|
5750
|
-
* history-replay flashes — during
|
|
5751
|
-
*
|
|
5752
|
-
*
|
|
5753
|
-
*
|
|
6141
|
+
* for at least this long before the indicator transitions out of
|
|
6142
|
+
* `hidden`. This filters out history-replay flashes — during
|
|
6143
|
+
* `connectAgent` replay, tool calls and their results arrive
|
|
6144
|
+
* back-to-back in sub-millisecond bursts, so the timer is cancelled
|
|
6145
|
+
* before it fires. Live runs cross the threshold easily because the
|
|
6146
|
+
* tool actually has to execute.
|
|
5754
6147
|
*/
|
|
5755
6148
|
const PENDING_THRESHOLD_MS = 100;
|
|
5756
|
-
/** Hold the checkmark briefly before fading out. */
|
|
5757
|
-
const CHECK_HOLD_MS = 800;
|
|
5758
6149
|
/**
|
|
5759
|
-
*
|
|
5760
|
-
*
|
|
6150
|
+
* Tool-name regex patterns that trigger the indicator. Matches any tool
|
|
6151
|
+
* name *containing* the Intelligence MCP server's canonical tool name, so
|
|
6152
|
+
* both the bare `copilotkit_knowledge_base_shell` and the namespaced
|
|
6153
|
+
* `mcp__<server>__copilotkit_knowledge_base_shell` form (emitted by
|
|
6154
|
+
* `@ag-ui/mcp-middleware`) light up the pill. If we add per-instance
|
|
6155
|
+
* customization later (e.g. a `CopilotKitProvider` prop or a runtime-info
|
|
6156
|
+
* field), this constant becomes the fallback.
|
|
5761
6157
|
*/
|
|
5762
|
-
const
|
|
6158
|
+
const DEFAULT_TOOL_PATTERNS = [/copilotkit_knowledge_base_shell/];
|
|
5763
6159
|
/**
|
|
5764
|
-
*
|
|
5765
|
-
*
|
|
5766
|
-
*
|
|
5767
|
-
*
|
|
6160
|
+
* Phase to start in when an indicator first mounts. A turn that is already
|
|
6161
|
+
* complete at mount jumps straight to `finished` — no `hidden` flash, no
|
|
6162
|
+
* spinner blip — which is what makes scrolled-back / replayed history render
|
|
6163
|
+
* its indicators directly in the finished state.
|
|
6164
|
+
*
|
|
6165
|
+
* Pure and timing-free on purpose: the grace window ({@link
|
|
6166
|
+
* PENDING_THRESHOLD_MS}) only controls *when* the live transition is applied;
|
|
6167
|
+
* these functions decide *what* it resolves to, so the decision can be unit
|
|
6168
|
+
* tested deterministically without any timers.
|
|
5768
6169
|
*/
|
|
5769
|
-
|
|
6170
|
+
function initialIndicatorPhase(turnComplete) {
|
|
6171
|
+
return turnComplete ? "finished" : "hidden";
|
|
6172
|
+
}
|
|
6173
|
+
/**
|
|
6174
|
+
* Phase the grace window resolves to once it elapses:
|
|
6175
|
+
* - completed turn → `finished` (replay-flash suppression: a tool whose
|
|
6176
|
+
* result lands within the window skips the spinner entirely),
|
|
6177
|
+
* - a still-pending matching tool call → `spinner`,
|
|
6178
|
+
* - otherwise stay `hidden` (the matching tool call hasn't landed yet).
|
|
6179
|
+
*/
|
|
6180
|
+
function resolveGracePhase(turnComplete, hasPending) {
|
|
6181
|
+
if (turnComplete) return "finished";
|
|
6182
|
+
if (hasPending) return "spinner";
|
|
6183
|
+
return "hidden";
|
|
6184
|
+
}
|
|
5770
6185
|
const isMatchingToolCallName = (name) => typeof name === "string" && DEFAULT_TOOL_PATTERNS.some((p) => p.test(name));
|
|
6186
|
+
const messageHasMatchingToolCall = (m) => {
|
|
6187
|
+
if (m.role !== "assistant") return false;
|
|
6188
|
+
return (Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name));
|
|
6189
|
+
};
|
|
6190
|
+
/**
|
|
6191
|
+
* Stable turn id for the messages that precede the first user message (a turn
|
|
6192
|
+
* with no opening user message of its own). Used as the React key so the
|
|
6193
|
+
* indicator for that turn never collides with a real user-message id.
|
|
6194
|
+
*/
|
|
6195
|
+
const INTELLIGENCE_TURN_HEAD = "__cpk_turn_head__";
|
|
6196
|
+
/**
|
|
6197
|
+
* Map each Intelligence-using turn to its anchor message — the FIRST bash-using
|
|
6198
|
+
* assistant message of the turn — and a stable turn id (the id of the user
|
|
6199
|
+
* message that opened the turn, or {@link INTELLIGENCE_TURN_HEAD} for the
|
|
6200
|
+
* pre-first-user turn). Returns `Map<anchorMessageId, turnId>`.
|
|
6201
|
+
*
|
|
6202
|
+
* Anchoring to the FIRST (not last) bash-using message keeps the indicator
|
|
6203
|
+
* fixed in place for the whole turn: later bash steps don't reposition it, so
|
|
6204
|
+
* the spinner never abruptly jumps mid-turn (bug 1). `CopilotChatMessageView`
|
|
6205
|
+
* emits exactly one `IntelligenceIndicator` per entry, keyed by the turn id and
|
|
6206
|
+
* positioned at the anchor; the per-turn key also lets every past turn keep its
|
|
6207
|
+
* own indicator in scroll-back.
|
|
6208
|
+
*/
|
|
6209
|
+
function getIntelligenceTurnAnchors(messages) {
|
|
6210
|
+
const anchors = /* @__PURE__ */ new Map();
|
|
6211
|
+
let turnId = INTELLIGENCE_TURN_HEAD;
|
|
6212
|
+
let anchorId = null;
|
|
6213
|
+
const commit = () => {
|
|
6214
|
+
if (anchorId !== null) anchors.set(anchorId, turnId);
|
|
6215
|
+
anchorId = null;
|
|
6216
|
+
};
|
|
6217
|
+
for (const m of messages) {
|
|
6218
|
+
if (m.role === "user") {
|
|
6219
|
+
commit();
|
|
6220
|
+
turnId = m.id;
|
|
6221
|
+
continue;
|
|
6222
|
+
}
|
|
6223
|
+
if (anchorId === null && messageHasMatchingToolCall(m)) anchorId = m.id;
|
|
6224
|
+
}
|
|
6225
|
+
commit();
|
|
6226
|
+
return anchors;
|
|
6227
|
+
}
|
|
5771
6228
|
/**
|
|
5772
6229
|
* "Tool-call-like" messages do NOT count as a real follow-up: tool
|
|
5773
6230
|
* result messages, assistant messages that carry tool calls, and
|
|
@@ -5786,45 +6243,51 @@ const isToolCallLikeMessage = (m) => {
|
|
|
5786
6243
|
return false;
|
|
5787
6244
|
};
|
|
5788
6245
|
/**
|
|
5789
|
-
* The "Using CopilotKit Intelligence"
|
|
5790
|
-
* `CopilotChatMessageView`
|
|
5791
|
-
*
|
|
5792
|
-
*
|
|
5793
|
-
*
|
|
6246
|
+
* The "Using CopilotKit Intelligence" indicator brain. Auto-mounted by
|
|
6247
|
+
* `CopilotChatMessageView` — once per Intelligence-using turn, at that
|
|
6248
|
+
* turn's anchor message and keyed by the turn id (see
|
|
6249
|
+
* {@link getIntelligenceTurnAnchors}). Callers do not register this
|
|
6250
|
+
* themselves. It owns the run subscription and the phase machine and
|
|
6251
|
+
* renders its swappable face via the `intelligenceIndicator` slot.
|
|
6252
|
+
*
|
|
6253
|
+
* Placement (which message anchors the turn) is decided by the view, so
|
|
6254
|
+
* this component does not self-gate its own placement; it only derives
|
|
6255
|
+
* in-progress/finished for the turn it was mounted on.
|
|
5794
6256
|
*
|
|
5795
6257
|
* Render gates (all must hold):
|
|
5796
6258
|
* 1. `copilotkit.intelligence !== undefined`
|
|
5797
|
-
* 2. The message is an assistant message with at least one
|
|
5798
|
-
* whose name matches {@link DEFAULT_TOOL_PATTERNS}
|
|
5799
|
-
* 3. The
|
|
5800
|
-
*
|
|
5801
|
-
*
|
|
5802
|
-
*
|
|
5803
|
-
*
|
|
5804
|
-
*
|
|
6259
|
+
* 2. The (anchor) message is an assistant message with at least one
|
|
6260
|
+
* tool call whose name matches {@link DEFAULT_TOOL_PATTERNS}.
|
|
6261
|
+
* 3. The phase machine is past `hidden`.
|
|
6262
|
+
*
|
|
6263
|
+
* Because the view keys each indicator by its turn id, the instance moves
|
|
6264
|
+
* with the anchor across a hand-off (no remount, no spinner restart), and
|
|
6265
|
+
* every prior Intelligence-using turn keeps its own persistent indicator
|
|
6266
|
+
* in chat history.
|
|
5805
6267
|
*
|
|
5806
6268
|
* Phase machine (per-instance, all timers local):
|
|
5807
|
-
* - Starts in `
|
|
5808
|
-
*
|
|
6269
|
+
* - Starts in `hidden`, unless the message mounts onto an
|
|
6270
|
+
* already-completed turn (no pending work, agent stopped or a
|
|
6271
|
+
* real follow-up already present), in which case the lazy
|
|
6272
|
+
* `useState` initializer starts directly in `finished`. This is
|
|
6273
|
+
* what avoids a "hidden flash" on history replay.
|
|
6274
|
+
* - `hidden → spinner` once a matching tool call has been pending
|
|
5809
6275
|
* (no `tool`-role result with a matching `toolCallId`) for
|
|
5810
6276
|
* {@link PENDING_THRESHOLD_MS}. Replay flashes (tool call + result
|
|
5811
6277
|
* in the same tick) never cross this threshold.
|
|
5812
|
-
* - `
|
|
6278
|
+
* - `hidden → finished` if after the grace window the turn is
|
|
6279
|
+
* already complete (no pending work AND
|
|
6280
|
+
* `sawRealFollowup || !agent.isRunning`). Handles very fast tools
|
|
6281
|
+
* whose result lands within the grace window.
|
|
6282
|
+
* - `spinner → finished` as soon as EITHER `agent.isRunning` flips
|
|
5813
6283
|
* false OR a non-tool-call-like message appears later in
|
|
5814
|
-
* `agent.messages` (i.e. the agent
|
|
5815
|
-
*
|
|
5816
|
-
* - `
|
|
5817
|
-
*
|
|
5818
|
-
*
|
|
5819
|
-
* Once `hidden`, the phase is sticky — a finished pill never re-spawns
|
|
5820
|
-
* on the same message. New runs mount fresh indicator instances on
|
|
5821
|
-
* their own assistant messages.
|
|
5822
|
-
*
|
|
5823
|
-
* The "exactly one pill at a time" guarantee is structural: only one
|
|
5824
|
-
* message satisfies the latest-matching-assistant gate at any moment.
|
|
6284
|
+
* `agent.messages` (i.e. the agent produced a "real" follow-up —
|
|
6285
|
+
* prose answer or a new user turn).
|
|
6286
|
+
* - `finished` is terminal: the indicator settles into its
|
|
6287
|
+
* persistent tag form and stays mounted.
|
|
5825
6288
|
*/
|
|
5826
6289
|
function IntelligenceIndicator(props) {
|
|
5827
|
-
const { message, agentId, label = "
|
|
6290
|
+
const { message, agentId, label = "CopilotKit Intelligence", intelligenceIndicator } = props;
|
|
5828
6291
|
const { copilotkit } = useCopilotKit();
|
|
5829
6292
|
const config = useCopilotChatConfiguration();
|
|
5830
6293
|
const { agent } = useAgent({
|
|
@@ -5844,84 +6307,37 @@ function IntelligenceIndicator(props) {
|
|
|
5844
6307
|
for (const m of agent.messages) if (m.role === "tool" && m.toolCallId) resolved.add(m.toolCallId);
|
|
5845
6308
|
return matchingToolCallIds.some((id) => !resolved.has(id));
|
|
5846
6309
|
}, [matchingToolCallIds, agent.messages]);
|
|
5847
|
-
const
|
|
6310
|
+
const turnComplete = (0, react.useMemo)(() => {
|
|
5848
6311
|
const idx = agent.messages.findIndex((m) => m.id === message.id);
|
|
5849
6312
|
if (idx < 0) return false;
|
|
5850
6313
|
for (let i = idx + 1; i < agent.messages.length; i += 1) if (!isToolCallLikeMessage(agent.messages[i])) return true;
|
|
5851
6314
|
return false;
|
|
5852
|
-
}, [agent.messages, message.id]);
|
|
5853
|
-
const [phase, setPhase] = (0, react.useState)(
|
|
6315
|
+
}, [agent.messages, message.id]) || !agent.isRunning;
|
|
6316
|
+
const [phase, setPhase] = (0, react.useState)(() => initialIndicatorPhase(turnComplete));
|
|
5854
6317
|
(0, react.useEffect)(() => {
|
|
5855
|
-
if (phase !== "
|
|
5856
|
-
|
|
5857
|
-
|
|
6318
|
+
if (phase !== "hidden") return void 0;
|
|
6319
|
+
const t = setTimeout(() => {
|
|
6320
|
+
setPhase(resolveGracePhase(turnComplete, hasPending));
|
|
6321
|
+
}, PENDING_THRESHOLD_MS);
|
|
5858
6322
|
return () => clearTimeout(t);
|
|
5859
|
-
}, [phase, hasPending]);
|
|
5860
|
-
(0, react.useEffect)(() => {
|
|
5861
|
-
if (phase !== "spinner") return void 0;
|
|
5862
|
-
if (!agent.isRunning || sawRealFollowup) setPhase("check");
|
|
5863
6323
|
}, [
|
|
5864
6324
|
phase,
|
|
5865
|
-
|
|
5866
|
-
|
|
6325
|
+
hasPending,
|
|
6326
|
+
turnComplete
|
|
5867
6327
|
]);
|
|
5868
6328
|
(0, react.useEffect)(() => {
|
|
5869
|
-
if (phase !== "
|
|
5870
|
-
|
|
5871
|
-
|
|
5872
|
-
}, [phase]);
|
|
5873
|
-
(0, react.useEffect)(() => {
|
|
5874
|
-
if (phase !== "fading") return void 0;
|
|
5875
|
-
const t = setTimeout(() => setPhase("hidden"), FADE_OUT_ANIMATION_MS);
|
|
5876
|
-
return () => clearTimeout(t);
|
|
5877
|
-
}, [phase]);
|
|
6329
|
+
if (phase !== "spinner") return void 0;
|
|
6330
|
+
if (turnComplete) setPhase("finished");
|
|
6331
|
+
}, [phase, turnComplete]);
|
|
5878
6332
|
if (copilotkit.intelligence === void 0) return null;
|
|
5879
6333
|
if (!config) return null;
|
|
5880
|
-
if (phase === "
|
|
6334
|
+
if (phase === "hidden") return null;
|
|
5881
6335
|
if (message.role !== "assistant") return null;
|
|
5882
|
-
if (!(
|
|
5883
|
-
|
|
5884
|
-
|
|
5885
|
-
|
|
5886
|
-
|
|
5887
|
-
if ((Array.isArray(m.toolCalls) ? m.toolCalls : []).some((tc) => isMatchingToolCallName(tc?.function?.name))) {
|
|
5888
|
-
latestMatchingAssistantId = m.id;
|
|
5889
|
-
break;
|
|
5890
|
-
}
|
|
5891
|
-
}
|
|
5892
|
-
if (latestMatchingAssistantId !== message.id) return null;
|
|
5893
|
-
const showSpinner = phase === "spinner";
|
|
5894
|
-
const isFading = phase === "fading";
|
|
5895
|
-
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
5896
|
-
className: "cpk-intelligence-pill" + (isFading ? " cpk-intelligence-pill--fading" : ""),
|
|
5897
|
-
role: "status",
|
|
5898
|
-
"aria-live": "polite",
|
|
5899
|
-
"aria-hidden": isFading || void 0,
|
|
5900
|
-
"data-testid": `cpk-intelligence-pill-${message.id}`,
|
|
5901
|
-
title: label,
|
|
5902
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
5903
|
-
className: "cpk-intelligence-pill__icon",
|
|
5904
|
-
viewBox: "0 0 24 24",
|
|
5905
|
-
width: "14",
|
|
5906
|
-
height: "14",
|
|
5907
|
-
"aria-hidden": "true",
|
|
5908
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
5909
|
-
cx: "12",
|
|
5910
|
-
cy: "12",
|
|
5911
|
-
r: "9",
|
|
5912
|
-
fill: "none",
|
|
5913
|
-
strokeWidth: "2.5",
|
|
5914
|
-
strokeLinecap: "round",
|
|
5915
|
-
className: "cpk-intelligence-pill__ring" + (showSpinner ? "" : " cpk-intelligence-pill__ring--done")
|
|
5916
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
|
|
5917
|
-
d: "M8 12.5l3 3 5-6",
|
|
5918
|
-
fill: "none",
|
|
5919
|
-
strokeWidth: "2.5",
|
|
5920
|
-
strokeLinecap: "round",
|
|
5921
|
-
strokeLinejoin: "round",
|
|
5922
|
-
className: "cpk-intelligence-pill__check" + (showSpinner ? "" : " cpk-intelligence-pill__check--shown")
|
|
5923
|
-
})]
|
|
5924
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: label })]
|
|
6336
|
+
if (!messageHasMatchingToolCall(message)) return null;
|
|
6337
|
+
return renderSlot(intelligenceIndicator, IntelligenceIndicatorView, {
|
|
6338
|
+
message,
|
|
6339
|
+
status: phase === "finished" ? "finished" : "in-progress",
|
|
6340
|
+
label
|
|
5925
6341
|
});
|
|
5926
6342
|
}
|
|
5927
6343
|
|
|
@@ -6074,7 +6490,7 @@ function deduplicateMessages(messages) {
|
|
|
6074
6490
|
return [...acc.values()];
|
|
6075
6491
|
}
|
|
6076
6492
|
const VIRTUALIZE_THRESHOLD = 50;
|
|
6077
|
-
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, isRunning = false, children, className, ...props }) {
|
|
6493
|
+
function CopilotChatMessageView({ messages = [], assistantMessage, userMessage, reasoningMessage, cursor, intelligenceIndicator, isRunning = false, children, className, ...props }) {
|
|
6078
6494
|
const renderCustomMessage = useRenderCustomMessages();
|
|
6079
6495
|
const { renderActivityMessage } = useRenderActivityMessage();
|
|
6080
6496
|
const { copilotkit } = useCopilotKit();
|
|
@@ -6132,6 +6548,7 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
6132
6548
|
if (!shouldVirtualize || !deduplicatedMessages.length) return;
|
|
6133
6549
|
virtualizer.scrollToIndex(deduplicatedMessages.length - 1, { align: "end" });
|
|
6134
6550
|
}, [shouldVirtualize, firstMessageId]);
|
|
6551
|
+
const intelligenceTurnAnchors = (0, react.useMemo)(() => getIntelligenceTurnAnchors(deduplicatedMessages), [deduplicatedMessages]);
|
|
6135
6552
|
const renderMessageBlock = (message) => {
|
|
6136
6553
|
const elements = [];
|
|
6137
6554
|
const stateSnapshot = getStateSnapshotForMessage(message.id);
|
|
@@ -6170,10 +6587,12 @@ function CopilotChatMessageView({ messages = [], assistantMessage, userMessage,
|
|
|
6170
6587
|
renderCustomMessage,
|
|
6171
6588
|
stateSnapshot
|
|
6172
6589
|
}, `${message.id}-custom-after`));
|
|
6173
|
-
|
|
6590
|
+
const intelligenceTurnId = intelligenceTurnAnchors.get(message.id);
|
|
6591
|
+
if (intelligenceTurnId !== void 0) elements.push(/* @__PURE__ */ (0, react_jsx_runtime.jsx)(IntelligenceIndicator, {
|
|
6174
6592
|
message,
|
|
6175
|
-
agentId: config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID
|
|
6176
|
-
|
|
6593
|
+
agentId: config?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID,
|
|
6594
|
+
intelligenceIndicator
|
|
6595
|
+
}, `intelligence-${intelligenceTurnId}`));
|
|
6177
6596
|
return elements.filter(Boolean);
|
|
6178
6597
|
};
|
|
6179
6598
|
const messageElements = shouldVirtualize ? [] : deduplicatedMessages.flatMap(renderMessageBlock);
|
|
@@ -6610,7 +7029,7 @@ function DropOverlay() {
|
|
|
6610
7029
|
})
|
|
6611
7030
|
});
|
|
6612
7031
|
}
|
|
6613
|
-
function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, children, className, ...props }) {
|
|
7032
|
+
function CopilotChatView({ messageView, input, scrollView, suggestionView, welcomeScreen, messages = [], autoScroll = true, isRunning = false, suggestions, suggestionLoadingIndexes, onSelectSuggestion, onSubmitMessage, onStop, inputMode, inputValue, onInputChange, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, attachments, onRemoveAttachment, onAddFile, dragOver, onDragOver, onDragLeave, onDrop, isConnecting = false, hasExplicitThreadId = false, disclaimer, intelligenceIndicator, children, className, ...props }) {
|
|
6614
7033
|
const [inputContainerEl, setInputContainerEl] = (0, react.useState)(null);
|
|
6615
7034
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
6616
7035
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -6647,7 +7066,8 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6647
7066
|
}, [inputContainerEl]);
|
|
6648
7067
|
const BoundMessageView = renderSlot(messageView, CopilotChatMessageView, {
|
|
6649
7068
|
messages,
|
|
6650
|
-
isRunning
|
|
7069
|
+
isRunning,
|
|
7070
|
+
intelligenceIndicator
|
|
6651
7071
|
});
|
|
6652
7072
|
const BoundInput = renderSlot(input, CopilotChatInput_default, {
|
|
6653
7073
|
onSubmitMessage,
|
|
@@ -7153,6 +7573,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7153
7573
|
const [transcriptionError, setTranscriptionError] = (0, react.useState)(null);
|
|
7154
7574
|
const [isTranscribing, setIsTranscribing] = (0, react.useState)(false);
|
|
7155
7575
|
const { attachments: selectedAttachments, enabled: attachmentsEnabled, dragOver, fileInputRef, containerRef: chatContainerRef, handleFileUpload, handleDragOver, handleDragLeave, handleDrop, removeAttachment, consumeAttachments } = useAttachments({ config: attachmentsConfig });
|
|
7576
|
+
const selectedAttachmentsRef = (0, react.useRef)(selectedAttachments);
|
|
7577
|
+
(0, react.useEffect)(() => {
|
|
7578
|
+
selectedAttachmentsRef.current = selectedAttachments;
|
|
7579
|
+
}, [selectedAttachments]);
|
|
7156
7580
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
7157
7581
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
7158
7582
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
@@ -7188,9 +7612,25 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7188
7612
|
resolvedAgentId,
|
|
7189
7613
|
hasExplicitThreadId
|
|
7190
7614
|
]);
|
|
7615
|
+
const waitForActiveRunToSettle = (0, react.useCallback)(async () => {
|
|
7616
|
+
if (agent.isRunning && (0, _copilotkit_core.isRunCompletionAware)(agent) && agent.activeRunCompletionPromise) try {
|
|
7617
|
+
await agent.activeRunCompletionPromise;
|
|
7618
|
+
} catch (error) {
|
|
7619
|
+
console.error("CopilotChat: in-flight run rejected while queuing send", error);
|
|
7620
|
+
}
|
|
7621
|
+
}, [agent]);
|
|
7191
7622
|
const onSubmitInput = (0, react.useCallback)(async (value) => {
|
|
7192
|
-
if (
|
|
7193
|
-
console.error("[CopilotKit] Cannot send while attachments are uploading");
|
|
7623
|
+
if (selectedAttachmentsRef.current.some((a) => a.status === "uploading")) {
|
|
7624
|
+
console.error("[CopilotKit] Cannot send while attachments are uploading (pre-await guard)");
|
|
7625
|
+
setTranscriptionError("Cannot send while attachments are uploading.");
|
|
7626
|
+
return;
|
|
7627
|
+
}
|
|
7628
|
+
setInputValue("");
|
|
7629
|
+
await waitForActiveRunToSettle();
|
|
7630
|
+
if (selectedAttachmentsRef.current.some((a) => a.status === "uploading")) {
|
|
7631
|
+
console.error("[CopilotKit] Cannot send while attachments are uploading (post-await re-check)");
|
|
7632
|
+
setTranscriptionError("Cannot send while attachments are uploading.");
|
|
7633
|
+
setInputValue(value);
|
|
7194
7634
|
return;
|
|
7195
7635
|
}
|
|
7196
7636
|
const readyAttachments = consumeAttachments();
|
|
@@ -7218,7 +7658,6 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7218
7658
|
role: "user",
|
|
7219
7659
|
content: value
|
|
7220
7660
|
});
|
|
7221
|
-
setInputValue("");
|
|
7222
7661
|
try {
|
|
7223
7662
|
await copilotkit.runAgent({ agent });
|
|
7224
7663
|
} catch (error) {
|
|
@@ -7226,10 +7665,11 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7226
7665
|
}
|
|
7227
7666
|
}, [
|
|
7228
7667
|
agent,
|
|
7229
|
-
|
|
7230
|
-
|
|
7668
|
+
consumeAttachments,
|
|
7669
|
+
waitForActiveRunToSettle
|
|
7231
7670
|
]);
|
|
7232
7671
|
const handleSelectSuggestion = (0, react.useCallback)(async (suggestion) => {
|
|
7672
|
+
await waitForActiveRunToSettle();
|
|
7233
7673
|
agent.addMessage({
|
|
7234
7674
|
id: (0, _copilotkit_shared.randomUUID)(),
|
|
7235
7675
|
role: "user",
|
|
@@ -7240,7 +7680,7 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
7240
7680
|
} catch (error) {
|
|
7241
7681
|
console.error("CopilotChat: runAgent failed after selecting suggestion", error);
|
|
7242
7682
|
}
|
|
7243
|
-
}, [agent]);
|
|
7683
|
+
}, [agent, waitForActiveRunToSettle]);
|
|
7244
7684
|
const stopCurrentRun = (0, react.useCallback)(() => {
|
|
7245
7685
|
try {
|
|
7246
7686
|
copilotkit.stopAgent({ agent });
|
|
@@ -10308,12 +10748,24 @@ Object.defineProperty(exports, 'DefaultOpenIcon', {
|
|
|
10308
10748
|
return DefaultOpenIcon;
|
|
10309
10749
|
}
|
|
10310
10750
|
});
|
|
10751
|
+
Object.defineProperty(exports, 'INTELLIGENCE_TURN_HEAD', {
|
|
10752
|
+
enumerable: true,
|
|
10753
|
+
get: function () {
|
|
10754
|
+
return INTELLIGENCE_TURN_HEAD;
|
|
10755
|
+
}
|
|
10756
|
+
});
|
|
10311
10757
|
Object.defineProperty(exports, 'IntelligenceIndicator', {
|
|
10312
10758
|
enumerable: true,
|
|
10313
10759
|
get: function () {
|
|
10314
10760
|
return IntelligenceIndicator;
|
|
10315
10761
|
}
|
|
10316
10762
|
});
|
|
10763
|
+
Object.defineProperty(exports, 'IntelligenceIndicatorView', {
|
|
10764
|
+
enumerable: true,
|
|
10765
|
+
get: function () {
|
|
10766
|
+
return IntelligenceIndicatorView;
|
|
10767
|
+
}
|
|
10768
|
+
});
|
|
10317
10769
|
Object.defineProperty(exports, 'MCPAppsActivityContentSchema', {
|
|
10318
10770
|
enumerable: true,
|
|
10319
10771
|
get: function () {
|
|
@@ -10386,6 +10838,12 @@ Object.defineProperty(exports, 'defineToolCallRenderer', {
|
|
|
10386
10838
|
return defineToolCallRenderer;
|
|
10387
10839
|
}
|
|
10388
10840
|
});
|
|
10841
|
+
Object.defineProperty(exports, 'getIntelligenceTurnAnchors', {
|
|
10842
|
+
enumerable: true,
|
|
10843
|
+
get: function () {
|
|
10844
|
+
return getIntelligenceTurnAnchors;
|
|
10845
|
+
}
|
|
10846
|
+
});
|
|
10389
10847
|
Object.defineProperty(exports, 'shouldShowDevConsole', {
|
|
10390
10848
|
enumerable: true,
|
|
10391
10849
|
get: function () {
|
|
@@ -10488,6 +10946,30 @@ Object.defineProperty(exports, 'useInterrupt', {
|
|
|
10488
10946
|
return useInterrupt;
|
|
10489
10947
|
}
|
|
10490
10948
|
});
|
|
10949
|
+
Object.defineProperty(exports, 'useLearnFromUserAction', {
|
|
10950
|
+
enumerable: true,
|
|
10951
|
+
get: function () {
|
|
10952
|
+
return useLearnFromUserAction;
|
|
10953
|
+
}
|
|
10954
|
+
});
|
|
10955
|
+
Object.defineProperty(exports, 'useLearnFromUserActionInCurrentThread', {
|
|
10956
|
+
enumerable: true,
|
|
10957
|
+
get: function () {
|
|
10958
|
+
return useLearnFromUserActionInCurrentThread;
|
|
10959
|
+
}
|
|
10960
|
+
});
|
|
10961
|
+
Object.defineProperty(exports, 'useLearningContainers', {
|
|
10962
|
+
enumerable: true,
|
|
10963
|
+
get: function () {
|
|
10964
|
+
return useLearningContainers;
|
|
10965
|
+
}
|
|
10966
|
+
});
|
|
10967
|
+
Object.defineProperty(exports, 'useLearningContainersInCurrentThread', {
|
|
10968
|
+
enumerable: true,
|
|
10969
|
+
get: function () {
|
|
10970
|
+
return useLearningContainersInCurrentThread;
|
|
10971
|
+
}
|
|
10972
|
+
});
|
|
10491
10973
|
Object.defineProperty(exports, 'useRenderActivityMessage', {
|
|
10492
10974
|
enumerable: true,
|
|
10493
10975
|
get: function () {
|
|
@@ -10542,4 +11024,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
10542
11024
|
return useToast;
|
|
10543
11025
|
}
|
|
10544
11026
|
});
|
|
10545
|
-
//# sourceMappingURL=copilotkit-
|
|
11027
|
+
//# sourceMappingURL=copilotkit-LdQ8w20l.cjs.map
|