@copilotkit/react-core 1.56.2 → 1.56.4-canary.1777529757
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-CSJw5BG8.cjs → copilotkit-BAkj3zUc.cjs} +359 -157
- package/dist/copilotkit-BAkj3zUc.cjs.map +1 -0
- package/dist/{copilotkit-Cj2ZIxVr.mjs → copilotkit-DAatqMh2.mjs} +360 -158
- package/dist/copilotkit-DAatqMh2.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/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 +361 -163
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +8 -8
- 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 +7 -114
- package/src/v2/components/chat/CopilotChatAttachmentRenderer.tsx +26 -6
- package/src/v2/components/chat/CopilotChatInput.tsx +22 -0
- package/src/v2/components/chat/CopilotChatUserMessage.tsx +2 -2
- package/src/v2/components/chat/CopilotChatView.tsx +226 -48
- package/src/v2/components/chat/Lightbox.tsx +103 -0
- package/src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx +66 -0
- package/src/v2/components/chat/__tests__/CopilotChat.suggestionsAlways.test.tsx +189 -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 +264 -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
|
@@ -16,9 +16,9 @@ import { z } from "zod";
|
|
|
16
16
|
import { createComponent } from "@lit-labs/react";
|
|
17
17
|
import { A2UIProvider, A2UIRenderer, A2UI_SCHEMA_CONTEXT_DESCRIPTION, DEFAULT_SURFACE_ID, buildCatalogContextValue, extractCatalogComponentSchemas, initializeDefaultCatalog, injectStyles, useA2UIActions, useA2UIError, viewerTheme } from "@copilotkit/a2ui-renderer";
|
|
18
18
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
19
|
-
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
20
19
|
import { createPortal, flushSync } from "react-dom";
|
|
21
|
-
import {
|
|
20
|
+
import { useVirtualizer } from "@tanstack/react-virtual";
|
|
21
|
+
import { StickToBottom, useStickToBottomContext } from "use-stick-to-bottom";
|
|
22
22
|
import ReactMarkdown from "react-markdown";
|
|
23
23
|
|
|
24
24
|
//#region src/v2/lib/slots.tsx
|
|
@@ -145,7 +145,7 @@ const CopilotChatDefaultLabels = {
|
|
|
145
145
|
welcomeMessageText: "How can I help you today?"
|
|
146
146
|
};
|
|
147
147
|
const CopilotChatConfiguration = createContext(null);
|
|
148
|
-
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, isModalDefaultOpen }) => {
|
|
148
|
+
const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId, hasExplicitThreadId, isModalDefaultOpen }) => {
|
|
149
149
|
const parentConfig = useContext(CopilotChatConfiguration);
|
|
150
150
|
const stableLabels = useShallowStableRef(labels);
|
|
151
151
|
const mergedLabels = useMemo(() => ({
|
|
@@ -159,6 +159,7 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
159
159
|
if (parentConfig?.threadId) return parentConfig.threadId;
|
|
160
160
|
return randomUUID();
|
|
161
161
|
}, [threadId, parentConfig?.threadId]);
|
|
162
|
+
const resolvedHasExplicitThreadId = (hasExplicitThreadId !== void 0 ? hasExplicitThreadId : !!threadId) || !!parentConfig?.hasExplicitThreadId;
|
|
162
163
|
const [internalModalOpen, setInternalModalOpen] = useState(isModalDefaultOpen ?? true);
|
|
163
164
|
const hasExplicitDefault = isModalDefaultOpen !== void 0;
|
|
164
165
|
const setAndSync = useCallback((open) => {
|
|
@@ -181,12 +182,14 @@ const CopilotChatConfigurationProvider = ({ children, labels, agentId, threadId,
|
|
|
181
182
|
labels: mergedLabels,
|
|
182
183
|
agentId: resolvedAgentId,
|
|
183
184
|
threadId: resolvedThreadId,
|
|
185
|
+
hasExplicitThreadId: resolvedHasExplicitThreadId,
|
|
184
186
|
isModalOpen: resolvedIsModalOpen,
|
|
185
187
|
setModalOpen: resolvedSetModalOpen
|
|
186
188
|
}), [
|
|
187
189
|
mergedLabels,
|
|
188
190
|
resolvedAgentId,
|
|
189
191
|
resolvedThreadId,
|
|
192
|
+
resolvedHasExplicitThreadId,
|
|
190
193
|
resolvedIsModalOpen,
|
|
191
194
|
resolvedSetModalOpen
|
|
192
195
|
]);
|
|
@@ -580,7 +583,7 @@ CopilotChatAudioRecorder.displayName = "CopilotChatAudioRecorder";
|
|
|
580
583
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
581
584
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
582
585
|
const SLASH_MENU_ITEM_HEIGHT_PX = 40;
|
|
583
|
-
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 }) {
|
|
586
|
+
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 }) {
|
|
584
587
|
const isControlled = value !== void 0;
|
|
585
588
|
const [internalValue, setInternalValue] = useState(() => value ?? "");
|
|
586
589
|
useEffect(() => {
|
|
@@ -1104,7 +1107,8 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1104
1107
|
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),
|
|
1105
1108
|
style: {
|
|
1106
1109
|
transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
|
|
1107
|
-
transition: "transform 0.2s ease-out"
|
|
1110
|
+
transition: "transform 0.2s ease-out",
|
|
1111
|
+
...positioning === "absolute" || bottomAnchored ? { paddingBottom: "var(--copilotkit-license-banner-offset, 0px)" } : {}
|
|
1108
1112
|
},
|
|
1109
1113
|
...props,
|
|
1110
1114
|
children: [/* @__PURE__ */ jsx("div", {
|
|
@@ -1319,6 +1323,8 @@ CopilotKitInspector.displayName = "CopilotKitInspector";
|
|
|
1319
1323
|
|
|
1320
1324
|
//#endregion
|
|
1321
1325
|
//#region src/v2/components/license-warning-banner.tsx
|
|
1326
|
+
const LICENSE_BANNER_OFFSET_PX = 52;
|
|
1327
|
+
const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
|
|
1322
1328
|
const BANNER_STYLES = {
|
|
1323
1329
|
base: {
|
|
1324
1330
|
position: "fixed",
|
|
@@ -1360,6 +1366,14 @@ function getSeverityStyle(severity) {
|
|
|
1360
1366
|
}
|
|
1361
1367
|
}
|
|
1362
1368
|
function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
|
|
1369
|
+
useEffect(() => {
|
|
1370
|
+
if (typeof document === "undefined") return;
|
|
1371
|
+
const root = document.documentElement;
|
|
1372
|
+
root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
|
|
1373
|
+
return () => {
|
|
1374
|
+
root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
|
|
1375
|
+
};
|
|
1376
|
+
}, []);
|
|
1363
1377
|
return /* @__PURE__ */ jsxs("div", {
|
|
1364
1378
|
style: {
|
|
1365
1379
|
...BANNER_STYLES.base,
|
|
@@ -3312,7 +3326,6 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
|
|
|
3312
3326
|
didMountRef.current = true;
|
|
3313
3327
|
}, []);
|
|
3314
3328
|
useEffect(() => {
|
|
3315
|
-
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.`);
|
|
3316
3329
|
copilotkit.setDefaultThrottleMs(defaultThrottleMs);
|
|
3317
3330
|
}, [copilotkit, defaultThrottleMs]);
|
|
3318
3331
|
const designSkill = openGenerativeUI?.designSkill ?? DEFAULT_DESIGN_SKILL;
|
|
@@ -3529,15 +3542,6 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3529
3542
|
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
3530
3543
|
const chatConfig = useCopilotChatConfiguration();
|
|
3531
3544
|
threadId ??= chatConfig?.threadId;
|
|
3532
|
-
const effectiveThrottleMs = useMemo(() => {
|
|
3533
|
-
const resolved = throttleMs ?? providerThrottleMs ?? 0;
|
|
3534
|
-
if (!Number.isFinite(resolved) || resolved < 0) {
|
|
3535
|
-
const source = throttleMs !== void 0 ? "hook-level throttleMs" : "provider-level defaultThrottleMs";
|
|
3536
|
-
console.error(`useAgent: ${source} must be a non-negative finite number, got ${resolved}. Falling back to unthrottled.`);
|
|
3537
|
-
return 0;
|
|
3538
|
-
}
|
|
3539
|
-
return resolved;
|
|
3540
|
-
}, [throttleMs, providerThrottleMs]);
|
|
3541
3545
|
const [, forceUpdate] = useReducer((x) => x + 1, 0);
|
|
3542
3546
|
const updateFlags = useMemo(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
3543
3547
|
const provisionalAgentCache = useRef(/* @__PURE__ */ new Map());
|
|
@@ -3600,9 +3604,8 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3600
3604
|
]);
|
|
3601
3605
|
useEffect(() => {
|
|
3602
3606
|
if (updateFlags.length === 0) return;
|
|
3603
|
-
const handlers = {};
|
|
3604
|
-
let timerId = null;
|
|
3605
3607
|
let active = true;
|
|
3608
|
+
const handlers = {};
|
|
3606
3609
|
let batchScheduled = false;
|
|
3607
3610
|
const batchedForceUpdate = () => {
|
|
3608
3611
|
if (!active) return;
|
|
@@ -3614,46 +3617,24 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3614
3617
|
});
|
|
3615
3618
|
}
|
|
3616
3619
|
};
|
|
3617
|
-
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged))
|
|
3618
|
-
const ms = effectiveThrottleMs;
|
|
3619
|
-
if (ms > 0) {
|
|
3620
|
-
let throttleActive = false;
|
|
3621
|
-
let pending = false;
|
|
3622
|
-
const throttledNotify = () => {
|
|
3623
|
-
if (!active) return;
|
|
3624
|
-
if (!throttleActive) {
|
|
3625
|
-
throttleActive = true;
|
|
3626
|
-
pending = false;
|
|
3627
|
-
forceUpdate();
|
|
3628
|
-
timerId = setTimeout(function trailingEdge() {
|
|
3629
|
-
timerId = null;
|
|
3630
|
-
if (active && pending) {
|
|
3631
|
-
pending = false;
|
|
3632
|
-
forceUpdate();
|
|
3633
|
-
timerId = setTimeout(trailingEdge, ms);
|
|
3634
|
-
} else throttleActive = false;
|
|
3635
|
-
}, ms);
|
|
3636
|
-
} else pending = true;
|
|
3637
|
-
};
|
|
3638
|
-
handlers.onMessagesChanged = throttledNotify;
|
|
3639
|
-
} else handlers.onMessagesChanged = forceUpdate;
|
|
3640
|
-
}
|
|
3620
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
|
|
3641
3621
|
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
3642
3622
|
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
3643
3623
|
handlers.onRunInitialized = batchedForceUpdate;
|
|
3644
3624
|
handlers.onRunFinalized = batchedForceUpdate;
|
|
3645
3625
|
handlers.onRunFailed = batchedForceUpdate;
|
|
3626
|
+
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
3646
3627
|
}
|
|
3647
|
-
const subscription =
|
|
3628
|
+
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
3648
3629
|
return () => {
|
|
3649
3630
|
active = false;
|
|
3650
|
-
if (timerId !== null) clearTimeout(timerId);
|
|
3651
3631
|
subscription.unsubscribe();
|
|
3652
3632
|
};
|
|
3653
3633
|
}, [
|
|
3654
3634
|
agent,
|
|
3655
3635
|
forceUpdate,
|
|
3656
|
-
|
|
3636
|
+
throttleMs,
|
|
3637
|
+
providerThrottleMs,
|
|
3657
3638
|
updateFlags
|
|
3658
3639
|
]);
|
|
3659
3640
|
useEffect(() => {
|
|
@@ -4607,13 +4588,14 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4607
4588
|
const { copilotkit } = useCopilotKit();
|
|
4608
4589
|
const [store] = useState(() => ɵcreateThreadStore({ fetch: globalThis.fetch }));
|
|
4609
4590
|
const coreThreads = useThreadStoreSelector(store, ɵselectThreads);
|
|
4610
|
-
const threads = useMemo(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
|
|
4591
|
+
const threads = useMemo(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
|
|
4611
4592
|
id,
|
|
4612
4593
|
agentId,
|
|
4613
4594
|
name,
|
|
4614
4595
|
archived,
|
|
4615
4596
|
createdAt,
|
|
4616
|
-
updatedAt
|
|
4597
|
+
updatedAt,
|
|
4598
|
+
...lastRunAt !== void 0 ? { lastRunAt } : {}
|
|
4617
4599
|
})), [coreThreads]);
|
|
4618
4600
|
const storeIsLoading = useThreadStoreSelector(store, ɵselectThreadsIsLoading);
|
|
4619
4601
|
const storeError = useThreadStoreSelector(store, ɵselectThreadsError);
|
|
@@ -4626,7 +4608,9 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4626
4608
|
if (copilotkit.runtimeUrl) return null;
|
|
4627
4609
|
return /* @__PURE__ */ new Error("Runtime URL is not configured");
|
|
4628
4610
|
}, [copilotkit.runtimeUrl]);
|
|
4629
|
-
const
|
|
4611
|
+
const [hasDispatchedContext, setHasDispatchedContext] = useState(false);
|
|
4612
|
+
const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
|
|
4613
|
+
const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
|
|
4630
4614
|
const error = runtimeError ?? storeError;
|
|
4631
4615
|
useEffect(() => {
|
|
4632
4616
|
store.start();
|
|
@@ -4634,19 +4618,27 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4634
4618
|
store.stop();
|
|
4635
4619
|
};
|
|
4636
4620
|
}, [store]);
|
|
4621
|
+
const runtimeStatus = copilotkit.runtimeConnectionStatus;
|
|
4637
4622
|
useEffect(() => {
|
|
4638
|
-
|
|
4623
|
+
if (!copilotkit.runtimeUrl) {
|
|
4624
|
+
store.setContext(null);
|
|
4625
|
+
return;
|
|
4626
|
+
}
|
|
4627
|
+
if (runtimeStatus !== CopilotKitCoreRuntimeConnectionStatus.Connected) return;
|
|
4628
|
+
const context = {
|
|
4639
4629
|
runtimeUrl: copilotkit.runtimeUrl,
|
|
4640
4630
|
headers: { ...copilotkit.headers },
|
|
4641
4631
|
wsUrl: copilotkit.intelligence?.wsUrl,
|
|
4642
4632
|
agentId,
|
|
4643
4633
|
includeArchived,
|
|
4644
4634
|
limit
|
|
4645
|
-
}
|
|
4635
|
+
};
|
|
4646
4636
|
store.setContext(context);
|
|
4637
|
+
setHasDispatchedContext(true);
|
|
4647
4638
|
}, [
|
|
4648
4639
|
store,
|
|
4649
4640
|
copilotkit.runtimeUrl,
|
|
4641
|
+
runtimeStatus,
|
|
4650
4642
|
headersKey,
|
|
4651
4643
|
copilotkit.intelligence?.wsUrl,
|
|
4652
4644
|
agentId,
|
|
@@ -5014,20 +5006,101 @@ CopilotChatAssistantMessage.ReadAloudButton.displayName = "CopilotChatAssistantM
|
|
|
5014
5006
|
CopilotChatAssistantMessage.RegenerateButton.displayName = "CopilotChatAssistantMessage.RegenerateButton";
|
|
5015
5007
|
var CopilotChatAssistantMessage_default = CopilotChatAssistantMessage;
|
|
5016
5008
|
|
|
5009
|
+
//#endregion
|
|
5010
|
+
//#region src/v2/components/chat/Lightbox.tsx
|
|
5011
|
+
function Lightbox({ onClose, children }) {
|
|
5012
|
+
useEffect(() => {
|
|
5013
|
+
const handleKey = (e) => {
|
|
5014
|
+
if (e.key === "Escape") onClose();
|
|
5015
|
+
};
|
|
5016
|
+
document.addEventListener("keydown", handleKey);
|
|
5017
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
5018
|
+
}, [onClose]);
|
|
5019
|
+
if (typeof document === "undefined") return null;
|
|
5020
|
+
return createPortal(/* @__PURE__ */ jsxs("div", {
|
|
5021
|
+
className: "cpk:fixed cpk:inset-0 cpk:z-[9999] cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/80 cpk:animate-fade-in",
|
|
5022
|
+
onClick: onClose,
|
|
5023
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
5024
|
+
onClick: onClose,
|
|
5025
|
+
className: "cpk:absolute cpk:top-4 cpk:right-4 cpk:text-white cpk:bg-white/10 cpk:hover:bg-white/20 cpk:rounded-full cpk:w-10 cpk:h-10 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:border-none cpk:z-10",
|
|
5026
|
+
"aria-label": "Close preview",
|
|
5027
|
+
children: /* @__PURE__ */ jsx(X, { className: "cpk:w-5 cpk:h-5" })
|
|
5028
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
5029
|
+
onClick: (e) => e.stopPropagation(),
|
|
5030
|
+
children
|
|
5031
|
+
})]
|
|
5032
|
+
}), document.body);
|
|
5033
|
+
}
|
|
5034
|
+
/**
|
|
5035
|
+
* Hook that manages lightbox open/close and uses the View Transition API to
|
|
5036
|
+
* morph the thumbnail into fullscreen content.
|
|
5037
|
+
*
|
|
5038
|
+
* The trick: `view-transition-name` must live on exactly ONE element at a time.
|
|
5039
|
+
* - Old state (thumbnail visible): name is on the thumbnail.
|
|
5040
|
+
* - New state (lightbox visible): name moves to the lightbox content.
|
|
5041
|
+
* `flushSync` ensures React commits the DOM change synchronously inside the
|
|
5042
|
+
* `startViewTransition` callback so the API can snapshot old → new correctly.
|
|
5043
|
+
*/
|
|
5044
|
+
function useLightbox() {
|
|
5045
|
+
const thumbnailRef = useRef(null);
|
|
5046
|
+
const [open, setOpen] = useState(false);
|
|
5047
|
+
const vtName = useId();
|
|
5048
|
+
return {
|
|
5049
|
+
thumbnailRef,
|
|
5050
|
+
vtName,
|
|
5051
|
+
open,
|
|
5052
|
+
openLightbox: useCallback(() => {
|
|
5053
|
+
const thumb = thumbnailRef.current;
|
|
5054
|
+
const doc = document;
|
|
5055
|
+
if (doc.startViewTransition && thumb) {
|
|
5056
|
+
thumb.style.viewTransitionName = vtName;
|
|
5057
|
+
doc.startViewTransition(() => {
|
|
5058
|
+
thumb.style.viewTransitionName = "";
|
|
5059
|
+
flushSync(() => setOpen(true));
|
|
5060
|
+
});
|
|
5061
|
+
} else setOpen(true);
|
|
5062
|
+
}, [vtName]),
|
|
5063
|
+
closeLightbox: useCallback(() => {
|
|
5064
|
+
const thumb = thumbnailRef.current;
|
|
5065
|
+
const doc = document;
|
|
5066
|
+
if (doc.startViewTransition && thumb) doc.startViewTransition(() => {
|
|
5067
|
+
flushSync(() => setOpen(false));
|
|
5068
|
+
thumb.style.viewTransitionName = vtName;
|
|
5069
|
+
}).finished.then(() => {
|
|
5070
|
+
thumb.style.viewTransitionName = "";
|
|
5071
|
+
}).catch(() => {
|
|
5072
|
+
thumb.style.viewTransitionName = "";
|
|
5073
|
+
});
|
|
5074
|
+
else setOpen(false);
|
|
5075
|
+
}, [vtName])
|
|
5076
|
+
};
|
|
5077
|
+
}
|
|
5078
|
+
|
|
5017
5079
|
//#endregion
|
|
5018
5080
|
//#region src/v2/components/chat/CopilotChatAttachmentRenderer.tsx
|
|
5019
5081
|
const ImageAttachment = memo(function ImageAttachment({ src, className }) {
|
|
5020
5082
|
const [error, setError] = useState(false);
|
|
5083
|
+
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
5021
5084
|
if (error) return /* @__PURE__ */ jsx("div", {
|
|
5022
5085
|
className: cn("cpk:flex cpk:flex-col cpk:items-center cpk:justify-center cpk:rounded-lg cpk:bg-muted cpk:p-4 cpk:text-sm cpk:text-muted-foreground", className),
|
|
5023
5086
|
children: /* @__PURE__ */ jsx("span", { children: "Failed to load image" })
|
|
5024
5087
|
});
|
|
5025
|
-
return /* @__PURE__ */ jsx("img", {
|
|
5088
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("img", {
|
|
5089
|
+
ref: thumbnailRef,
|
|
5026
5090
|
src,
|
|
5027
5091
|
alt: "Image attachment",
|
|
5028
|
-
className: cn("cpk:max-w-
|
|
5092
|
+
className: cn("cpk:max-w-[80px] cpk:max-h-[80px] cpk:w-auto cpk:h-auto cpk:rounded-xl cpk:object-cover cpk:cursor-pointer cpk:bg-muted", className),
|
|
5093
|
+
onClick: openLightbox,
|
|
5029
5094
|
onError: () => setError(true)
|
|
5030
|
-
})
|
|
5095
|
+
}), open && /* @__PURE__ */ jsx(Lightbox, {
|
|
5096
|
+
onClose: closeLightbox,
|
|
5097
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
5098
|
+
style: { viewTransitionName: vtName },
|
|
5099
|
+
src,
|
|
5100
|
+
alt: "Image attachment",
|
|
5101
|
+
className: "cpk:max-w-[90vw] cpk:max-h-[90vh] cpk:object-contain cpk:rounded-lg"
|
|
5102
|
+
})
|
|
5103
|
+
})] });
|
|
5031
5104
|
});
|
|
5032
5105
|
const AudioAttachment = memo(function AudioAttachment({ src, filename, className }) {
|
|
5033
5106
|
return /* @__PURE__ */ jsxs("div", {
|
|
@@ -5152,15 +5225,15 @@ function CopilotChatUserMessage({ message, onEditMessage, branchIndex, numberOfB
|
|
|
5152
5225
|
"data-message-id": message.id,
|
|
5153
5226
|
...props,
|
|
5154
5227
|
children: [
|
|
5155
|
-
BoundMessageRenderer,
|
|
5156
5228
|
mediaParts.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
5157
|
-
className: "cpk:flex cpk:flex-
|
|
5229
|
+
className: "cpk:flex cpk:flex-row cpk:flex-wrap cpk:justify-end cpk:gap-2 cpk:mb-2",
|
|
5158
5230
|
children: mediaParts.map((part, index) => /* @__PURE__ */ jsx(CopilotChatAttachmentRenderer, {
|
|
5159
5231
|
type: part.type,
|
|
5160
5232
|
source: part.source,
|
|
5161
5233
|
filename: getFilename(part)
|
|
5162
5234
|
}, index))
|
|
5163
5235
|
}),
|
|
5236
|
+
BoundMessageRenderer,
|
|
5164
5237
|
BoundToolbar
|
|
5165
5238
|
]
|
|
5166
5239
|
});
|
|
@@ -5829,6 +5902,7 @@ CopilotChatMessageView.Cursor = function Cursor({ className, ...props }) {
|
|
|
5829
5902
|
const CopilotChatAttachmentQueue = ({ attachments, onRemoveAttachment, className }) => {
|
|
5830
5903
|
if (attachments.length === 0) return null;
|
|
5831
5904
|
return /* @__PURE__ */ jsx("div", {
|
|
5905
|
+
"data-testid": "copilot-attachment-queue",
|
|
5832
5906
|
className: cn("cpk:flex cpk:flex-wrap cpk:gap-2 cpk:p-2", className),
|
|
5833
5907
|
children: attachments.map((attachment) => {
|
|
5834
5908
|
const isMedia = attachment.type === "image" || attachment.type === "video";
|
|
@@ -5863,73 +5937,6 @@ function AttachmentPreview({ attachment }) {
|
|
|
5863
5937
|
case "document": return /* @__PURE__ */ jsx(DocumentPreview, { attachment });
|
|
5864
5938
|
}
|
|
5865
5939
|
}
|
|
5866
|
-
function Lightbox({ onClose, children }) {
|
|
5867
|
-
useEffect(() => {
|
|
5868
|
-
const handleKey = (e) => {
|
|
5869
|
-
if (e.key === "Escape") onClose();
|
|
5870
|
-
};
|
|
5871
|
-
document.addEventListener("keydown", handleKey);
|
|
5872
|
-
return () => document.removeEventListener("keydown", handleKey);
|
|
5873
|
-
}, [onClose]);
|
|
5874
|
-
if (typeof document === "undefined") return null;
|
|
5875
|
-
return createPortal(/* @__PURE__ */ jsxs("div", {
|
|
5876
|
-
className: "cpk:fixed cpk:inset-0 cpk:z-[9999] cpk:flex cpk:items-center cpk:justify-center cpk:bg-black/80 cpk:animate-fade-in",
|
|
5877
|
-
onClick: onClose,
|
|
5878
|
-
children: [/* @__PURE__ */ jsx("button", {
|
|
5879
|
-
onClick: onClose,
|
|
5880
|
-
className: "cpk:absolute cpk:top-4 cpk:right-4 cpk:text-white cpk:bg-white/10 cpk:hover:bg-white/20 cpk:rounded-full cpk:w-10 cpk:h-10 cpk:flex cpk:items-center cpk:justify-center cpk:cursor-pointer cpk:border-none cpk:z-10",
|
|
5881
|
-
"aria-label": "Close preview",
|
|
5882
|
-
children: /* @__PURE__ */ jsx(X, { className: "cpk:w-5 cpk:h-5" })
|
|
5883
|
-
}), /* @__PURE__ */ jsx("div", {
|
|
5884
|
-
onClick: (e) => e.stopPropagation(),
|
|
5885
|
-
children
|
|
5886
|
-
})]
|
|
5887
|
-
}), document.body);
|
|
5888
|
-
}
|
|
5889
|
-
/**
|
|
5890
|
-
* Hook that manages lightbox open/close and uses the View Transition API to
|
|
5891
|
-
* morph the thumbnail into fullscreen content.
|
|
5892
|
-
*
|
|
5893
|
-
* The trick: `view-transition-name` must live on exactly ONE element at a time.
|
|
5894
|
-
* - Old state (thumbnail visible): name is on the thumbnail.
|
|
5895
|
-
* - New state (lightbox visible): name moves to the lightbox content.
|
|
5896
|
-
* `flushSync` ensures React commits the DOM change synchronously inside the
|
|
5897
|
-
* `startViewTransition` callback so the API can snapshot old → new correctly.
|
|
5898
|
-
*/
|
|
5899
|
-
function useLightbox() {
|
|
5900
|
-
const thumbnailRef = useRef(null);
|
|
5901
|
-
const [open, setOpen] = useState(false);
|
|
5902
|
-
const vtName = useId();
|
|
5903
|
-
return {
|
|
5904
|
-
thumbnailRef,
|
|
5905
|
-
vtName,
|
|
5906
|
-
open,
|
|
5907
|
-
openLightbox: useCallback(() => {
|
|
5908
|
-
const thumb = thumbnailRef.current;
|
|
5909
|
-
const doc = document;
|
|
5910
|
-
if (doc.startViewTransition && thumb) {
|
|
5911
|
-
thumb.style.viewTransitionName = vtName;
|
|
5912
|
-
doc.startViewTransition(() => {
|
|
5913
|
-
thumb.style.viewTransitionName = "";
|
|
5914
|
-
flushSync(() => setOpen(true));
|
|
5915
|
-
});
|
|
5916
|
-
} else setOpen(true);
|
|
5917
|
-
}, []),
|
|
5918
|
-
closeLightbox: useCallback(() => {
|
|
5919
|
-
const thumb = thumbnailRef.current;
|
|
5920
|
-
const doc = document;
|
|
5921
|
-
if (doc.startViewTransition && thumb) doc.startViewTransition(() => {
|
|
5922
|
-
flushSync(() => setOpen(false));
|
|
5923
|
-
thumb.style.viewTransitionName = vtName;
|
|
5924
|
-
}).finished.then(() => {
|
|
5925
|
-
thumb.style.viewTransitionName = "";
|
|
5926
|
-
}).catch(() => {
|
|
5927
|
-
thumb.style.viewTransitionName = "";
|
|
5928
|
-
});
|
|
5929
|
-
else setOpen(false);
|
|
5930
|
-
}, [])
|
|
5931
|
-
};
|
|
5932
|
-
}
|
|
5933
5940
|
function ImagePreview({ attachment }) {
|
|
5934
5941
|
const src = getSourceUrl(attachment.source);
|
|
5935
5942
|
const { thumbnailRef, vtName, open, openLightbox, closeLightbox } = useLightbox();
|
|
@@ -6171,9 +6178,91 @@ function useKeyboardHeight() {
|
|
|
6171
6178
|
return keyboardState;
|
|
6172
6179
|
}
|
|
6173
6180
|
|
|
6181
|
+
//#endregion
|
|
6182
|
+
//#region src/v2/components/chat/normalize-auto-scroll.ts
|
|
6183
|
+
const VALID = [
|
|
6184
|
+
"pin-to-bottom",
|
|
6185
|
+
"pin-to-send",
|
|
6186
|
+
"none"
|
|
6187
|
+
];
|
|
6188
|
+
function normalizeAutoScroll(value) {
|
|
6189
|
+
if (value === void 0) return "pin-to-bottom";
|
|
6190
|
+
if (value === true) return "pin-to-bottom";
|
|
6191
|
+
if (value === false) return "none";
|
|
6192
|
+
if (VALID.includes(value)) return value;
|
|
6193
|
+
return "pin-to-bottom";
|
|
6194
|
+
}
|
|
6195
|
+
|
|
6196
|
+
//#endregion
|
|
6197
|
+
//#region src/v2/components/chat/last-user-message-context.ts
|
|
6198
|
+
const LastUserMessageContext = React.createContext({
|
|
6199
|
+
id: null,
|
|
6200
|
+
sendNonce: 0
|
|
6201
|
+
});
|
|
6202
|
+
|
|
6203
|
+
//#endregion
|
|
6204
|
+
//#region src/v2/hooks/use-pin-to-send.ts
|
|
6205
|
+
function usePinToSend({ scrollRef, contentRef, spacerRef, topOffset = 16 }) {
|
|
6206
|
+
const { id, sendNonce } = useContext(LastUserMessageContext);
|
|
6207
|
+
const lastNonceRef = useRef(-1);
|
|
6208
|
+
const currentSpacerHeightRef = useRef(0);
|
|
6209
|
+
useEffect(() => {
|
|
6210
|
+
if (sendNonce === lastNonceRef.current) return;
|
|
6211
|
+
lastNonceRef.current = sendNonce;
|
|
6212
|
+
if (!id) return;
|
|
6213
|
+
const scrollEl = scrollRef.current;
|
|
6214
|
+
const contentEl = contentRef.current;
|
|
6215
|
+
const spacerEl = spacerRef.current;
|
|
6216
|
+
if (!scrollEl || !contentEl || !spacerEl) return;
|
|
6217
|
+
const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(id) : id.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
|
6218
|
+
const targetEl = contentEl.querySelector(`[data-message-id="${escaped}"]`);
|
|
6219
|
+
if (!targetEl) return;
|
|
6220
|
+
const viewportHeight = scrollEl.clientHeight;
|
|
6221
|
+
const userMessageHeight = targetEl.getBoundingClientRect().height;
|
|
6222
|
+
const paddingTop = parseFloat(getComputedStyle(targetEl).paddingTop) || 0;
|
|
6223
|
+
const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
|
|
6224
|
+
const spacerHeight = Math.max(0, viewportHeight - bubbleHeight - topOffset);
|
|
6225
|
+
spacerEl.style.height = `${spacerHeight}px`;
|
|
6226
|
+
currentSpacerHeightRef.current = spacerHeight;
|
|
6227
|
+
const raf = requestAnimationFrame(() => {
|
|
6228
|
+
const targetTop = computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
|
|
6229
|
+
scrollEl.scrollTo({
|
|
6230
|
+
top: Math.max(0, targetTop),
|
|
6231
|
+
behavior: "smooth"
|
|
6232
|
+
});
|
|
6233
|
+
});
|
|
6234
|
+
const ro = new ResizeObserver(() => {
|
|
6235
|
+
if (!contentEl || !spacerEl || !scrollEl) return;
|
|
6236
|
+
const consumedBelow = contentEl.getBoundingClientRect().height - computeOffsetTop(targetEl, contentEl) - userMessageHeight;
|
|
6237
|
+
const remaining = Math.max(0, spacerHeight - consumedBelow);
|
|
6238
|
+
if (remaining < currentSpacerHeightRef.current) {
|
|
6239
|
+
spacerEl.style.height = `${remaining}px`;
|
|
6240
|
+
currentSpacerHeightRef.current = remaining;
|
|
6241
|
+
}
|
|
6242
|
+
});
|
|
6243
|
+
ro.observe(contentEl);
|
|
6244
|
+
return () => {
|
|
6245
|
+
cancelAnimationFrame(raf);
|
|
6246
|
+
ro.disconnect();
|
|
6247
|
+
};
|
|
6248
|
+
}, [
|
|
6249
|
+
id,
|
|
6250
|
+
sendNonce,
|
|
6251
|
+
scrollRef,
|
|
6252
|
+
contentRef,
|
|
6253
|
+
spacerRef,
|
|
6254
|
+
topOffset
|
|
6255
|
+
]);
|
|
6256
|
+
}
|
|
6257
|
+
function computeOffsetTop(el, stopAt) {
|
|
6258
|
+
const elRect = el.getBoundingClientRect();
|
|
6259
|
+
const stopRect = stopAt.getBoundingClientRect();
|
|
6260
|
+
return elRect.top - stopRect.top + stopAt.scrollTop;
|
|
6261
|
+
}
|
|
6262
|
+
|
|
6174
6263
|
//#endregion
|
|
6175
6264
|
//#region src/v2/components/chat/CopilotChatView.tsx
|
|
6176
|
-
const
|
|
6265
|
+
const SCROLL_BUTTON_OFFSET = 16;
|
|
6177
6266
|
function DropOverlay() {
|
|
6178
6267
|
return /* @__PURE__ */ jsx("div", {
|
|
6179
6268
|
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"),
|
|
@@ -6186,15 +6275,18 @@ function DropOverlay() {
|
|
|
6186
6275
|
})
|
|
6187
6276
|
});
|
|
6188
6277
|
}
|
|
6189
|
-
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 }) {
|
|
6190
|
-
const
|
|
6278
|
+
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 }) {
|
|
6279
|
+
const [inputContainerEl, setInputContainerEl] = useState(null);
|
|
6191
6280
|
const [inputContainerHeight, setInputContainerHeight] = useState(0);
|
|
6192
6281
|
const [isResizing, setIsResizing] = useState(false);
|
|
6193
6282
|
const resizeTimeoutRef = useRef(null);
|
|
6194
6283
|
const { isKeyboardOpen, keyboardHeight, availableHeight } = useKeyboardHeight();
|
|
6195
6284
|
useEffect(() => {
|
|
6196
|
-
const element =
|
|
6197
|
-
if (!element)
|
|
6285
|
+
const element = inputContainerEl;
|
|
6286
|
+
if (!element) {
|
|
6287
|
+
setInputContainerHeight(0);
|
|
6288
|
+
return;
|
|
6289
|
+
}
|
|
6198
6290
|
const resizeObserver = new ResizeObserver((entries) => {
|
|
6199
6291
|
for (const entry of entries) {
|
|
6200
6292
|
const newHeight = entry.contentRect.height;
|
|
@@ -6217,7 +6309,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6217
6309
|
resizeObserver.disconnect();
|
|
6218
6310
|
if (resizeTimeoutRef.current) clearTimeout(resizeTimeoutRef.current);
|
|
6219
6311
|
};
|
|
6220
|
-
}, []);
|
|
6312
|
+
}, [inputContainerEl]);
|
|
6221
6313
|
const BoundMessageView = renderSlot(messageView, CopilotChatMessageView, {
|
|
6222
6314
|
messages,
|
|
6223
6315
|
isRunning
|
|
@@ -6236,11 +6328,11 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6236
6328
|
onAddFile,
|
|
6237
6329
|
positioning: "static",
|
|
6238
6330
|
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
|
|
6239
|
-
containerRef: inputContainerRef,
|
|
6240
6331
|
showDisclaimer: true,
|
|
6332
|
+
bottomAnchored: true,
|
|
6241
6333
|
...disclaimer !== void 0 ? { disclaimer } : {}
|
|
6242
6334
|
});
|
|
6243
|
-
const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
|
|
6335
|
+
const hasSuggestions = !isConnecting && Array.isArray(suggestions) && suggestions.length > 0;
|
|
6244
6336
|
const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView, {
|
|
6245
6337
|
suggestions,
|
|
6246
6338
|
loadingIndexes: suggestionLoadingIndexes,
|
|
@@ -6252,7 +6344,8 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6252
6344
|
inputContainerHeight,
|
|
6253
6345
|
isResizing,
|
|
6254
6346
|
children: /* @__PURE__ */ jsx("div", {
|
|
6255
|
-
|
|
6347
|
+
"data-testid": "copilot-scroll-content",
|
|
6348
|
+
style: { paddingBottom: `${inputContainerHeight + (hasSuggestions ? 4 : 32)}px` },
|
|
6256
6349
|
children: /* @__PURE__ */ jsxs("div", {
|
|
6257
6350
|
className: "cpk:max-w-3xl cpk:mx-auto",
|
|
6258
6351
|
children: [BoundMessageView, hasSuggestions ? /* @__PURE__ */ jsx("div", {
|
|
@@ -6262,7 +6355,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6262
6355
|
})
|
|
6263
6356
|
})
|
|
6264
6357
|
});
|
|
6265
|
-
if (messages.length === 0 && !(welcomeScreen === false)) {
|
|
6358
|
+
if (messages.length === 0 && !(welcomeScreen === false) && !isConnecting && !hasExplicitThreadId) {
|
|
6266
6359
|
const BoundInputForWelcome = renderSlot(input, CopilotChatInput_default, {
|
|
6267
6360
|
onSubmitMessage,
|
|
6268
6361
|
onStop,
|
|
@@ -6326,15 +6419,19 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6326
6419
|
children: [
|
|
6327
6420
|
dragOver && /* @__PURE__ */ jsx(DropOverlay, {}),
|
|
6328
6421
|
BoundScrollView,
|
|
6329
|
-
/* @__PURE__ */
|
|
6330
|
-
|
|
6331
|
-
|
|
6332
|
-
|
|
6333
|
-
|
|
6334
|
-
className: "cpk:
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6422
|
+
/* @__PURE__ */ jsxs("div", {
|
|
6423
|
+
ref: setInputContainerEl,
|
|
6424
|
+
"data-testid": "copilot-input-overlay",
|
|
6425
|
+
className: "cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-0 cpk:z-20 cpk:pointer-events-none",
|
|
6426
|
+
children: [attachments && attachments.length > 0 && /* @__PURE__ */ jsx("div", {
|
|
6427
|
+
className: "cpk:max-w-3xl cpk:mx-auto cpk:w-full cpk:pointer-events-auto",
|
|
6428
|
+
children: /* @__PURE__ */ jsx(CopilotChatAttachmentQueue, {
|
|
6429
|
+
attachments,
|
|
6430
|
+
onRemoveAttachment: (id) => onRemoveAttachment?.(id),
|
|
6431
|
+
className: "cpk:px-4"
|
|
6432
|
+
})
|
|
6433
|
+
}), BoundInput]
|
|
6434
|
+
})
|
|
6338
6435
|
]
|
|
6339
6436
|
});
|
|
6340
6437
|
}
|
|
@@ -6363,15 +6460,66 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6363
6460
|
BoundFeather,
|
|
6364
6461
|
!isAtBottom && !isResizing && /* @__PURE__ */ jsx("div", {
|
|
6365
6462
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6366
|
-
style: { bottom: `${inputContainerHeight +
|
|
6463
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6367
6464
|
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6368
6465
|
})
|
|
6369
6466
|
] })
|
|
6370
6467
|
});
|
|
6371
6468
|
};
|
|
6372
|
-
|
|
6469
|
+
const PinToSendScrollContainer = ({ children, scrollRef, contentRef, scrollToBottom, scrollToBottomButton, feather, inputContainerHeight, isResizing, nonAutoScrollEl, nonAutoScrollRefCallback, showScrollButton, className, ...props }) => {
|
|
6470
|
+
const spacerRef = useRef(null);
|
|
6471
|
+
usePinToSend({
|
|
6472
|
+
scrollRef,
|
|
6473
|
+
contentRef,
|
|
6474
|
+
spacerRef,
|
|
6475
|
+
topOffset: 16
|
|
6476
|
+
});
|
|
6477
|
+
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
6478
|
+
return /* @__PURE__ */ jsx(ScrollElementContext.Provider, {
|
|
6479
|
+
value: nonAutoScrollEl,
|
|
6480
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
6481
|
+
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:relative", className),
|
|
6482
|
+
children: [
|
|
6483
|
+
/* @__PURE__ */ jsxs("div", {
|
|
6484
|
+
ref: nonAutoScrollRefCallback,
|
|
6485
|
+
className: "cpk:flex-1 cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
6486
|
+
...props,
|
|
6487
|
+
children: [/* @__PURE__ */ jsx("div", {
|
|
6488
|
+
ref: contentRef,
|
|
6489
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
6490
|
+
children
|
|
6491
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
6492
|
+
ref: spacerRef,
|
|
6493
|
+
"data-pin-to-send-spacer": true,
|
|
6494
|
+
"aria-hidden": "true",
|
|
6495
|
+
style: {
|
|
6496
|
+
height: 0,
|
|
6497
|
+
flex: "0 0 auto"
|
|
6498
|
+
}
|
|
6499
|
+
})]
|
|
6500
|
+
}),
|
|
6501
|
+
BoundFeather,
|
|
6502
|
+
showScrollButton && !isResizing && /* @__PURE__ */ jsx("div", {
|
|
6503
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6504
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6505
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6506
|
+
})
|
|
6507
|
+
]
|
|
6508
|
+
})
|
|
6509
|
+
});
|
|
6510
|
+
};
|
|
6511
|
+
_CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
6512
|
+
const mode = normalizeAutoScroll(autoScroll);
|
|
6373
6513
|
const [hasMounted, setHasMounted] = useState(false);
|
|
6374
|
-
const
|
|
6514
|
+
const scrollRef = useRef(null);
|
|
6515
|
+
const contentRef = useRef(null);
|
|
6516
|
+
const scrollToBottom = useCallback(() => {
|
|
6517
|
+
const el = scrollRef.current;
|
|
6518
|
+
if (el) el.scrollTo({
|
|
6519
|
+
top: el.scrollHeight,
|
|
6520
|
+
behavior: "smooth"
|
|
6521
|
+
});
|
|
6522
|
+
}, []);
|
|
6375
6523
|
const [showScrollButton, setShowScrollButton] = useState(false);
|
|
6376
6524
|
const [nonAutoScrollEl, setNonAutoScrollEl] = useState(null);
|
|
6377
6525
|
const nonAutoScrollRefCallback = useCallback((el) => {
|
|
@@ -6382,7 +6530,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6382
6530
|
setHasMounted(true);
|
|
6383
6531
|
}, []);
|
|
6384
6532
|
useEffect(() => {
|
|
6385
|
-
if (
|
|
6533
|
+
if (mode === "pin-to-bottom") return;
|
|
6386
6534
|
const scrollElement = scrollRef.current;
|
|
6387
6535
|
if (!scrollElement) return;
|
|
6388
6536
|
const checkScroll = () => {
|
|
@@ -6396,7 +6544,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6396
6544
|
scrollElement.removeEventListener("scroll", checkScroll);
|
|
6397
6545
|
resizeObserver.disconnect();
|
|
6398
6546
|
};
|
|
6399
|
-
}, [scrollRef,
|
|
6547
|
+
}, [scrollRef, mode]);
|
|
6400
6548
|
if (!hasMounted) return /* @__PURE__ */ jsx("div", {
|
|
6401
6549
|
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",
|
|
6402
6550
|
children: /* @__PURE__ */ jsx("div", {
|
|
@@ -6404,7 +6552,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6404
6552
|
children
|
|
6405
6553
|
})
|
|
6406
6554
|
});
|
|
6407
|
-
if (
|
|
6555
|
+
if (mode === "none") {
|
|
6408
6556
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
6409
6557
|
return /* @__PURE__ */ jsx(ScrollElementContext.Provider, {
|
|
6410
6558
|
value: nonAutoScrollEl,
|
|
@@ -6421,13 +6569,28 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6421
6569
|
BoundFeather,
|
|
6422
6570
|
showScrollButton && !isResizing && /* @__PURE__ */ jsx("div", {
|
|
6423
6571
|
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6424
|
-
style: { bottom: `${inputContainerHeight +
|
|
6572
|
+
style: { bottom: `${inputContainerHeight + SCROLL_BUTTON_OFFSET}px` },
|
|
6425
6573
|
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6426
6574
|
})
|
|
6427
6575
|
]
|
|
6428
6576
|
})
|
|
6429
6577
|
});
|
|
6430
6578
|
}
|
|
6579
|
+
if (mode === "pin-to-send") return /* @__PURE__ */ jsx(PinToSendScrollContainer, {
|
|
6580
|
+
scrollRef,
|
|
6581
|
+
contentRef,
|
|
6582
|
+
scrollToBottom,
|
|
6583
|
+
scrollToBottomButton,
|
|
6584
|
+
feather,
|
|
6585
|
+
inputContainerHeight,
|
|
6586
|
+
isResizing,
|
|
6587
|
+
nonAutoScrollEl,
|
|
6588
|
+
nonAutoScrollRefCallback,
|
|
6589
|
+
showScrollButton,
|
|
6590
|
+
className,
|
|
6591
|
+
...props,
|
|
6592
|
+
children
|
|
6593
|
+
});
|
|
6431
6594
|
return /* @__PURE__ */ jsx(StickToBottom, {
|
|
6432
6595
|
className: cn("cpk:flex-1 cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0", className),
|
|
6433
6596
|
resize: "smooth",
|
|
@@ -6450,9 +6613,8 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6450
6613
|
...props,
|
|
6451
6614
|
children: /* @__PURE__ */ jsx(ChevronDown, { className: "cpk:w-4 cpk:h-4 cpk:text-gray-600 cpk:dark:text-white" })
|
|
6452
6615
|
});
|
|
6453
|
-
_CopilotChatView.Feather = ({ className,
|
|
6454
|
-
className
|
|
6455
|
-
style,
|
|
6616
|
+
_CopilotChatView.Feather = ({ className, ...props }) => /* @__PURE__ */ jsx("div", {
|
|
6617
|
+
className,
|
|
6456
6618
|
...props
|
|
6457
6619
|
});
|
|
6458
6620
|
_CopilotChatView.WelcomeMessage = ({ className, ...props }) => {
|
|
@@ -6620,7 +6782,9 @@ async function transcribeAudio(core, audioBlob, filename = "recording.webm") {
|
|
|
6620
6782
|
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
|
|
6621
6783
|
const existingConfig = useCopilotChatConfiguration();
|
|
6622
6784
|
const resolvedAgentId = agentId ?? existingConfig?.agentId ?? DEFAULT_AGENT_ID;
|
|
6623
|
-
const
|
|
6785
|
+
const providedThreadId = threadId ?? existingConfig?.threadId;
|
|
6786
|
+
const resolvedThreadId = useMemo(() => providedThreadId ?? randomUUID(), [providedThreadId]);
|
|
6787
|
+
const hasExplicitThreadId = !!threadId || !!existingConfig?.hasExplicitThreadId;
|
|
6624
6788
|
const { agent } = useAgent({
|
|
6625
6789
|
agentId: resolvedAgentId,
|
|
6626
6790
|
threadId: resolvedThreadId,
|
|
@@ -6658,7 +6822,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6658
6822
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
6659
6823
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
6660
6824
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
6825
|
+
const [lastConnectedThreadId, setLastConnectedThreadId] = useState(null);
|
|
6826
|
+
const isConnecting = hasExplicitThreadId && lastConnectedThreadId !== resolvedThreadId;
|
|
6661
6827
|
useEffect(() => {
|
|
6828
|
+
if (!hasExplicitThreadId) return;
|
|
6662
6829
|
let detached = false;
|
|
6663
6830
|
const connectAbortController = new AbortController();
|
|
6664
6831
|
if (agent instanceof HttpAgent) agent.abortController = connectAbortController;
|
|
@@ -6668,6 +6835,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6668
6835
|
} catch (error) {
|
|
6669
6836
|
if (detached) return;
|
|
6670
6837
|
console.error("CopilotChat: connectAgent failed", error);
|
|
6838
|
+
} finally {
|
|
6839
|
+
if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
|
|
6840
|
+
if (!detached) setLastConnectedThreadId(resolvedThreadId);
|
|
6841
|
+
});
|
|
6671
6842
|
}
|
|
6672
6843
|
};
|
|
6673
6844
|
connect(agent);
|
|
@@ -6679,7 +6850,8 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6679
6850
|
}, [
|
|
6680
6851
|
resolvedThreadId,
|
|
6681
6852
|
agent,
|
|
6682
|
-
resolvedAgentId
|
|
6853
|
+
resolvedAgentId,
|
|
6854
|
+
hasExplicitThreadId
|
|
6683
6855
|
]);
|
|
6684
6856
|
const onSubmitInput = useCallback(async (value) => {
|
|
6685
6857
|
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
@@ -6832,6 +7004,22 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6832
7004
|
const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => `${tc.id}:${tc.function?.arguments?.length ?? 0}`).join(";") : "";
|
|
6833
7005
|
return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
|
|
6834
7006
|
}).join(",")]);
|
|
7007
|
+
const lastUserMessageId = useMemo(() => {
|
|
7008
|
+
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "user") return messages[i].id;
|
|
7009
|
+
return null;
|
|
7010
|
+
}, [messages]);
|
|
7011
|
+
const [sendNonce, setSendNonce] = useState(0);
|
|
7012
|
+
const prevLastUserMessageIdRef = useRef(lastUserMessageId);
|
|
7013
|
+
useEffect(() => {
|
|
7014
|
+
if (lastUserMessageId && lastUserMessageId !== prevLastUserMessageIdRef.current) {
|
|
7015
|
+
setSendNonce((n) => n + 1);
|
|
7016
|
+
prevLastUserMessageIdRef.current = lastUserMessageId;
|
|
7017
|
+
}
|
|
7018
|
+
}, [lastUserMessageId]);
|
|
7019
|
+
const lastUserMessageState = useMemo(() => ({
|
|
7020
|
+
id: lastUserMessageId,
|
|
7021
|
+
sendNonce
|
|
7022
|
+
}), [lastUserMessageId, sendNonce]);
|
|
6835
7023
|
const RenderedChatView = renderSlot(chatView, CopilotChatView, {
|
|
6836
7024
|
...mergedProps,
|
|
6837
7025
|
messages,
|
|
@@ -6850,11 +7038,14 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6850
7038
|
dragOver,
|
|
6851
7039
|
onDragOver: handleDragOver,
|
|
6852
7040
|
onDragLeave: handleDragLeave,
|
|
6853
|
-
onDrop: handleDrop
|
|
7041
|
+
onDrop: handleDrop,
|
|
7042
|
+
isConnecting,
|
|
7043
|
+
hasExplicitThreadId
|
|
6854
7044
|
});
|
|
6855
7045
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
6856
7046
|
agentId: resolvedAgentId,
|
|
6857
7047
|
threadId: resolvedThreadId,
|
|
7048
|
+
hasExplicitThreadId,
|
|
6858
7049
|
labels,
|
|
6859
7050
|
isModalDefaultOpen,
|
|
6860
7051
|
children: /* @__PURE__ */ jsxs("div", {
|
|
@@ -6885,7 +7076,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6885
7076
|
},
|
|
6886
7077
|
children: transcriptionError
|
|
6887
7078
|
}),
|
|
6888
|
-
|
|
7079
|
+
/* @__PURE__ */ jsx(LastUserMessageContext.Provider, {
|
|
7080
|
+
value: lastUserMessageState,
|
|
7081
|
+
children: RenderedChatView
|
|
7082
|
+
})
|
|
6889
7083
|
]
|
|
6890
7084
|
})
|
|
6891
7085
|
});
|
|
@@ -8611,12 +8805,19 @@ function useCoAgentStateRenders() {
|
|
|
8611
8805
|
//#region src/context/threads-context.tsx
|
|
8612
8806
|
const ThreadsContext = createContext(void 0);
|
|
8613
8807
|
function ThreadsProvider({ children, threadId: explicitThreadId }) {
|
|
8614
|
-
const [internalThreadId,
|
|
8808
|
+
const [internalThreadId, setInternalThreadId] = useState(() => randomUUID());
|
|
8809
|
+
const [internalIsExplicit, setInternalIsExplicit] = useState(false);
|
|
8615
8810
|
const threadId = explicitThreadId ?? internalThreadId;
|
|
8811
|
+
const isThreadIdExplicit = explicitThreadId != null || internalIsExplicit;
|
|
8812
|
+
const setThreadId = useCallback((value) => {
|
|
8813
|
+
setInternalThreadId(value);
|
|
8814
|
+
setInternalIsExplicit(true);
|
|
8815
|
+
}, []);
|
|
8616
8816
|
return /* @__PURE__ */ jsx(ThreadsContext.Provider, {
|
|
8617
8817
|
value: {
|
|
8618
8818
|
threadId,
|
|
8619
|
-
setThreadId
|
|
8819
|
+
setThreadId,
|
|
8820
|
+
isThreadIdExplicit
|
|
8620
8821
|
},
|
|
8621
8822
|
children
|
|
8622
8823
|
});
|
|
@@ -9318,7 +9519,7 @@ function CopilotKitInternal(cpkProps) {
|
|
|
9318
9519
|
if (props.agent) setAgentSession({ agentName: props.agent });
|
|
9319
9520
|
else setAgentSession(null);
|
|
9320
9521
|
}, [props.agent]);
|
|
9321
|
-
const { threadId, setThreadId: setInternalThreadId } = useThreads();
|
|
9522
|
+
const { threadId, setThreadId: setInternalThreadId, isThreadIdExplicit } = useThreads();
|
|
9322
9523
|
const setThreadId = useCallback((value) => {
|
|
9323
9524
|
if (props.threadId) throw new Error("Cannot call setThreadId() when threadId is provided via props.");
|
|
9324
9525
|
setInternalThreadId(value);
|
|
@@ -9518,6 +9719,7 @@ function CopilotKitInternal(cpkProps) {
|
|
|
9518
9719
|
return /* @__PURE__ */ jsx(CopilotChatConfigurationProvider, {
|
|
9519
9720
|
agentId: props.agent ?? "default",
|
|
9520
9721
|
threadId,
|
|
9722
|
+
hasExplicitThreadId: isThreadIdExplicit,
|
|
9521
9723
|
children: /* @__PURE__ */ jsxs(CopilotContext.Provider, {
|
|
9522
9724
|
value: copilotContextValue,
|
|
9523
9725
|
children: [
|
|
@@ -9568,4 +9770,4 @@ function validateProps(props) {
|
|
|
9568
9770
|
|
|
9569
9771
|
//#endregion
|
|
9570
9772
|
export { CopilotKitProvider as $, CopilotChatSuggestionView as A, useConfigureSuggestions as B, CopilotChatToggleButton as C, CopilotChatView_default as D, CopilotChat as E, CopilotChatAssistantMessage_default as F, useRenderTool as G, useCapabilities as H, CopilotChatToolCallsView as I, useRenderActivityMessage as J, useComponent as K, useAttachments as L, CopilotChatReasoningMessage_default as M, CopilotChatUserMessage_default as N, CopilotChatAttachmentQueue as O, CopilotChatAttachmentRenderer as P, useRenderToolCall as Q, useThreads$1 as R, CopilotModalHeader as S, DefaultOpenIcon as T, useHumanInTheLoop as U, useSuggestions as V, useDefaultRenderTool as W, UseAgentUpdate as X, useRenderCustomMessages as Y, useAgent as Z, WildcardToolCallRender as _, ThreadsProvider as a, SandboxFunctionsContext as at, CopilotPopupView as b, CoAgentStateRendersProvider as c, MCPAppsActivityRenderer as ct, shouldShowDevConsole as d, CopilotChatInput_default as dt, useCopilotKit as et, useToast as f, AudioRecorderError as ft, useCopilotContext as g, CopilotContext as h, useCopilotChatConfiguration as ht, ThreadsContext as i, createA2UIMessageRenderer as it, CopilotChatSuggestionPill as j, CopilotChatMessageView as k, useCoAgentStateRenders as l, MCPAppsActivityType as lt, useCopilotMessagesContext as m, CopilotChatConfigurationProvider as mt, defaultCopilotContextCategories as n, useAgentContext as nt, useThreads as o, useSandboxFunctions as ot, CopilotMessagesContext as p, CopilotChatAudioRecorder as pt, useFrontendTool as q, CoAgentStateRenderBridge as r, defineToolCallRenderer as rt, CoAgentStateRendersContext as s, MCPAppsActivityContentSchema as st, CopilotKit as t, CopilotKitCoreReact as tt, useAsyncCallback as u, CopilotKitInspector as ut, CopilotPopup as v, DefaultCloseIcon as w, CopilotSidebarView as x, CopilotSidebar as y, useInterrupt as z };
|
|
9571
|
-
//# sourceMappingURL=copilotkit-
|
|
9773
|
+
//# sourceMappingURL=copilotkit-DAatqMh2.mjs.map
|