@copilotkit/react-core 1.56.1 → 1.56.2-canary.pin-to-send
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-BBYbekCa.mjs} +234 -60
- package/dist/copilotkit-BBYbekCa.mjs.map +1 -0
- package/dist/{copilotkit-CSJw5BG8.cjs → copilotkit-D5JT2Pu3.cjs} +233 -59
- package/dist/copilotkit-D5JT2Pu3.cjs.map +1 -0
- package/dist/{copilotkit-CCbxm6JM.d.mts → copilotkit-DArT2Iuw.d.mts} +62 -18
- package/dist/copilotkit-DArT2Iuw.d.mts.map +1 -0
- package/dist/{copilotkit-BtP7w7cT.d.cts → copilotkit-KEc28l8G.d.cts} +62 -18
- package/dist/copilotkit-KEc28l8G.d.cts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +16 -40
- 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 +232 -62
- package/dist/v2/index.umd.js.map +1 -1
- package/package.json +6 -6
- package/src/v2/components/chat/CopilotChat.tsx +80 -4
- package/src/v2/components/chat/CopilotChatInput.tsx +22 -0
- package/src/v2/components/chat/CopilotChatView.tsx +206 -11
- package/src/v2/components/chat/__tests__/CopilotChat.absentThreadConnect.test.tsx +66 -0
- package/src/v2/components/chat/__tests__/CopilotChatActivityRendering.e2e.test.tsx +300 -2
- package/src/v2/components/chat/__tests__/CopilotChatView.connectingGate.test.tsx +56 -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/CopilotKitProvider.tsx +2 -11
- 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
|
@@ -610,7 +610,7 @@ CopilotChatAudioRecorder.displayName = "CopilotChatAudioRecorder";
|
|
|
610
610
|
//#region src/v2/components/chat/CopilotChatInput.tsx
|
|
611
611
|
const SLASH_MENU_MAX_VISIBLE_ITEMS = 5;
|
|
612
612
|
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 }) {
|
|
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, bottomAnchored = false, textArea, sendButton, startTranscribeButton, cancelTranscribeButton, finishTranscribeButton, addMenuButton, audioRecorder, disclaimer, children, className, ...props }) {
|
|
614
614
|
const isControlled = value !== void 0;
|
|
615
615
|
const [internalValue, setInternalValue] = (0, react.useState)(() => value ?? "");
|
|
616
616
|
(0, react.useEffect)(() => {
|
|
@@ -1134,7 +1134,8 @@ function CopilotChatInput({ mode = "input", onSubmitMessage, onStop, isRunning =
|
|
|
1134
1134
|
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
1135
|
style: {
|
|
1136
1136
|
transform: keyboardHeight > 0 ? `translateY(-${keyboardHeight}px)` : void 0,
|
|
1137
|
-
transition: "transform 0.2s ease-out"
|
|
1137
|
+
transition: "transform 0.2s ease-out",
|
|
1138
|
+
...positioning === "absolute" || bottomAnchored ? { paddingBottom: "var(--copilotkit-license-banner-offset, 0px)" } : {}
|
|
1138
1139
|
},
|
|
1139
1140
|
...props,
|
|
1140
1141
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -1349,6 +1350,8 @@ CopilotKitInspector.displayName = "CopilotKitInspector";
|
|
|
1349
1350
|
|
|
1350
1351
|
//#endregion
|
|
1351
1352
|
//#region src/v2/components/license-warning-banner.tsx
|
|
1353
|
+
const LICENSE_BANNER_OFFSET_PX = 52;
|
|
1354
|
+
const LICENSE_BANNER_OFFSET_VAR = "--copilotkit-license-banner-offset";
|
|
1352
1355
|
const BANNER_STYLES = {
|
|
1353
1356
|
base: {
|
|
1354
1357
|
position: "fixed",
|
|
@@ -1390,6 +1393,14 @@ function getSeverityStyle(severity) {
|
|
|
1390
1393
|
}
|
|
1391
1394
|
}
|
|
1392
1395
|
function BannerShell({ severity, message, actionLabel, actionUrl, onDismiss }) {
|
|
1396
|
+
(0, react.useEffect)(() => {
|
|
1397
|
+
if (typeof document === "undefined") return;
|
|
1398
|
+
const root = document.documentElement;
|
|
1399
|
+
root.style.setProperty(LICENSE_BANNER_OFFSET_VAR, `${LICENSE_BANNER_OFFSET_PX}px`);
|
|
1400
|
+
return () => {
|
|
1401
|
+
root.style.removeProperty(LICENSE_BANNER_OFFSET_VAR);
|
|
1402
|
+
};
|
|
1403
|
+
}, []);
|
|
1393
1404
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1394
1405
|
style: {
|
|
1395
1406
|
...BANNER_STYLES.base,
|
|
@@ -3342,7 +3353,6 @@ const CopilotKitProvider = ({ children, runtimeUrl, headers: headersProp = {}, c
|
|
|
3342
3353
|
didMountRef.current = true;
|
|
3343
3354
|
}, []);
|
|
3344
3355
|
(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
3356
|
copilotkit.setDefaultThrottleMs(defaultThrottleMs);
|
|
3347
3357
|
}, [copilotkit, defaultThrottleMs]);
|
|
3348
3358
|
const designSkill = openGenerativeUI?.designSkill ?? DEFAULT_DESIGN_SKILL;
|
|
@@ -3559,15 +3569,6 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3559
3569
|
const providerThrottleMs = copilotkit.defaultThrottleMs;
|
|
3560
3570
|
const chatConfig = useCopilotChatConfiguration();
|
|
3561
3571
|
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
3572
|
const [, forceUpdate] = (0, react.useReducer)((x) => x + 1, 0);
|
|
3572
3573
|
const updateFlags = (0, react.useMemo)(() => updates ?? ALL_UPDATES, [JSON.stringify(updates)]);
|
|
3573
3574
|
const provisionalAgentCache = (0, react.useRef)(/* @__PURE__ */ new Map());
|
|
@@ -3630,9 +3631,8 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3630
3631
|
]);
|
|
3631
3632
|
(0, react.useEffect)(() => {
|
|
3632
3633
|
if (updateFlags.length === 0) return;
|
|
3633
|
-
const handlers = {};
|
|
3634
|
-
let timerId = null;
|
|
3635
3634
|
let active = true;
|
|
3635
|
+
const handlers = {};
|
|
3636
3636
|
let batchScheduled = false;
|
|
3637
3637
|
const batchedForceUpdate = () => {
|
|
3638
3638
|
if (!active) return;
|
|
@@ -3644,46 +3644,24 @@ function useAgent({ agentId, threadId, updates, throttleMs } = {}) {
|
|
|
3644
3644
|
});
|
|
3645
3645
|
}
|
|
3646
3646
|
};
|
|
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
|
-
}
|
|
3647
|
+
if (updateFlags.includes(UseAgentUpdate.OnMessagesChanged)) handlers.onMessagesChanged = forceUpdate;
|
|
3671
3648
|
if (updateFlags.includes(UseAgentUpdate.OnStateChanged)) handlers.onStateChanged = batchedForceUpdate;
|
|
3672
3649
|
if (updateFlags.includes(UseAgentUpdate.OnRunStatusChanged)) {
|
|
3673
3650
|
handlers.onRunInitialized = batchedForceUpdate;
|
|
3674
3651
|
handlers.onRunFinalized = batchedForceUpdate;
|
|
3675
3652
|
handlers.onRunFailed = batchedForceUpdate;
|
|
3653
|
+
handlers.onRunErrorEvent = batchedForceUpdate;
|
|
3676
3654
|
}
|
|
3677
|
-
const subscription =
|
|
3655
|
+
const subscription = copilotkit.subscribeToAgentWithOptions(agent, handlers, { throttleMs });
|
|
3678
3656
|
return () => {
|
|
3679
3657
|
active = false;
|
|
3680
|
-
if (timerId !== null) clearTimeout(timerId);
|
|
3681
3658
|
subscription.unsubscribe();
|
|
3682
3659
|
};
|
|
3683
3660
|
}, [
|
|
3684
3661
|
agent,
|
|
3685
3662
|
forceUpdate,
|
|
3686
|
-
|
|
3663
|
+
throttleMs,
|
|
3664
|
+
providerThrottleMs,
|
|
3687
3665
|
updateFlags
|
|
3688
3666
|
]);
|
|
3689
3667
|
(0, react.useEffect)(() => {
|
|
@@ -4637,13 +4615,14 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4637
4615
|
const { copilotkit } = useCopilotKit();
|
|
4638
4616
|
const [store] = (0, react.useState)(() => (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch }));
|
|
4639
4617
|
const coreThreads = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreads);
|
|
4640
|
-
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt }) => ({
|
|
4618
|
+
const threads = (0, react.useMemo)(() => coreThreads.map(({ id, agentId, name, archived, createdAt, updatedAt, lastRunAt }) => ({
|
|
4641
4619
|
id,
|
|
4642
4620
|
agentId,
|
|
4643
4621
|
name,
|
|
4644
4622
|
archived,
|
|
4645
4623
|
createdAt,
|
|
4646
|
-
updatedAt
|
|
4624
|
+
updatedAt,
|
|
4625
|
+
...lastRunAt !== void 0 ? { lastRunAt } : {}
|
|
4647
4626
|
})), [coreThreads]);
|
|
4648
4627
|
const storeIsLoading = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsIsLoading);
|
|
4649
4628
|
const storeError = useThreadStoreSelector(store, _copilotkit_core.ɵselectThreadsError);
|
|
@@ -4656,7 +4635,9 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4656
4635
|
if (copilotkit.runtimeUrl) return null;
|
|
4657
4636
|
return /* @__PURE__ */ new Error("Runtime URL is not configured");
|
|
4658
4637
|
}, [copilotkit.runtimeUrl]);
|
|
4659
|
-
const
|
|
4638
|
+
const [hasDispatchedContext, setHasDispatchedContext] = (0, react.useState)(false);
|
|
4639
|
+
const preConnectLoading = !!copilotkit.runtimeUrl && !hasDispatchedContext;
|
|
4640
|
+
const isLoading = runtimeError ? false : preConnectLoading || storeIsLoading;
|
|
4660
4641
|
const error = runtimeError ?? storeError;
|
|
4661
4642
|
(0, react.useEffect)(() => {
|
|
4662
4643
|
store.start();
|
|
@@ -4664,19 +4645,27 @@ function useThreads$1({ agentId, includeArchived, limit }) {
|
|
|
4664
4645
|
store.stop();
|
|
4665
4646
|
};
|
|
4666
4647
|
}, [store]);
|
|
4648
|
+
const runtimeStatus = copilotkit.runtimeConnectionStatus;
|
|
4667
4649
|
(0, react.useEffect)(() => {
|
|
4668
|
-
|
|
4650
|
+
if (!copilotkit.runtimeUrl) {
|
|
4651
|
+
store.setContext(null);
|
|
4652
|
+
return;
|
|
4653
|
+
}
|
|
4654
|
+
if (runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
|
|
4655
|
+
const context = {
|
|
4669
4656
|
runtimeUrl: copilotkit.runtimeUrl,
|
|
4670
4657
|
headers: { ...copilotkit.headers },
|
|
4671
4658
|
wsUrl: copilotkit.intelligence?.wsUrl,
|
|
4672
4659
|
agentId,
|
|
4673
4660
|
includeArchived,
|
|
4674
4661
|
limit
|
|
4675
|
-
}
|
|
4662
|
+
};
|
|
4676
4663
|
store.setContext(context);
|
|
4664
|
+
setHasDispatchedContext(true);
|
|
4677
4665
|
}, [
|
|
4678
4666
|
store,
|
|
4679
4667
|
copilotkit.runtimeUrl,
|
|
4668
|
+
runtimeStatus,
|
|
4680
4669
|
headersKey,
|
|
4681
4670
|
copilotkit.intelligence?.wsUrl,
|
|
4682
4671
|
agentId,
|
|
@@ -6201,9 +6190,97 @@ function useKeyboardHeight() {
|
|
|
6201
6190
|
return keyboardState;
|
|
6202
6191
|
}
|
|
6203
6192
|
|
|
6193
|
+
//#endregion
|
|
6194
|
+
//#region src/v2/components/chat/normalize-auto-scroll.ts
|
|
6195
|
+
const VALID = [
|
|
6196
|
+
"pin-to-bottom",
|
|
6197
|
+
"pin-to-send",
|
|
6198
|
+
"none"
|
|
6199
|
+
];
|
|
6200
|
+
function normalizeAutoScroll(value) {
|
|
6201
|
+
if (value === void 0) return "pin-to-bottom";
|
|
6202
|
+
if (value === true) return "pin-to-bottom";
|
|
6203
|
+
if (value === false) return "none";
|
|
6204
|
+
if (VALID.includes(value)) return value;
|
|
6205
|
+
return "pin-to-bottom";
|
|
6206
|
+
}
|
|
6207
|
+
|
|
6208
|
+
//#endregion
|
|
6209
|
+
//#region src/v2/components/chat/last-user-message-context.ts
|
|
6210
|
+
const LastUserMessageContext = react.default.createContext({
|
|
6211
|
+
id: null,
|
|
6212
|
+
sendNonce: 0
|
|
6213
|
+
});
|
|
6214
|
+
|
|
6215
|
+
//#endregion
|
|
6216
|
+
//#region src/v2/hooks/use-pin-to-send.ts
|
|
6217
|
+
function usePinToSend({ scrollRef, contentRef, spacerRef, topOffset = 16 }) {
|
|
6218
|
+
const { id, sendNonce } = (0, react.useContext)(LastUserMessageContext);
|
|
6219
|
+
const lastNonceRef = (0, react.useRef)(-1);
|
|
6220
|
+
const currentSpacerHeightRef = (0, react.useRef)(0);
|
|
6221
|
+
(0, react.useEffect)(() => {
|
|
6222
|
+
if (sendNonce === lastNonceRef.current) return;
|
|
6223
|
+
lastNonceRef.current = sendNonce;
|
|
6224
|
+
if (!id) return;
|
|
6225
|
+
const scrollEl = scrollRef.current;
|
|
6226
|
+
const contentEl = contentRef.current;
|
|
6227
|
+
const spacerEl = spacerRef.current;
|
|
6228
|
+
if (!scrollEl || !contentEl || !spacerEl) return;
|
|
6229
|
+
const escaped = typeof CSS !== "undefined" && CSS.escape ? CSS.escape(id) : id.replace(/[!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~]/g, "\\$&");
|
|
6230
|
+
const targetEl = contentEl.querySelector(`[data-message-id="${escaped}"]`);
|
|
6231
|
+
if (!targetEl) return;
|
|
6232
|
+
const viewportHeight = scrollEl.clientHeight;
|
|
6233
|
+
const userMessageHeight = targetEl.getBoundingClientRect().height;
|
|
6234
|
+
const paddingTop = parseFloat(getComputedStyle(targetEl).paddingTop) || 0;
|
|
6235
|
+
const bubbleHeight = Math.max(0, userMessageHeight - paddingTop);
|
|
6236
|
+
const spacerHeight = Math.max(0, viewportHeight - bubbleHeight - topOffset);
|
|
6237
|
+
spacerEl.style.height = `${spacerHeight}px`;
|
|
6238
|
+
currentSpacerHeightRef.current = spacerHeight;
|
|
6239
|
+
const raf = requestAnimationFrame(() => {
|
|
6240
|
+
const targetTop = computeOffsetTop(targetEl, scrollEl) + paddingTop - topOffset;
|
|
6241
|
+
scrollEl.scrollTo({
|
|
6242
|
+
top: Math.max(0, targetTop),
|
|
6243
|
+
behavior: "smooth"
|
|
6244
|
+
});
|
|
6245
|
+
});
|
|
6246
|
+
const ro = new ResizeObserver(() => {
|
|
6247
|
+
if (!contentEl || !spacerEl || !scrollEl) return;
|
|
6248
|
+
const consumedBelow = contentEl.getBoundingClientRect().height - computeOffsetTop(targetEl, contentEl) - userMessageHeight;
|
|
6249
|
+
const remaining = Math.max(0, spacerHeight - consumedBelow);
|
|
6250
|
+
if (remaining < currentSpacerHeightRef.current) {
|
|
6251
|
+
spacerEl.style.height = `${remaining}px`;
|
|
6252
|
+
currentSpacerHeightRef.current = remaining;
|
|
6253
|
+
}
|
|
6254
|
+
});
|
|
6255
|
+
ro.observe(contentEl);
|
|
6256
|
+
return () => {
|
|
6257
|
+
cancelAnimationFrame(raf);
|
|
6258
|
+
ro.disconnect();
|
|
6259
|
+
};
|
|
6260
|
+
}, [
|
|
6261
|
+
id,
|
|
6262
|
+
sendNonce,
|
|
6263
|
+
scrollRef,
|
|
6264
|
+
contentRef,
|
|
6265
|
+
spacerRef,
|
|
6266
|
+
topOffset
|
|
6267
|
+
]);
|
|
6268
|
+
}
|
|
6269
|
+
function computeOffsetTop(el, stopAt) {
|
|
6270
|
+
const elRect = el.getBoundingClientRect();
|
|
6271
|
+
const stopRect = stopAt.getBoundingClientRect();
|
|
6272
|
+
return elRect.top - stopRect.top + stopAt.scrollTop;
|
|
6273
|
+
}
|
|
6274
|
+
|
|
6204
6275
|
//#endregion
|
|
6205
6276
|
//#region src/v2/components/chat/CopilotChatView.tsx
|
|
6206
6277
|
const FEATHER_HEIGHT = 96;
|
|
6278
|
+
const PIN_TO_SEND_FEATHER_HEIGHT = 48;
|
|
6279
|
+
const PinToSendSoftFeather = ({ className, style, ...props }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6280
|
+
className: cn("cpk:absolute cpk:bottom-0 cpk:left-0 cpk:right-4 cpk:h-12 cpk:pointer-events-none cpk:z-10 cpk:bg-gradient-to-t", "cpk:from-white cpk:to-transparent", "cpk:dark:from-[rgb(33,33,33)]", className),
|
|
6281
|
+
style,
|
|
6282
|
+
...props
|
|
6283
|
+
});
|
|
6207
6284
|
function DropOverlay() {
|
|
6208
6285
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6209
6286
|
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 +6293,7 @@ function DropOverlay() {
|
|
|
6216
6293
|
})
|
|
6217
6294
|
});
|
|
6218
6295
|
}
|
|
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 }) {
|
|
6296
|
+
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
6297
|
const inputContainerRef = (0, react.useRef)(null);
|
|
6221
6298
|
const [inputContainerHeight, setInputContainerHeight] = (0, react.useState)(0);
|
|
6222
6299
|
const [isResizing, setIsResizing] = (0, react.useState)(false);
|
|
@@ -6268,9 +6345,10 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6268
6345
|
keyboardHeight: isKeyboardOpen ? keyboardHeight : 0,
|
|
6269
6346
|
containerRef: inputContainerRef,
|
|
6270
6347
|
showDisclaimer: true,
|
|
6348
|
+
bottomAnchored: true,
|
|
6271
6349
|
...disclaimer !== void 0 ? { disclaimer } : {}
|
|
6272
6350
|
});
|
|
6273
|
-
const hasSuggestions = Array.isArray(suggestions) && suggestions.length > 0;
|
|
6351
|
+
const hasSuggestions = !isConnecting && !isRunning && Array.isArray(suggestions) && suggestions.length > 0;
|
|
6274
6352
|
const BoundSuggestionView = hasSuggestions ? renderSlot(suggestionView, CopilotChatSuggestionView, {
|
|
6275
6353
|
suggestions,
|
|
6276
6354
|
loadingIndexes: suggestionLoadingIndexes,
|
|
@@ -6292,7 +6370,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6292
6370
|
})
|
|
6293
6371
|
})
|
|
6294
6372
|
});
|
|
6295
|
-
if (messages.length === 0 && !(welcomeScreen === false)) {
|
|
6373
|
+
if (messages.length === 0 && !(welcomeScreen === false) && !isConnecting && !hasExplicitThreadId) {
|
|
6296
6374
|
const BoundInputForWelcome = renderSlot(input, CopilotChatInput_default, {
|
|
6297
6375
|
onSubmitMessage,
|
|
6298
6376
|
onStop,
|
|
@@ -6399,9 +6477,60 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6399
6477
|
] })
|
|
6400
6478
|
});
|
|
6401
6479
|
};
|
|
6402
|
-
|
|
6480
|
+
const PinToSendScrollContainer = ({ children, scrollRef, contentRef, scrollToBottom, scrollToBottomButton, feather, inputContainerHeight, isResizing, nonAutoScrollEl, nonAutoScrollRefCallback, showScrollButton, className, ...props }) => {
|
|
6481
|
+
const spacerRef = (0, react.useRef)(null);
|
|
6482
|
+
usePinToSend({
|
|
6483
|
+
scrollRef,
|
|
6484
|
+
contentRef,
|
|
6485
|
+
spacerRef,
|
|
6486
|
+
topOffset: 16
|
|
6487
|
+
});
|
|
6488
|
+
const BoundFeather = renderSlot(feather, PinToSendSoftFeather, {});
|
|
6489
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6490
|
+
value: nonAutoScrollEl,
|
|
6491
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6492
|
+
className: cn("cpk:h-full cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0 cpk:relative", className),
|
|
6493
|
+
children: [
|
|
6494
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6495
|
+
ref: nonAutoScrollRefCallback,
|
|
6496
|
+
className: "cpk:flex-1 cpk:min-h-0 cpk:overflow-y-auto cpk:overflow-x-hidden",
|
|
6497
|
+
...props,
|
|
6498
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6499
|
+
ref: contentRef,
|
|
6500
|
+
className: "cpk:px-4 cpk:sm:px-0 cpk:[div[data-sidebar-chat]_&]:px-8 cpk:[div[data-popup-chat]_&]:px-6",
|
|
6501
|
+
children
|
|
6502
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6503
|
+
ref: spacerRef,
|
|
6504
|
+
"data-pin-to-send-spacer": true,
|
|
6505
|
+
"aria-hidden": "true",
|
|
6506
|
+
style: {
|
|
6507
|
+
height: 0,
|
|
6508
|
+
flex: "0 0 auto"
|
|
6509
|
+
}
|
|
6510
|
+
})]
|
|
6511
|
+
}),
|
|
6512
|
+
BoundFeather,
|
|
6513
|
+
showScrollButton && !isResizing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6514
|
+
className: "cpk:absolute cpk:inset-x-0 cpk:flex cpk:justify-center cpk:z-30 cpk:pointer-events-none",
|
|
6515
|
+
style: { bottom: `${inputContainerHeight + PIN_TO_SEND_FEATHER_HEIGHT + 16}px` },
|
|
6516
|
+
children: renderSlot(scrollToBottomButton, CopilotChatView.ScrollToBottomButton, { onClick: () => scrollToBottom() })
|
|
6517
|
+
})
|
|
6518
|
+
]
|
|
6519
|
+
})
|
|
6520
|
+
});
|
|
6521
|
+
};
|
|
6522
|
+
_CopilotChatView.ScrollView = ({ children, autoScroll = "pin-to-bottom", scrollToBottomButton, feather, inputContainerHeight = 0, isResizing = false, className, ...props }) => {
|
|
6523
|
+
const mode = normalizeAutoScroll(autoScroll);
|
|
6403
6524
|
const [hasMounted, setHasMounted] = (0, react.useState)(false);
|
|
6404
|
-
const
|
|
6525
|
+
const scrollRef = (0, react.useRef)(null);
|
|
6526
|
+
const contentRef = (0, react.useRef)(null);
|
|
6527
|
+
const scrollToBottom = (0, react.useCallback)(() => {
|
|
6528
|
+
const el = scrollRef.current;
|
|
6529
|
+
if (el) el.scrollTo({
|
|
6530
|
+
top: el.scrollHeight,
|
|
6531
|
+
behavior: "smooth"
|
|
6532
|
+
});
|
|
6533
|
+
}, []);
|
|
6405
6534
|
const [showScrollButton, setShowScrollButton] = (0, react.useState)(false);
|
|
6406
6535
|
const [nonAutoScrollEl, setNonAutoScrollEl] = (0, react.useState)(null);
|
|
6407
6536
|
const nonAutoScrollRefCallback = (0, react.useCallback)((el) => {
|
|
@@ -6412,7 +6541,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6412
6541
|
setHasMounted(true);
|
|
6413
6542
|
}, []);
|
|
6414
6543
|
(0, react.useEffect)(() => {
|
|
6415
|
-
if (
|
|
6544
|
+
if (mode === "pin-to-bottom") return;
|
|
6416
6545
|
const scrollElement = scrollRef.current;
|
|
6417
6546
|
if (!scrollElement) return;
|
|
6418
6547
|
const checkScroll = () => {
|
|
@@ -6426,7 +6555,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6426
6555
|
scrollElement.removeEventListener("scroll", checkScroll);
|
|
6427
6556
|
resizeObserver.disconnect();
|
|
6428
6557
|
};
|
|
6429
|
-
}, [scrollRef,
|
|
6558
|
+
}, [scrollRef, mode]);
|
|
6430
6559
|
if (!hasMounted) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6431
6560
|
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
6561
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
@@ -6434,7 +6563,7 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6434
6563
|
children
|
|
6435
6564
|
})
|
|
6436
6565
|
});
|
|
6437
|
-
if (
|
|
6566
|
+
if (mode === "none") {
|
|
6438
6567
|
const BoundFeather = renderSlot(feather, CopilotChatView.Feather, {});
|
|
6439
6568
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ScrollElementContext.Provider, {
|
|
6440
6569
|
value: nonAutoScrollEl,
|
|
@@ -6458,6 +6587,21 @@ function CopilotChatView({ messageView, input, scrollView, suggestionView, welco
|
|
|
6458
6587
|
})
|
|
6459
6588
|
});
|
|
6460
6589
|
}
|
|
6590
|
+
if (mode === "pin-to-send") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PinToSendScrollContainer, {
|
|
6591
|
+
scrollRef,
|
|
6592
|
+
contentRef,
|
|
6593
|
+
scrollToBottom,
|
|
6594
|
+
scrollToBottomButton,
|
|
6595
|
+
feather,
|
|
6596
|
+
inputContainerHeight,
|
|
6597
|
+
isResizing,
|
|
6598
|
+
nonAutoScrollEl,
|
|
6599
|
+
nonAutoScrollRefCallback,
|
|
6600
|
+
showScrollButton,
|
|
6601
|
+
className,
|
|
6602
|
+
...props,
|
|
6603
|
+
children
|
|
6604
|
+
});
|
|
6461
6605
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(use_stick_to_bottom.StickToBottom, {
|
|
6462
6606
|
className: cn("cpk:flex-1 cpk:max-h-full cpk:flex cpk:flex-col cpk:min-h-0", className),
|
|
6463
6607
|
resize: "smooth",
|
|
@@ -6650,7 +6794,8 @@ async function transcribeAudio(core, audioBlob, filename = "recording.webm") {
|
|
|
6650
6794
|
function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen, attachments: attachmentsConfig, onError, throttleMs, ...props }) {
|
|
6651
6795
|
const existingConfig = useCopilotChatConfiguration();
|
|
6652
6796
|
const resolvedAgentId = agentId ?? existingConfig?.agentId ?? _copilotkit_shared.DEFAULT_AGENT_ID;
|
|
6653
|
-
const
|
|
6797
|
+
const providedThreadId = threadId ?? existingConfig?.threadId;
|
|
6798
|
+
const resolvedThreadId = (0, react.useMemo)(() => providedThreadId ?? (0, _copilotkit_shared.randomUUID)(), [providedThreadId]);
|
|
6654
6799
|
const { agent } = useAgent({
|
|
6655
6800
|
agentId: resolvedAgentId,
|
|
6656
6801
|
threadId: resolvedThreadId,
|
|
@@ -6688,7 +6833,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6688
6833
|
const isTranscriptionEnabled = copilotkit.audioFileTranscriptionEnabled;
|
|
6689
6834
|
const isMediaRecorderSupported = typeof window !== "undefined" && typeof MediaRecorder !== "undefined";
|
|
6690
6835
|
const { messageView: providedMessageView, suggestionView: providedSuggestionView, onStop: providedStopHandler, ...restProps } = props;
|
|
6836
|
+
const [lastConnectedThreadId, setLastConnectedThreadId] = (0, react.useState)(null);
|
|
6837
|
+
const isConnecting = !!providedThreadId && lastConnectedThreadId !== resolvedThreadId;
|
|
6691
6838
|
(0, react.useEffect)(() => {
|
|
6839
|
+
if (!providedThreadId) return;
|
|
6692
6840
|
let detached = false;
|
|
6693
6841
|
const connectAbortController = new AbortController();
|
|
6694
6842
|
if (agent instanceof _ag_ui_client.HttpAgent) agent.abortController = connectAbortController;
|
|
@@ -6698,6 +6846,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6698
6846
|
} catch (error) {
|
|
6699
6847
|
if (detached) return;
|
|
6700
6848
|
console.error("CopilotChat: connectAgent failed", error);
|
|
6849
|
+
} finally {
|
|
6850
|
+
if (!detached) (typeof requestAnimationFrame === "function" ? requestAnimationFrame : (cb) => setTimeout(cb, 16))(() => {
|
|
6851
|
+
if (!detached) setLastConnectedThreadId(resolvedThreadId);
|
|
6852
|
+
});
|
|
6701
6853
|
}
|
|
6702
6854
|
};
|
|
6703
6855
|
connect(agent);
|
|
@@ -6709,7 +6861,8 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6709
6861
|
}, [
|
|
6710
6862
|
resolvedThreadId,
|
|
6711
6863
|
agent,
|
|
6712
|
-
resolvedAgentId
|
|
6864
|
+
resolvedAgentId,
|
|
6865
|
+
providedThreadId
|
|
6713
6866
|
]);
|
|
6714
6867
|
const onSubmitInput = (0, react.useCallback)(async (value) => {
|
|
6715
6868
|
if (selectedAttachments.some((a) => a.status === "uploading")) {
|
|
@@ -6862,6 +7015,22 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6862
7015
|
const toolCallsKey = "toolCalls" in m && Array.isArray(m.toolCalls) ? m.toolCalls.map((tc) => `${tc.id}:${tc.function?.arguments?.length ?? 0}`).join(";") : "";
|
|
6863
7016
|
return `${m.id}:${m.role}:${contentKey}:${toolCallsKey}`;
|
|
6864
7017
|
}).join(",")]);
|
|
7018
|
+
const lastUserMessageId = (0, react.useMemo)(() => {
|
|
7019
|
+
for (let i = messages.length - 1; i >= 0; i--) if (messages[i].role === "user") return messages[i].id;
|
|
7020
|
+
return null;
|
|
7021
|
+
}, [messages]);
|
|
7022
|
+
const [sendNonce, setSendNonce] = (0, react.useState)(0);
|
|
7023
|
+
const prevLastUserMessageIdRef = (0, react.useRef)(lastUserMessageId);
|
|
7024
|
+
(0, react.useEffect)(() => {
|
|
7025
|
+
if (lastUserMessageId && lastUserMessageId !== prevLastUserMessageIdRef.current) {
|
|
7026
|
+
setSendNonce((n) => n + 1);
|
|
7027
|
+
prevLastUserMessageIdRef.current = lastUserMessageId;
|
|
7028
|
+
}
|
|
7029
|
+
}, [lastUserMessageId]);
|
|
7030
|
+
const lastUserMessageState = (0, react.useMemo)(() => ({
|
|
7031
|
+
id: lastUserMessageId,
|
|
7032
|
+
sendNonce
|
|
7033
|
+
}), [lastUserMessageId, sendNonce]);
|
|
6865
7034
|
const RenderedChatView = renderSlot(chatView, CopilotChatView, {
|
|
6866
7035
|
...mergedProps,
|
|
6867
7036
|
messages,
|
|
@@ -6880,7 +7049,9 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6880
7049
|
dragOver,
|
|
6881
7050
|
onDragOver: handleDragOver,
|
|
6882
7051
|
onDragLeave: handleDragLeave,
|
|
6883
|
-
onDrop: handleDrop
|
|
7052
|
+
onDrop: handleDrop,
|
|
7053
|
+
isConnecting,
|
|
7054
|
+
hasExplicitThreadId: !!providedThreadId
|
|
6884
7055
|
});
|
|
6885
7056
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(CopilotChatConfigurationProvider, {
|
|
6886
7057
|
agentId: resolvedAgentId,
|
|
@@ -6915,7 +7086,10 @@ function CopilotChat({ agentId, threadId, labels, chatView, isModalDefaultOpen,
|
|
|
6915
7086
|
},
|
|
6916
7087
|
children: transcriptionError
|
|
6917
7088
|
}),
|
|
6918
|
-
|
|
7089
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(LastUserMessageContext.Provider, {
|
|
7090
|
+
value: lastUserMessageState,
|
|
7091
|
+
children: RenderedChatView
|
|
7092
|
+
})
|
|
6919
7093
|
]
|
|
6920
7094
|
})
|
|
6921
7095
|
});
|
|
@@ -10017,4 +10191,4 @@ Object.defineProperty(exports, 'useToast', {
|
|
|
10017
10191
|
return useToast;
|
|
10018
10192
|
}
|
|
10019
10193
|
});
|
|
10020
|
-
//# sourceMappingURL=copilotkit-
|
|
10194
|
+
//# sourceMappingURL=copilotkit-D5JT2Pu3.cjs.map
|