@copilotkit/react-core 1.56.2 → 1.56.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-Cj2ZIxVr.mjs → copilotkit-Bd0m5HFp.mjs} +266 -81
- package/dist/copilotkit-Bd0m5HFp.mjs.map +1 -0
- package/dist/{copilotkit-CCbxm6JM.d.mts → copilotkit-DFaI4j2r.d.mts} +64 -18
- package/dist/copilotkit-DFaI4j2r.d.mts.map +1 -0
- package/dist/{copilotkit-BtP7w7cT.d.cts → copilotkit-Dg4r4Gi_.d.cts} +64 -18
- package/dist/copilotkit-Dg4r4Gi_.d.cts.map +1 -0
- package/dist/{copilotkit-CSJw5BG8.cjs → copilotkit-tb4zqaMK.cjs} +265 -80
- package/dist/copilotkit-tb4zqaMK.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +31 -44
- package/dist/index.umd.js.map +1 -1
- package/dist/v2/index.cjs +1 -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 +1 -1
- package/dist/v2/index.umd.js +264 -83
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/components/copilot-provider/__tests__/v1-explicit-threadid-bridge.test.tsx +107 -0
- package/src/components/copilot-provider/copilotkit.tsx +6 -1
- package/src/context/__tests__/threads-context.test.tsx +116 -3
- package/src/context/threads-context.tsx +18 -1
- package/src/v2/components/chat/CopilotChat.tsx +91 -4
- package/src/v2/components/chat/CopilotChatAttachmentQueue.tsx +4 -1
- package/src/v2/components/chat/CopilotChatInput.tsx +22 -0
- package/src/v2/components/chat/CopilotChatView.tsx +207 -44
- package/src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx +66 -0
- package/src/v2/components/chat/__tests__/CopilotChat.welcomeGate.test.tsx +186 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +438 -4
- package/src/v2/components/chat/__tests__/CopilotChatView.connectingGate.test.tsx +56 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.inputOverlay.test.tsx +172 -0
- package/src/v2/components/chat/__tests__/CopilotChatView.pinToSend.test.tsx +94 -0
- package/src/v2/components/chat/__tests__/copilot-chat-throttle.test.tsx +0 -1
- package/src/v2/components/chat/__tests__/normalize-auto-scroll.test.ts +37 -0
- package/src/v2/components/chat/index.ts +2 -0
- package/src/v2/components/chat/last-user-message-context.ts +21 -0
- package/src/v2/components/chat/normalize-auto-scroll.ts +17 -0
- package/src/v2/components/license-warning-banner.tsx +20 -1
- package/src/v2/hooks/__tests__/use-agent-stability.test.tsx +6 -0
- package/src/v2/hooks/__tests__/use-agent-thread-isolation.test.tsx +6 -0
- package/src/v2/hooks/__tests__/use-agent-throttle.test.tsx +76 -50
- package/src/v2/hooks/__tests__/use-pin-to-send.test.tsx +219 -0
- package/src/v2/hooks/__tests__/use-threads.test.tsx +68 -0
- package/src/v2/hooks/use-agent.tsx +34 -77
- package/src/v2/hooks/use-pin-to-send.ts +94 -0
- package/src/v2/hooks/use-threads.tsx +55 -12
- package/src/v2/providers/CopilotChatConfigurationProvider.tsx +29 -1
- package/src/v2/providers/CopilotKitProvider.tsx +2 -11
- package/src/v2/providers/__tests__/CopilotChatConfigurationProvider.test.tsx +106 -0
- package/dist/copilotkit-BtP7w7cT.d.cts.map +0 -1
- package/dist/copilotkit-CCbxm6JM.d.mts.map +0 -1
- package/dist/copilotkit-CSJw5BG8.cjs.map +0 -1
- package/dist/copilotkit-Cj2ZIxVr.mjs.map +0 -1
|
@@ -175,7 +175,7 @@ const CopilotChatDefaultLabels = {
|
|
|
175
175
|
welcomeMessageText: "How can I help you today?"
|
|
176
176
|
};
|
|
177
177
|
const CopilotChatConfiguration = (0, react.createContext)(null);
|
|
178
|
-
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
|
|
178
|
+
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
|
|
179
179
|
const parentConfig = (0, react.useContext)(CopilotChatConfiguration);
|
|
180
180
|
const stableLabels = useShallowStableRef(labels);
|
|
181
181
|
const mergedLabels = (0, react.useMemo)(() => ({
|
|
@@ -189,6 +189,7 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
189
189
|
if (parentConfig?.threadId) return parentConfig.threadId;
|
|
190
190
|
return (0, _copilotkit_shared.randomUUID)();
|
|
191
191
|
}, [threadId, parentConfig?.threadId]);
|
|
192
|
+
const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
|
|
192
193
|
const [internalModalOpen, setInternalModalOpen] = (0, react.useState)(isModalDefaultOpen ?? true);
|
|
193
194
|
const hasExplicitDefault = isModalDefaultOpen !== void 0;
|
|
194
195
|
const setAndSync = (0, react.useCallback)((open) => {
|
|
@@ -211,12 +212,14 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
211
212
|
labels: mergedLabels,
|
|
212
213
|
agentId: resolvedAgentId,
|
|
213
214
|
threadId: resolvedThreadId,
|
|
215
|
+
hasExplicitThreadId: resolvedHasExplicitThreadId,
|
|
214
216
|
isModalOpen: resolvedIsModalOpen,
|
|
215
217
|
setModalOpen: resolvedSetModalOpen
|
|
216
218
|
}), [
|
|
217
219
|
mergedLabels,
|
|
218
220
|
resolvedAgentId,
|
|
219
221
|
resolvedThreadId,
|
|
222
|
+
resolvedHasExplicitThreadId,
|
|
220
223
|
resolvedIsModalOpen,
|
|
221
224
|
resolvedSetModalOpen
|
|
222
225
|
]);
|
|
@@ -610,7 +613,7 @@ CopilotChatAudioRecorder.displayName = "CopilotChatAudioRecorder";
|
|
|
610
613
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
611
614
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
612
615
|
const SLASH_MENU_ITEM_HEIGHT_PX = 40;
|
|
613
|
-
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
|
|
616
|
+
function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning = false, onStartTranscribe, onCancelTranscribe, onFinishTranscribe, onFinishTranscribeWithAudio, onAddFile, onChange, value, toolsMenu, autoFocus = false, positioning = "static", keyboardHeight = 0, containerRef, showDisclaimer, bottomAnchored = false, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
|
|
614
617
|
const isControlled = value !== void 0;
|
|
615
618
|
const [internalValue, setInternalValue] = (0, react.useState)(() => value ?? "");
|
|
616
619
|
(0, react.useEffect)(() => {
|
|
@@ -1134,7 +1137,8 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1134
1137
|
className: cn("cpk:pointer-events-none cpk:relative cpk:z-20", positioning === "absolute" && "cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-0", className),
|
|
1135
1138
|
style: {
|
|
1136
1139
|
transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
|
|
1137
|
-
transition: "transform 0.2s ease-out"
|
|
1140
|
+
transition: "transform 0.2s ease-out",
|
|
1141
|
+
...positioning === "absolute" || bottomAnchored ? { paddingBottom: "var(--copilotkit-license-banner-offset, 0px)" } : {}
|
|
1138
1142
|
},
|
|
1139
1143
|
...props,
|
|
1140
1144
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1349,6 +1353,8 @@ CopilotKitInspector.displayName = "CopilotKitInspector";
|
|
|
1349
1353
|
|
|
1350
1354
|
//#endregion
|
|
1351
1355
|
//#region src/v2/components/license-warning-banner.tsx
|
|
1356
|
+
const LICENSE_BANNER_OFFSET_PX = 52;
|
|
1357
|
+
const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
|
|
1352
1358
|
const BANNER_STYLES = {
|
|
1353
1359
|
base: {
|
|
1354
1360
|
position: "fixed",
|
|
@@ -1390,6 +1396,14 @@ function getSeverityStyle(severity) {
|
|
|
1390
1396
|
}
|
|
1391
1397
|
}
|
|
1392
1398
|
function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
|
|
1399
|
+
(0, react.useEffect)(() => {
|
|
1400
|
+
if (typeof document === "undefined") return;
|
|
1401
|
+
const root = document.documentElement;
|
|
1402
|
+
root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
|
|
1403
|
+
return () => {
|
|
1404
|
+
root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
|
|
1405
|
+
};
|
|
1406
|
+
}, []);
|
|
1393
1407
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1394
1408
|
style: {
|
|
1395
1409
|
...BANNER_STYLES.base,
|
|
@@ -3342,7 +3356,6 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
|
|
|
3342
3356
|
didMountRef.current = true;
|
|
3343
3357
|
}, []);
|
|
3344
3358
|
(0, react.useEffect)(() => {
|
|
3345
|
-
if (defaultThrottleMs !== void 0 && (!Number.isFinite(defaultThrottleMs) || defaultThrottleMs < 0)) console.error(`CopilotKitProvider: defaultThrottleMs must be a non-negative finite number, got ${defaultThrottleMs}. useAgent hooks without an explicit throttleMs will fall back to unthrottled.`);
|
|
3346
3359
|
copilotkit.setDefaultThrottleMs(defaultThrottleMs);
|
|
3347
3360
|
}, [copilotkit, defaultThrottleMs]);
|
|
3348
3361
|
const designSkill = openGenerativeUI?.designSkill ?? DEFAULT_DESIGN_SKILL;
|
|
@@ -3559,15 +3572,6 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3559
3572
|
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
3560
3573
|
const chatConfig = useCopilotChatConfiguration();
|
|
3561
3574
|
threadId ??= chatConfig?.threadId;
|
|
3562
|
-
const effectiveThrottleMs = (0, react.useMemo)(() => {
|
|
3563
|
-
const resolved = throttleMs ?? providerThrottleMs ?? 0;
|
|
3564
|
-
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
3565
|
-
const source = throttleMs !== void 0 ? "hook-level throttleMs" : "provider-level defaultThrottleMs";
|
|
3566
|
-
console.error(`useAgent: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`);
|
|
3567
|
-
return 0;
|
|
3568
|
-
}
|
|
3569
|
-
return resolved;
|
|
3570
|
-
}, [throttleMs, providerThrottleMs]);
|
|
3571
3575
|
const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
|
|
3572
3576
|
const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
3573
3577
|
const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -3630,9 +3634,8 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3630
3634
|
]);
|
|
3631
3635
|
(0, react.useEffect)(() => {
|
|
3632
3636
|
if (updateFlags.length === 0) return;
|
|
3633
|
-
const handlers = {};
|
|
3634
|
-
let timerId = null;
|
|
3635
3637
|
let active = true;
|
|
3638
|
+
const handlers = {};
|
|
3636
3639
|
let batchScheduled = false;
|
|
3637
3640
|
const batchedForceUpdate = () => {
|
|
3638
3641
|
if (!active) return;
|
|
@@ -3644,46 +3647,24 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3644
3647
|
});
|
|
3645
3648
|
}
|
|
3646
3649
|
};
|
|
3647
|
-
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged))
|
|
3648
|
-
const ms = effectiveThrottleMs;
|
|
3649
|
-
if (ms > 0) {
|
|
3650
|
-
let throttleActive = false;
|
|
3651
|
-
let pending = false;
|
|
3652
|
-
const throttledNotify = () => {
|
|
3653
|
-
if (!active) return;
|
|
3654
|
-
if (!throttleActive) {
|
|
3655
|
-
throttleActive = true;
|
|
3656
|
-
pending = false;
|
|
3657
|
-
forceUpdate();
|
|
3658
|
-
timerId = setTimeout(function trailingEdge() {
|
|
3659
|
-
timerId = null;
|
|
3660
|
-
if (active && pending) {
|
|
3661
|
-
pending = false;
|
|
3662
|
-
forceUpdate();
|
|
3663
|
-
timerId = setTimeout(trailingEdge, ms);
|
|
3664
|
-
} else throttleActive = false;
|
|
3665
|
-
}, ms);
|
|
3666
|
-
} else pending = true;
|
|
3667
|
-
};
|
|
3668
|
-
handlers.onMessagesChanged = throttledNotify;
|
|
3669
|
-
} else handlers.onMessagesChanged = forceUpdate;
|
|
3670
|
-
}
|
|
3650
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
|
|
3671
3651
|
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
3672
3652
|
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
3673
3653
|
handlers.onRunInitialized = batchedForceUpdate;
|
|
3674
3654
|
handlers.onRunFinalized = batchedForceUpdate;
|
|
3675
3655
|
handlers.onRunFailed = batchedForceUpdate;
|
|
3656
|
+
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
3676
3657
|
}
|
|
3677
|
-
const subscription =
|
|
3658
|
+
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
3678
3659
|
return () => {
|
|
3679
3660
|
active = false;
|
|
3680
|
-
if (timerId !== null) clearTimeout(timerId);
|
|
3681
3661
|
subscription.unsubscribe();
|
|
3682
3662
|
};
|
|
3683
3663
|
}, [
|
|
3684
3664
|
agent,
|
|
3685
3665
|
forceUpdate,
|
|
3686
|
-
|
|
3666
|
+
throttleMs,
|
|
3667
|
+
providerThrottleMs,
|
|
3687
3668
|
updateFlags
|
|
3688
3669
|
]);
|
|
3689
3670
|
(0, react.useEffect)(() => {
|
|
@@ -4637,13 +4618,14 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4637
4618
|
const { copilotkit } = useCopilotKit();
|
|
4638
4619
|
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
4639
4620
|
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
4640
|
-
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
|
|
4621
|
+
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
|
|
4641
4622
|
id,
|
|
4642
4623
|
agentId,
|
|
4643
4624
|
name,
|
|
4644
4625
|
archived,
|
|
4645
4626
|
createdAt,
|
|
4646
|
-
updatedAt
|
|
4627
|
+
updatedAt,
|
|
4628
|
+
...lastRunAt !== void 0 ? { lastRunAt } : {}
|
|
4647
4629
|
})), [coreThreads]);
|
|
4648
4630
|
const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
|
|
4649
4631
|
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
@@ -4656,7 +4638,9 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4656
4638
|
if (copilotkit.runtimeUrl) return null;
|
|
4657
4639
|
return /* @__PURE__ */ new Error("Runtime URL is not configured");
|
|
4658
4640
|
}, [copilotkit.runtimeUrl]);
|
|
4659
|
-
const
|
|
4641
|
+
const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
|
|
4642
|
+
const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
|
|
4643
|
+
const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
|
|
4660
4644
|
const error = runtimeError ?? storeError;
|
|
4661
4645
|
(0, react.useEffect)(() => {
|
|
4662
4646
|
store.start();
|
|
@@ -4664,19 +4648,27 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4664
4648
|
store.stop();
|
|
4665
4649
|
};
|
|
4666
4650
|
}, [store]);
|
|
4651
|
+
const runtimeStatus = copilotkit.runtimeConnectionStatus;
|
|
4667
4652
|
(0, react.useEffect)(() => {
|
|
4668
|
-
|
|
4653
|
+
if (!copilotkit.runtimeUrl) {
|
|
4654
|
+
store.setContext(null);
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
if (runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
|
|
4658
|
+
const context = {
|
|
4669
4659
|
runtimeUrl: copilotkit.runtimeUrl,
|
|
4670
4660
|
headers: { ...copilotkit.headers },
|
|
4671
4661
|
wsUrl: copilotkit.intelligence?.wsUrl,
|
|
4672
4662
|
agentId,
|
|
4673
4663
|
includeArchived,
|
|
4674
4664
|
limit
|
|
4675
|
-
}
|
|
4665
|
+
};
|
|
4676
4666
|
store.setContext(context);
|
|
4667
|
+
setHasDispatchedContext(true);
|
|
4677
4668
|
}, [
|
|
4678
4669
|
store,
|
|
4679
4670
|
copilotkit.runtimeUrl,
|
|
4671
|
+
runtimeStatus,
|
|
4680
4672
|
headersKey,
|
|
4681
4673
|
copilotkit.intelligence?.wsUrl,
|
|
4682
4674
|
agentId,
|
|
@@ -5859,6 +5851,7 @@ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
|
5859
5851
|
const CopilotChatAttachmentQueue = ({ attachments, onRemoveAttachment, className }) => {
|
|
5860
5852
|
if (attachments.length === 0) return null;
|
|
5861
5853
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
5854
|
+
"data-testid": "copilot-attachment-queue",
|
|
5862
5855
|
className: cn("cpk:flex cpk:flex-wrap cpk:gap-2 cpk:p-2", className),
|
|
5863
5856
|
children: attachments.map((attachment) => {
|
|
5864
5857
|
const isMedia = attachment.type === "image" || attachment.type === "video";
|
|
@@ -6201,9 +6194,91 @@ function useKeyboardHeight() {
|
|
|
6201
6194
|
return keyboardState;
|
|
6202
6195
|
}
|
|
6203
6196
|
|
|
6197
|
+
//#endregion
|
|
6198
|
+
//#region src/v2/components/chat/normalize-auto-scroll.ts
|
|
6199
|
+
const VALID = [
|
|
6200
|
+
"pin-to-bottom",
|
|
6201
|
+
"pin-to-send",
|
|
6202
|
+
"none"
|
|
6203
|
+
];
|
|
6204
|
+
function normalizeAutoScroll(value) {
|
|
6205
|
+
if (value === void 0) return "pin-to-bottom";
|
|
6206
|
+
if (value === true) return "pin-to-bottom";
|
|
6207
|
+
if (value === false) return "none";
|
|
6208
|
+
if (VALID.includes(value)) return value;
|
|
6209
|
+
return "pin-to-bottom";
|
|
6210
|
+
}
|
|
6211
|
+
|
|
6212
|
+
//#endregion
|
|
6213
|
+
//#region src/v2/components/chat/last-user-message-context.ts
|
|
6214
|
+
const LastUserMessageContext = react.default.createContext({
|
|
6215
|
+
id: null,
|
|
6216
|
+
sendNonce: 0
|
|
6217
|
+
});
|
|
6218
|
+
|
|
6219
|
+
//#endregion
|
|
6220
|
+
//#region src/v2/hooks/use-pin-to-send.ts
|
|
6221
|
+
function usePinToSend({ scrollRef, contentRef, spacerRef, topOffset = 16 }) {
|
|
6222
|
+
const { id, sendNonce } = (0, react.useContext)(LastUserMessageContext);
|
|
6223
|
+
const lastNonceRef = (0, react.useRef)(-1);
|
|
6224
|
+
const currentSpacerHeightRef = (0, react.useRef)(0);
|
|
6225
|
+
(0, react.useEffect)(() => {
|
|
6226
|
+
if (sendNonce === lastNonceRef.current) return;
|
|
6227
|
+
lastNonceRef.current = sendNonce;
|
|
6228
|
+
if (!id) return;
|
|
6229
|
+
const scrollEl = scrollRef.current;
|
|
6230
|
+
const contentEl = contentRef.current;
|
|
6231
|
+
const spacerEl = spacerRef.current;
|
|
6232
|
+
if (!scrollEl || !contentEl || !spacerEl) return;
|
|
6233
|
+
const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(id) : id.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
|
6234
|
+
const targetEl = contentEl.querySelector(`[data-message-id="${escaped}"]`);
|
|
6235
|
+
if (!targetEl) return;
|
|
6236
|
+
const viewportHeight = scrollEl.clientHeight;
|
|
6237
|
+
const userMessageHeight = targetEl.getBoundingClientRect().height;
|
|
6238
|
+
const paddingTop = parseFloat(getComputedStyle(targetEl).paddingTop) || 0;
|
|
6239
|
+
const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
|
|
6240
|
+
const spacerHeight = Math.max(0, viewportHeight - bubbleHeight - topOffset);
|
|
6241
|
+
spacerEl.style.height = `${spacerHeight}px`;
|
|
6242
|
+
currentSpacerHeightRef.current = spacerHeight;
|
|
6243
|
+
const raf = requestAnimationFrame(() => {
|
|
6244
|
+
const targetTop = computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
|
|
6245
|
+
scrollEl.scrollTo({
|
|
6246
|
+
top: Math.max(0, targetTop),
|
|
6247
|
+
behavior: "smooth"
|
|
6248
|
+
});
|
|
6249
|
+
});
|
|
6250
|
+
const ro = new ResizeObserver(() => {
|
|
6251
|
+
if (!contentEl || !spacerEl || !scrollEl) return;
|
|
6252
|
+
const consumedBelow = contentEl.getBoundingClientRect().height - computeOffsetTop(targetEl, contentEl) - userMessageHeight;
|
|
6253
|
+
const remaining = Math.max(0, spacerHeight - consumedBelow);
|
|
6254
|
+
if (remaining < currentSpacerHeightRef.current) {
|
|
6255
|
+
spacerEl.style.height = `${remaining}px`;
|
|
6256
|
+
currentSpacerHeightRef.current = remaining;
|
|
6257
|
+
}
|
|
6258
|
+
});
|
|
6259
|
+
ro.observe(contentEl);
|
|
6260
|
+
return () => {
|
|
6261
|
+
cancelAnimationFrame(raf);
|
|
6262
|
+
ro.disconnect();
|
|
6263
|
+
};
|
|
6264
|
+
}, [
|
|
6265
|
+
id,
|
|
6266
|
+
sendNonce,
|
|
6267
|
+
scrollRef,
|
|
6268
|
+
contentRef,
|
|
6269
|
+
spacerRef,
|
|
6270
|
+
topOffset
|
|
6271
|
+
]);
|
|
6272
|
+
}
|
|
6273
|
+
function computeOffsetTop(el, stopAt) {
|
|
6274
|
+
const elRect = el.getBoundingClientRect();
|
|
6275
|
+
const stopRect = stopAt.getBoundingClientRect();
|
|
6276
|
+
return elRect.top - stopRect.top + stopAt.scrollTop;
|
|
6277
|
+
}
|
|
6278
|
+
|
|
6204
6279
|
//#endregion
|
|
6205
6280
|
//#region src/v2/components/chat/CopilotChatView.tsx
|
|
6206
|
-
const
|
|
6281
|
+
const SCROLL_BUTTON_OFFSET = 16;
|
|
6207
6282
|
function DropOverlay() {
|
|
6208
6283
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6209
6284
|
className: cn("cpk:absolute cpk:inset-0 cpk:z-50 cpk:pointer-events-none", "cpk:flex cpk:items-center cpk:justify-center", "cpk:bg-primary/5 cpk:backdrop-blur-[2px]", "cpk:border-2 cpk:border-dashed cpk:border-primary/40 cpk:rounded-lg cpk:m-2"),
|
|
@@ -6216,7 +6291,7 @@ function DropOverlay() {
|
|
|
6216
6291
|
})
|
|
6217
6292
|
});
|
|
6218
6293
|
}
|
|
6219
|
-
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, disclaimer, children, className, ...props }) {
|
|
6294
|
+
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 }) {
|
|
6220
6295
|
const inputContainerRef = (0, react.useRef)(null);
|
|
6221
6296
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
6222
6297
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -6266,11 +6341,11 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6266
6341
|
onAddFile,
|
|
6267
6342
|
positioning: "static",
|
|
6268
6343
|
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
|
|
6269
|
-
containerRef: inputContainerRef,
|
|
6270
6344
|
showDisclaimer: true,
|
|
6345
|
+
bottomAnchored: true,
|
|
6271
6346
|
...disclaimer !== void 0 ? { disclaimer } : {}
|
|
6272
6347
|
});
|
|
6273
|
-
const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
|
|
6348
|
+
const hasSuggestions = !isConnecting && !isRunning && Array.isArray(suggestions) && suggestions.length > 0;
|
|
6274
6349
|
const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView, {
|
|
6275
6350
|
suggestions,
|
|
6276
6351
|
loadingIndexes: suggestionLoadingIndexes,
|
|
@@ -6282,7 +6357,8 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6282
6357
|
inputContainerHeight,
|
|
6283
6358
|
isResizing,
|
|
6284
6359
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6285
|
-
|
|
6360
|
+
"data-testid": "copilot-scroll-content",
|
|
6361
|
+
style: { paddingBottom: `${inputContainerHeight + (hasSuggestions ? 4 : 32)}px` },
|
|
6286
6362
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6287
6363
|
className: "cpk:max-w-3xl cpk:mx-auto",
|
|
6288
6364
|
children: [BoundMessageView, hasSuggestions ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6292,7 +6368,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6292
6368
|
})
|
|
6293
6369
|
})
|
|
6294
6370
|
});
|
|
6295
|
-
if (messages.length === 0 && !(welcomeScreen === false)) {
|
|
6371
|
+
if (messages.length === 0 && !(welcomeScreen === false) && !isConnecting && !hasExplicitThreadId) {
|
|
6296
6372
|
const BoundInputForWelcome = renderSlot(input, CopilotChatInput_default, {
|
|
6297
6373
|
onSubmitMessage,
|
|
6298
6374
|
onStop,
|
|
@@ -6356,15 +6432,19 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6356
6432
|
children: [
|
|
6357
6433
|
dragOver && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DropOverlay, {}),
|
|
6358
6434
|
BoundScrollView,
|
|
6359
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
className: "cpk:
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6435
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6436
|
+
ref: inputContainerRef,
|
|
6437
|
+
"data-testid": "copilot-input-overlay",
|
|
6438
|
+
className: "cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-0 cpk:z-20 cpk:pointer-events-none",
|
|
6439
|
+
children: [attachments && attachments.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6440
|
+
className: "cpk:max-w-3xl cpk:mx-auto cpk:w-full cpk:pointer-events-auto",
|
|
6441
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatAttachmentQueue, {
|
|
6442
|
+
attachments,
|
|
6443
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
6444
|
+
className: "cpk:px-4"
|
|
6445
|
+
})
|
|
6446
|
+
}), BoundInput]
|
|
6447
|
+
})
|
|
6368
6448
|
]
|
|
6369
6449
|
});
|
|
6370
6450
|
}
|
|
@@ -6393,15 +6473,66 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6393
6473
|
BoundFeather,
|
|
6394
6474
|
!isAtBottom && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6395
6475
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6396
|
-
style: { bottom: `${inputContainerHeight +
|
|
6476
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6397
6477
|
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6398
6478
|
})
|
|
6399
6479
|
] })
|
|
6400
6480
|
});
|
|
6401
6481
|
};
|
|
6402
|
-
|
|
6482
|
+
const PinToSendScrollContainer = ({ children, scrollRef, contentRef, scrollToBottom, scrollToBottomButton, feather, inputContainerHeight, isResizing, nonAutoScrollEl, nonAutoScrollRefCallback, showScrollButton, className, ...props }) => {
|
|
6483
|
+
const spacerRef = (0, react.useRef)(null);
|
|
6484
|
+
usePinToSend({
|
|
6485
|
+
scrollRef,
|
|
6486
|
+
contentRef,
|
|
6487
|
+
spacerRef,
|
|
6488
|
+
topOffset: 16
|
|
6489
|
+
});
|
|
6490
|
+
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
6491
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6492
|
+
value: nonAutoScrollEl,
|
|
6493
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6494
|
+
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:relative", className),
|
|
6495
|
+
children: [
|
|
6496
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6497
|
+
ref: nonAutoScrollRefCallback,
|
|
6498
|
+
className: "cpk:flex-1 cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
6499
|
+
...props,
|
|
6500
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6501
|
+
ref: contentRef,
|
|
6502
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
6503
|
+
children
|
|
6504
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6505
|
+
ref: spacerRef,
|
|
6506
|
+
"data-pin-to-send-spacer": true,
|
|
6507
|
+
"aria-hidden": "true",
|
|
6508
|
+
style: {
|
|
6509
|
+
height: 0,
|
|
6510
|
+
flex: "0 0 auto"
|
|
6511
|
+
}
|
|
6512
|
+
})]
|
|
6513
|
+
}),
|
|
6514
|
+
BoundFeather,
|
|
6515
|
+
showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6516
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6517
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6518
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6519
|
+
})
|
|
6520
|
+
]
|
|
6521
|
+
})
|
|
6522
|
+
});
|
|
6523
|
+
};
|
|
6524
|
+
_CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
6525
|
+
const mode = normalizeAutoScroll(autoScroll);
|
|
6403
6526
|
const [hasMounted, setHasMounted] = (0, react.useState)(false);
|
|
6404
|
-
const
|
|
6527
|
+
const scrollRef = (0, react.useRef)(null);
|
|
6528
|
+
const contentRef = (0, react.useRef)(null);
|
|
6529
|
+
const scrollToBottom = (0, react.useCallback)(() => {
|
|
6530
|
+
const el = scrollRef.current;
|
|
6531
|
+
if (el) el.scrollTo({
|
|
6532
|
+
top: el.scrollHeight,
|
|
6533
|
+
behavior: "smooth"
|
|
6534
|
+
});
|
|
6535
|
+
}, []);
|
|
6405
6536
|
const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
|
|
6406
6537
|
const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
|
|
6407
6538
|
const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
|
|
@@ -6412,7 +6543,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6412
6543
|
setHasMounted(true);
|
|
6413
6544
|
}, []);
|
|
6414
6545
|
(0, react.useEffect)(() => {
|
|
6415
|
-
if (
|
|
6546
|
+
if (mode === "pin-to-bottom") return;
|
|
6416
6547
|
const scrollElement = scrollRef.current;
|
|
6417
6548
|
if (!scrollElement) return;
|
|
6418
6549
|
const checkScroll = () => {
|
|
@@ -6426,7 +6557,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6426
6557
|
scrollElement.removeEventListener("scroll", checkScroll);
|
|
6427
6558
|
resizeObserver.disconnect();
|
|
6428
6559
|
};
|
|
6429
|
-
}, [scrollRef,
|
|
6560
|
+
}, [scrollRef, mode]);
|
|
6430
6561
|
if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6431
6562
|
className: "cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
6432
6563
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6434,7 +6565,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6434
6565
|
children
|
|
6435
6566
|
})
|
|
6436
6567
|
});
|
|
6437
|
-
if (
|
|
6568
|
+
if (mode === "none") {
|
|
6438
6569
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
6439
6570
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6440
6571
|
value: nonAutoScrollEl,
|
|
@@ -6451,13 +6582,28 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6451
6582
|
BoundFeather,
|
|
6452
6583
|
showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6453
6584
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6454
|
-
style: { bottom: `${inputContainerHeight +
|
|
6585
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6455
6586
|
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6456
6587
|
})
|
|
6457
6588
|
]
|
|
6458
6589
|
})
|
|
6459
6590
|
});
|
|
6460
6591
|
}
|
|
6592
|
+
if (mode === "pin-to-send") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PinToSendScrollContainer, {
|
|
6593
|
+
scrollRef,
|
|
6594
|
+
contentRef,
|
|
6595
|
+
scrollToBottom,
|
|
6596
|
+
scrollToBottomButton,
|
|
6597
|
+
feather,
|
|
6598
|
+
inputContainerHeight,
|
|
6599
|
+
isResizing,
|
|
6600
|
+
nonAutoScrollEl,
|
|
6601
|
+
nonAutoScrollRefCallback,
|
|
6602
|
+
showScrollButton,
|
|
6603
|
+
className,
|
|
6604
|
+
...props,
|
|
6605
|
+
children
|
|
6606
|
+
});
|
|
6461
6607
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
|
|
6462
6608
|
className: cn("cpk:flex-1 cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0", className),
|
|
6463
6609
|
resize: "smooth",
|
|
@@ -6480,9 +6626,8 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6480
6626
|
...props,
|
|
6481
6627
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(lucide_react.ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
|
|
6482
6628
|
});
|
|
6483
|
-
_CopilotChatView.Feather = ({ className,
|
|
6484
|
-
className
|
|
6485
|
-
style,
|
|
6629
|
+
_CopilotChatView.Feather = ({ className, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6630
|
+
className,
|
|
6486
6631
|
...props
|
|
6487
6632
|
});
|
|
6488
6633
|
_CopilotChatView.WelcomeMessage = ({ className, ...props }) => {
|
|
@@ -6650,7 +6795,9 @@ async function transcribeAudio(core, audioBlob, filename = "recording.webm") {
|
|
|
6650
6795
|
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
|
|
6651
6796
|
const existingConfig = useCopilotChatConfiguration();
|
|
6652
6797
|
const resolvedAgentId = agentId ?? existingConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
6653
|
-
const
|
|
6798
|
+
const providedThreadId = threadId ?? existingConfig?.threadId;
|
|
6799
|
+
const resolvedThreadId = (0, react.useMemo)(() => providedThreadId ?? (0, _copilotkit_shared.randomUUID)(), [providedThreadId]);
|
|
6800
|
+
const hasExplicitThreadId = !!threadId || !!existingConfig?.hasExplicitThreadId;
|
|
6654
6801
|
const { agent } = useAgent({
|
|
6655
6802
|
agentId: resolvedAgentId,
|
|
6656
6803
|
threadId: resolvedThreadId,
|
|
@@ -6688,7 +6835,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6688
6835
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
6689
6836
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
6690
6837
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
6838
|
+
const [lastConnectedThreadId, setLastConnectedThreadId] = (0, react.useState)(null);
|
|
6839
|
+
const isConnecting = hasExplicitThreadId && lastConnectedThreadId !== resolvedThreadId;
|
|
6691
6840
|
(0, react.useEffect)(() => {
|
|
6841
|
+
if (!hasExplicitThreadId) return;
|
|
6692
6842
|
let detached = false;
|
|
6693
6843
|
const connectAbortController = new AbortController();
|
|
6694
6844
|
if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
|
|
@@ -6698,6 +6848,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6698
6848
|
} catch (error) {
|
|
6699
6849
|
if (detached) return;
|
|
6700
6850
|
console.error("CopilotChat: connectAgent failed", error);
|
|
6851
|
+
} finally {
|
|
6852
|
+
if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
|
|
6853
|
+
if (!detached) setLastConnectedThreadId(resolvedThreadId);
|
|
6854
|
+
});
|
|
6701
6855
|
}
|
|
6702
6856
|
};
|
|
6703
6857
|
connect(agent);
|
|
@@ -6709,7 +6863,8 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6709
6863
|
}, [
|
|
6710
6864
|
resolvedThreadId,
|
|
6711
6865
|
agent,
|
|
6712
|
-
resolvedAgentId
|
|
6866
|
+
resolvedAgentId,
|
|
6867
|
+
hasExplicitThreadId
|
|
6713
6868
|
]);
|
|
6714
6869
|
const onSubmitInput = (0, react.useCallback)(async (value) => {
|
|
6715
6870
|
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
@@ -6862,6 +7017,22 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6862
7017
|
const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => `${tc.id}:${tc.function?.arguments?.length ?? 0}`).join(";") : "";
|
|
6863
7018
|
return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
|
|
6864
7019
|
}).join(",")]);
|
|
7020
|
+
const lastUserMessageId = (0, react.useMemo)(() => {
|
|
7021
|
+
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "user") return messages[i].id;
|
|
7022
|
+
return null;
|
|
7023
|
+
}, [messages]);
|
|
7024
|
+
const [sendNonce, setSendNonce] = (0, react.useState)(0);
|
|
7025
|
+
const prevLastUserMessageIdRef = (0, react.useRef)(lastUserMessageId);
|
|
7026
|
+
(0, react.useEffect)(() => {
|
|
7027
|
+
if (lastUserMessageId && lastUserMessageId !== prevLastUserMessageIdRef.current) {
|
|
7028
|
+
setSendNonce((n) => n + 1);
|
|
7029
|
+
prevLastUserMessageIdRef.current = lastUserMessageId;
|
|
7030
|
+
}
|
|
7031
|
+
}, [lastUserMessageId]);
|
|
7032
|
+
const lastUserMessageState = (0, react.useMemo)(() => ({
|
|
7033
|
+
id: lastUserMessageId,
|
|
7034
|
+
sendNonce
|
|
7035
|
+
}), [lastUserMessageId, sendNonce]);
|
|
6865
7036
|
const RenderedChatView = renderSlot(chatView, CopilotChatView, {
|
|
6866
7037
|
...mergedProps,
|
|
6867
7038
|
messages,
|
|
@@ -6880,11 +7051,14 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6880
7051
|
dragOver,
|
|
6881
7052
|
onDragOver: handleDragOver,
|
|
6882
7053
|
onDragLeave: handleDragLeave,
|
|
6883
|
-
onDrop: handleDrop
|
|
7054
|
+
onDrop: handleDrop,
|
|
7055
|
+
isConnecting,
|
|
7056
|
+
hasExplicitThreadId
|
|
6884
7057
|
});
|
|
6885
7058
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
6886
7059
|
agentId: resolvedAgentId,
|
|
6887
7060
|
threadId: resolvedThreadId,
|
|
7061
|
+
hasExplicitThreadId,
|
|
6888
7062
|
labels,
|
|
6889
7063
|
isModalDefaultOpen,
|
|
6890
7064
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -6915,7 +7089,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6915
7089
|
},
|
|
6916
7090
|
children: transcriptionError
|
|
6917
7091
|
}),
|
|
6918
|
-
|
|
7092
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LastUserMessageContext.Provider, {
|
|
7093
|
+
value: lastUserMessageState,
|
|
7094
|
+
children: RenderedChatView
|
|
7095
|
+
})
|
|
6919
7096
|
]
|
|
6920
7097
|
})
|
|
6921
7098
|
});
|
|
@@ -8641,12 +8818,19 @@ function useCoAgentStateRenders() {
|
|
|
8641
8818
|
//#region src/context/threads-context.tsx
|
|
8642
8819
|
const ThreadsContext = (0, react.createContext)(void 0);
|
|
8643
8820
|
function ThreadsProvider({ children, threadId: explicitThreadId }) {
|
|
8644
|
-
const [internalThreadId,
|
|
8821
|
+
const [internalThreadId, setInternalThreadId] = (0, react.useState)(() => (0, _copilotkit_shared.randomUUID)());
|
|
8822
|
+
const [internalIsExplicit, setInternalIsExplicit] = (0, react.useState)(false);
|
|
8645
8823
|
const threadId = explicitThreadId ?? internalThreadId;
|
|
8824
|
+
const isThreadIdExplicit = explicitThreadId != null || internalIsExplicit;
|
|
8825
|
+
const setThreadId = (0, react.useCallback)((value) => {
|
|
8826
|
+
setInternalThreadId(value);
|
|
8827
|
+
setInternalIsExplicit(true);
|
|
8828
|
+
}, []);
|
|
8646
8829
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ThreadsContext.Provider, {
|
|
8647
8830
|
value: {
|
|
8648
8831
|
threadId,
|
|
8649
|
-
setThreadId
|
|
8832
|
+
setThreadId,
|
|
8833
|
+
isThreadIdExplicit
|
|
8650
8834
|
},
|
|
8651
8835
|
children
|
|
8652
8836
|
});
|
|
@@ -9348,7 +9532,7 @@ function CopilotKitInternal(cpkProps) {
|
|
|
9348
9532
|
if (props.agent) setAgentSession({ agentName: props.agent });
|
|
9349
9533
|
else setAgentSession(null);
|
|
9350
9534
|
}, [props.agent]);
|
|
9351
|
-
const { threadId, setThreadId: setInternalThreadId } = useThreads();
|
|
9535
|
+
const { threadId, setThreadId: setInternalThreadId, isThreadIdExplicit } = useThreads();
|
|
9352
9536
|
const setThreadId = (0, react.useCallback)((value) => {
|
|
9353
9537
|
if (props.threadId) throw new Error("Cannot call setThreadId() when threadId is provided via props.");
|
|
9354
9538
|
setInternalThreadId(value);
|
|
@@ -9548,6 +9732,7 @@ function CopilotKitInternal(cpkProps) {
|
|
|
9548
9732
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
9549
9733
|
agentId: props.agent ?? "default",
|
|
9550
9734
|
threadId,
|
|
9735
|
+
hasExplicitThreadId: isThreadIdExplicit,
|
|
9551
9736
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(CopilotContext.Provider, {
|
|
9552
9737
|
value: copilotContextValue,
|
|
9553
9738
|
children: [
|
|
@@ -10017,4 +10202,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
10017
10202
|
return useToast;
|
|
10018
10203
|
}
|
|
10019
10204
|
});
|
|
10020
|
-
//# sourceMappingURL=copilotkit-
|
|
10205
|
+
//# sourceMappingURL=copilotkit-tb4zqaMK.cjs.map
|