@copilotkit/react-ui 1.9.2-next.4 → 1.9.2-next.6
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/CHANGELOG.md +17 -0
- package/dist/{chunk-KGKVOUC3.mjs → chunk-2TJK4TTF.mjs} +2 -2
- package/dist/{chunk-GBGU4ZR6.mjs → chunk-AHVYHPVQ.mjs} +2 -2
- package/dist/{chunk-RT4HE74K.mjs → chunk-KQEMBE47.mjs} +6 -4
- package/dist/chunk-KQEMBE47.mjs.map +1 -0
- package/dist/{chunk-XZI6DUGE.mjs → chunk-OMIVNOML.mjs} +3 -3
- package/dist/{chunk-EMIYIMQ6.mjs → chunk-X3LV7OXQ.mjs} +21 -11
- package/dist/chunk-X3LV7OXQ.mjs.map +1 -0
- package/dist/components/chat/Chat.d.ts +2 -1
- package/dist/components/chat/Chat.js +23 -11
- package/dist/components/chat/Chat.js.map +1 -1
- package/dist/components/chat/Chat.mjs +2 -2
- package/dist/components/chat/Input.d.ts +1 -1
- package/dist/components/chat/Input.js +19 -9
- package/dist/components/chat/Input.js.map +1 -1
- package/dist/components/chat/Input.mjs +1 -1
- package/dist/components/chat/Modal.js +23 -11
- package/dist/components/chat/Modal.js.map +1 -1
- package/dist/components/chat/Modal.mjs +3 -3
- package/dist/components/chat/Popup.js +23 -11
- package/dist/components/chat/Popup.js.map +1 -1
- package/dist/components/chat/Popup.mjs +4 -4
- package/dist/components/chat/Sidebar.js +23 -11
- package/dist/components/chat/Sidebar.js.map +1 -1
- package/dist/components/chat/Sidebar.mjs +4 -4
- package/dist/components/chat/index.js +23 -11
- package/dist/components/chat/index.js.map +1 -1
- package/dist/components/chat/index.mjs +5 -5
- package/dist/components/chat/props.d.ts +1 -0
- package/dist/components/chat/props.js.map +1 -1
- package/dist/components/index.js +23 -11
- package/dist/components/index.js.map +1 -1
- package/dist/components/index.mjs +5 -5
- package/dist/index.js +23 -11
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/package.json +4 -4
- package/src/components/chat/Chat.tsx +4 -0
- package/src/components/chat/Input.tsx +21 -11
- package/src/components/chat/props.ts +1 -0
- package/dist/chunk-EMIYIMQ6.mjs.map +0 -1
- package/dist/chunk-RT4HE74K.mjs.map +0 -1
- /package/dist/{chunk-KGKVOUC3.mjs.map → chunk-2TJK4TTF.mjs.map} +0 -0
- /package/dist/{chunk-GBGU4ZR6.mjs.map → chunk-AHVYHPVQ.mjs.map} +0 -0
- /package/dist/{chunk-XZI6DUGE.mjs.map → chunk-OMIVNOML.mjs.map} +0 -0
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
CopilotChat,
|
|
3
3
|
WrappedCopilotChat,
|
|
4
4
|
useCopilotChatLogic
|
|
5
|
-
} from "../../chunk-
|
|
5
|
+
} from "../../chunk-KQEMBE47.mjs";
|
|
6
6
|
import "../../chunk-UKCPOBQM.mjs";
|
|
7
7
|
import "../../chunk-2II3Q27P.mjs";
|
|
8
8
|
import "../../chunk-ULDQXCED.mjs";
|
|
@@ -13,7 +13,7 @@ import "../../chunk-HWMFMBJC.mjs";
|
|
|
13
13
|
import "../../chunk-QGSPTXOV.mjs";
|
|
14
14
|
import "../../chunk-IMBPSLL4.mjs";
|
|
15
15
|
import "../../chunk-PLHTVHUW.mjs";
|
|
16
|
-
import "../../chunk-
|
|
16
|
+
import "../../chunk-X3LV7OXQ.mjs";
|
|
17
17
|
import "../../chunk-CGEAG65D.mjs";
|
|
18
18
|
import "../../chunk-YQFVRDNC.mjs";
|
|
19
19
|
import "../../chunk-YTXEWDNC.mjs";
|
|
@@ -4,6 +4,6 @@ import '@copilotkit/runtime-client-gql';
|
|
|
4
4
|
import '../../types/suggestions.js';
|
|
5
5
|
import 'react';
|
|
6
6
|
|
|
7
|
-
declare const Input: ({ inProgress, onSend, isVisible, onStop, onUpload }: InputProps) => react_jsx_runtime.JSX.Element;
|
|
7
|
+
declare const Input: ({ inProgress, onSend, isVisible, onStop, onUpload, hideStopButton, }: InputProps) => react_jsx_runtime.JSX.Element;
|
|
8
8
|
|
|
9
9
|
export { Input };
|
|
@@ -268,8 +268,15 @@ function PoweredByTag({ showPoweredBy = true }) {
|
|
|
268
268
|
// src/components/chat/Input.tsx
|
|
269
269
|
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
270
270
|
var MAX_NEWLINES = 6;
|
|
271
|
-
var Input = ({
|
|
272
|
-
|
|
271
|
+
var Input = ({
|
|
272
|
+
inProgress,
|
|
273
|
+
onSend,
|
|
274
|
+
isVisible = false,
|
|
275
|
+
onStop,
|
|
276
|
+
onUpload,
|
|
277
|
+
hideStopButton = false
|
|
278
|
+
}) => {
|
|
279
|
+
var _a, _b;
|
|
273
280
|
const context = useChatContext();
|
|
274
281
|
const copilotContext = (0, import_react_core2.useCopilotContext)();
|
|
275
282
|
const showPoweredBy = !((_a = copilotContext.copilotApiConfig) == null ? void 0 : _a.publicApiKey);
|
|
@@ -298,15 +305,18 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
298
305
|
inProgress
|
|
299
306
|
});
|
|
300
307
|
const isInProgress = inProgress || pushToTalkState === "transcribing";
|
|
301
|
-
const buttonIcon = isInProgress ? context.icons.stopIcon : context.icons.sendIcon;
|
|
308
|
+
const buttonIcon = isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;
|
|
302
309
|
const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
|
|
303
|
-
const canSend = () => {
|
|
310
|
+
const canSend = (0, import_react4.useMemo)(() => {
|
|
304
311
|
var _a2;
|
|
305
312
|
const interruptEvent = (_a2 = copilotContext.langGraphInterruptAction) == null ? void 0 : _a2.event;
|
|
306
313
|
const interruptInProgress = (interruptEvent == null ? void 0 : interruptEvent.name) === "LangGraphInterruptEvent" && !(interruptEvent == null ? void 0 : interruptEvent.response);
|
|
307
|
-
return
|
|
308
|
-
};
|
|
309
|
-
const
|
|
314
|
+
return !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress;
|
|
315
|
+
}, [(_b = copilotContext.langGraphInterruptAction) == null ? void 0 : _b.event, isInProgress, text, pushToTalkState]);
|
|
316
|
+
const canStop = (0, import_react4.useMemo)(() => {
|
|
317
|
+
return isInProgress && !hideStopButton;
|
|
318
|
+
}, [isInProgress, hideStopButton]);
|
|
319
|
+
const sendDisabled = !canSend && !canStop;
|
|
310
320
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `copilotKitInputContainer ${showPoweredBy ? "poweredByContainer" : ""}`, children: [
|
|
311
321
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
|
|
312
322
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
@@ -321,7 +331,7 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
321
331
|
onKeyDown: (event) => {
|
|
322
332
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
323
333
|
event.preventDefault();
|
|
324
|
-
if (canSend
|
|
334
|
+
if (canSend) {
|
|
325
335
|
send();
|
|
326
336
|
}
|
|
327
337
|
}
|
|
@@ -343,7 +353,7 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
343
353
|
"button",
|
|
344
354
|
{
|
|
345
355
|
disabled: sendDisabled,
|
|
346
|
-
onClick: isInProgress ? onStop : send,
|
|
356
|
+
onClick: isInProgress && !hideStopButton ? onStop : send,
|
|
347
357
|
"data-copilotkit-in-progress": inProgress,
|
|
348
358
|
"data-test-id": inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready",
|
|
349
359
|
className: "copilotKitInputControlButton",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/components/chat/Input.tsx","../../../src/components/chat/ChatContext.tsx","../../../src/components/chat/Textarea.tsx","../../../src/hooks/use-push-to-talk.tsx","../../../src/hooks/use-dark-mode.ts","../../../src/components/chat/PoweredByTag.tsx"],"sourcesContent":["import React, { useRef, useState } from \"react\";\nimport { InputProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport AutoResizingTextarea from \"./Textarea\";\nimport { usePushToTalk } from \"../../hooks/use-push-to-talk\";\nimport { useCopilotContext } from \"@copilotkit/react-core\";\nimport { PoweredByTag } from \"./PoweredByTag\";\n\nconst MAX_NEWLINES = 6;\n\nexport const Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }: InputProps) => {\n const context = useChatContext();\n const copilotContext = useCopilotContext();\n\n const showPoweredBy = !copilotContext.copilotApiConfig?.publicApiKey;\n\n const pushToTalkConfigured =\n copilotContext.copilotApiConfig.textToSpeechUrl !== undefined &&\n copilotContext.copilotApiConfig.transcribeAudioUrl !== undefined;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement;\n\n // If the user clicked a button or inside a button, don't focus the textarea\n if (target.closest(\"button\")) return;\n\n // If the user clicked the textarea, do nothing (it's already focused)\n if (target.tagName === \"TEXTAREA\") return;\n\n // Otherwise, focus the textarea\n textareaRef.current?.focus();\n };\n\n const [text, setText] = useState(\"\");\n const send = () => {\n if (inProgress) return;\n onSend(text);\n setText(\"\");\n\n textareaRef.current?.focus();\n };\n\n // tylerslaton:\n //\n // This scrolls CopilotKit into view always. Reading the commit history, it was likely\n // added to fix a bug but it is causing issues now.\n //\n // For the future, if we want this behavior again, we will need to find a way to do it without\n // forcing CopilotKit to always be in view. This code causes this because focusing an element\n // in most browsers will scroll that element into view.\n //\n // useEffect(() => {\n // if (isVisible) {\n // textareaRef.current?.focus();\n // }\n // }, [isVisible]);\n\n const { pushToTalkState, setPushToTalkState } = usePushToTalk({\n sendFunction: onSend,\n inProgress,\n });\n\n const isInProgress = inProgress || pushToTalkState === \"transcribing\";\n const buttonIcon = isInProgress ? context.icons.stopIcon : context.icons.sendIcon;\n const showPushToTalk =\n pushToTalkConfigured &&\n (pushToTalkState === \"idle\" || pushToTalkState === \"recording\") &&\n !inProgress;\n\n const canSend = () => {\n const interruptEvent = copilotContext.langGraphInterruptAction?.event;\n const interruptInProgress =\n interruptEvent?.name === \"LangGraphInterruptEvent\" && !interruptEvent?.response;\n\n return (\n (isInProgress || (!isInProgress && text.trim().length > 0)) &&\n pushToTalkState === \"idle\" &&\n !interruptInProgress\n );\n };\n\n const sendDisabled = !canSend();\n\n return (\n <div className={`copilotKitInputContainer ${showPoweredBy ? \"poweredByContainer\" : \"\"}`}>\n <div className=\"copilotKitInput\" onClick={handleDivClick}>\n <AutoResizingTextarea\n ref={textareaRef}\n placeholder={context.labels.placeholder}\n autoFocus={false}\n maxRows={MAX_NEWLINES}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n if (canSend()) {\n send();\n }\n }\n }}\n />\n <div className=\"copilotKitInputControls\">\n {onUpload && (\n <button onClick={onUpload} className=\"copilotKitInputControlButton\">\n {context.icons.uploadIcon}\n </button>\n )}\n\n <div style={{ flexGrow: 1 }} />\n\n {showPushToTalk && (\n <button\n onClick={() =>\n setPushToTalkState(pushToTalkState === \"idle\" ? \"recording\" : \"transcribing\")\n }\n className={\n pushToTalkState === \"recording\"\n ? \"copilotKitInputControlButton copilotKitPushToTalkRecording\"\n : \"copilotKitInputControlButton\"\n }\n >\n {context.icons.pushToTalkIcon}\n </button>\n )}\n <button\n disabled={sendDisabled}\n onClick={isInProgress ? onStop : send}\n data-copilotkit-in-progress={inProgress}\n data-test-id={inProgress ? \"copilot-chat-request-in-progress\" : \"copilot-chat-ready\"}\n className=\"copilotKitInputControlButton\"\n >\n {buttonIcon}\n </button>\n </div>\n </div>\n <PoweredByTag showPoweredBy={showPoweredBy} />\n </div>\n );\n};\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\nimport { ThumbsDownIcon, ThumbsUpIcon } from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n\n /**\n * The icons to use for copy assistant response\n * @default <CopyIcon />\n */\n\n copyIcon?: React.ReactNode;\n\n /**\n * The icon to use for thumbs up/response approval.\n * @default <ThumbsUpIcon />\n */\n\n thumbsUpIcon?: React.ReactNode;\n\n /**\n * The icon to use for thumbs down/response rejection.\n * @default <ThumbsDownIcon />\n */\n\n thumbsDownIcon?: React.ReactNode;\n\n /**\n * The icon to use for the upload button.\n * @default <UploadIcon />\n */\n uploadIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n\n /**\n * The label for the copy button.\n * @default \"Copy to clipboard\"\n */\n copyToClipboard?: string;\n\n /**\n * The label for the thumbs up button.\n * @default \"Thumbs up\"\n */\n thumbsUp?: string;\n\n /**\n * The label for the thumbs down button.\n * @default \"Thumbs down\"\n */\n thumbsDown?: string;\n\n /**\n * The text to display when content is copied.\n * @default \"Copied!\"\n */\n copied?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n copyToClipboard: \"Copy to clipboard\",\n thumbsUp: \"Thumbs up\",\n thumbsDown: \"Thumbs down\",\n copied: \"Copied!\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.MicrophoneIcon,\n copyIcon: DefaultIcons.CopyIcon,\n thumbsUpIcon: DefaultIcons.ThumbsUpIcon,\n thumbsDownIcon: DefaultIcons.ThumbsDownIcon,\n uploadIcon: DefaultIcons.UploadIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n","import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from \"react\";\n\ninterface AutoResizingTextareaProps {\n maxRows?: number;\n placeholder?: string;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n autoFocus?: boolean;\n}\n\nconst AutoResizingTextarea = forwardRef<HTMLTextAreaElement, AutoResizingTextareaProps>(\n ({ maxRows = 1, placeholder, value, onChange, onKeyDown, autoFocus }, ref) => {\n const internalTextareaRef = useRef<HTMLTextAreaElement>(null);\n const [maxHeight, setMaxHeight] = useState<number>(0);\n\n useImperativeHandle(ref, () => internalTextareaRef.current as HTMLTextAreaElement);\n\n useEffect(() => {\n const calculateMaxHeight = () => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n const singleRowHeight = textarea.scrollHeight;\n setMaxHeight(singleRowHeight * maxRows);\n if (autoFocus) {\n textarea.focus();\n }\n }\n };\n\n calculateMaxHeight();\n }, [maxRows]);\n\n useEffect(() => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;\n }\n }, [value, maxHeight]);\n\n return (\n <textarea\n ref={internalTextareaRef}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n style={{\n overflow: \"auto\",\n resize: \"none\",\n maxHeight: `${maxHeight}px`,\n }}\n rows={1}\n />\n );\n },\n);\n\nexport default AutoResizingTextarea;\n","import { useCopilotContext, useCopilotMessagesContext } from \"@copilotkit/react-core\";\nimport { Message, TextMessage } from \"@copilotkit/runtime-client-gql\";\nimport { MutableRefObject, useEffect, useRef, useState } from \"react\";\n\nexport const checkMicrophonePermission = async () => {\n try {\n const permissionStatus = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n if (permissionStatus.state === \"granted\") {\n return true;\n } else {\n return false;\n }\n } catch (err) {\n console.error(\"Error checking microphone permission\", err);\n }\n};\n\nexport const requestMicAndPlaybackPermission = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const audioContext = new window.AudioContext();\n await audioContext.resume();\n return { stream, audioContext };\n } catch (err) {\n console.error(\"Error requesting microphone and playback permissions\", err);\n return null;\n }\n};\n\nconst startRecording = async (\n mediaStreamRef: MutableRefObject<MediaStream | null>,\n mediaRecorderRef: MutableRefObject<MediaRecorder | null>,\n audioContextRef: MutableRefObject<AudioContext | null>,\n recordedChunks: Blob[],\n onStop: () => void,\n) => {\n if (!mediaStreamRef.current || !audioContextRef.current) {\n mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });\n audioContextRef.current = new window.AudioContext();\n await audioContextRef.current.resume();\n }\n\n mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current!);\n mediaRecorderRef.current.start(1000);\n mediaRecorderRef.current.ondataavailable = (event) => {\n recordedChunks.push(event.data);\n };\n mediaRecorderRef.current.onstop = onStop;\n};\n\nconst stopRecording = (mediaRecorderRef: MutableRefObject<MediaRecorder | null>) => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== \"inactive\") {\n mediaRecorderRef.current.stop();\n }\n};\n\nconst transcribeAudio = async (recordedChunks: Blob[], transcribeAudioUrl: string) => {\n const completeBlob = new Blob(recordedChunks, { type: \"audio/mp4\" });\n const formData = new FormData();\n formData.append(\"file\", completeBlob, \"recording.mp4\");\n\n const response = await fetch(transcribeAudioUrl, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n\n const transcription = await response.json();\n return transcription.text;\n};\n\nconst playAudioResponse = (text: string, textToSpeechUrl: string, audioContext: AudioContext) => {\n const encodedText = encodeURIComponent(text);\n const url = `${textToSpeechUrl}?text=${encodedText}`;\n\n fetch(url)\n .then((response) => response.arrayBuffer())\n .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))\n .then((audioBuffer) => {\n const source = audioContext.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(audioContext.destination);\n source.start(0);\n })\n .catch((error) => {\n console.error(\"Error with decoding audio data\", error);\n });\n};\n\nexport type PushToTalkState = \"idle\" | \"recording\" | \"transcribing\";\n\nexport type SendFunction = (text: string) => Promise<Message>;\n\nexport const usePushToTalk = ({\n sendFunction,\n inProgress,\n}: {\n sendFunction: SendFunction;\n inProgress: boolean;\n}) => {\n const [pushToTalkState, setPushToTalkState] = useState<PushToTalkState>(\"idle\");\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioContextRef = useRef<AudioContext | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedChunks = useRef<Blob[]>([]);\n const generalContext = useCopilotContext();\n const messagesContext = useCopilotMessagesContext();\n const context = { ...generalContext, ...messagesContext };\n const [startReadingFromMessageId, setStartReadingFromMessageId] = useState<string | null>(null);\n\n useEffect(() => {\n if (pushToTalkState === \"recording\") {\n startRecording(\n mediaStreamRef,\n mediaRecorderRef,\n audioContextRef,\n recordedChunks.current,\n () => {\n setPushToTalkState(\"transcribing\");\n },\n );\n } else {\n stopRecording(mediaRecorderRef);\n if (pushToTalkState === \"transcribing\") {\n transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl!).then(\n async (transcription) => {\n recordedChunks.current = [];\n setPushToTalkState(\"idle\");\n const message = await sendFunction(transcription);\n setStartReadingFromMessageId(message.id);\n },\n );\n }\n }\n\n return () => {\n stopRecording(mediaRecorderRef);\n };\n }, [pushToTalkState]);\n\n useEffect(() => {\n if (inProgress === false && startReadingFromMessageId) {\n const lastMessageIndex = context.messages.findIndex(\n (message) => message.id === startReadingFromMessageId,\n );\n\n const messagesAfterLast = context.messages\n .slice(lastMessageIndex + 1)\n .filter(\n (message) => message.isTextMessage() && message.role === \"assistant\",\n ) as TextMessage[];\n\n const text = messagesAfterLast.map((message) => message.content).join(\"\\n\");\n playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl!, audioContextRef.current!);\n\n setStartReadingFromMessageId(null);\n }\n }, [startReadingFromMessageId, inProgress]);\n\n return { pushToTalkState, setPushToTalkState };\n};\n","export const useDarkMode = () => {\n if (typeof window === \"undefined\") return false;\n return (\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\") ||\n document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n document.body.getAttribute(\"data-theme\") === \"dark\" ||\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n );\n};\n","import React from \"react\";\nimport { useDarkMode } from \"../../hooks/use-dark-mode\";\n\nexport function PoweredByTag({ showPoweredBy = true }: { showPoweredBy?: boolean }) {\n const isDark = useDarkMode();\n\n if (!showPoweredBy) {\n return null;\n }\n\n const poweredByStyle = {\n visibility: \"visible\",\n display: \"block\",\n position: \"static\",\n textAlign: \"center\",\n fontSize: \"12px\",\n padding: \"3px 0\",\n color: isDark ? \"rgb(69, 69, 69)\" : \"rgb(214, 214, 214)\",\n };\n\n return (\n <div>\n {/*@ts-expect-error -- expecting position not to be a string, but it can be.*/}\n <p className=\"poweredBy\" style={poweredByStyle}>\n Powered by CopilotKit\n </p>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","React","import_react","import_jsx_runtime","import_react","import_react_core","import_jsx_runtime","import_jsx_runtime","_a"]}
|
|
1
|
+
{"version":3,"sources":["../../../src/components/chat/Input.tsx","../../../src/components/chat/ChatContext.tsx","../../../src/components/chat/Textarea.tsx","../../../src/hooks/use-push-to-talk.tsx","../../../src/hooks/use-dark-mode.ts","../../../src/components/chat/PoweredByTag.tsx"],"sourcesContent":["import React, { useMemo, useRef, useState } from \"react\";\nimport { InputProps } from \"./props\";\nimport { useChatContext } from \"./ChatContext\";\nimport AutoResizingTextarea from \"./Textarea\";\nimport { usePushToTalk } from \"../../hooks/use-push-to-talk\";\nimport { useCopilotContext } from \"@copilotkit/react-core\";\nimport { PoweredByTag } from \"./PoweredByTag\";\n\nconst MAX_NEWLINES = 6;\n\nexport const Input = ({\n inProgress,\n onSend,\n isVisible = false,\n onStop,\n onUpload,\n hideStopButton = false,\n}: InputProps) => {\n const context = useChatContext();\n const copilotContext = useCopilotContext();\n\n const showPoweredBy = !copilotContext.copilotApiConfig?.publicApiKey;\n\n const pushToTalkConfigured =\n copilotContext.copilotApiConfig.textToSpeechUrl !== undefined &&\n copilotContext.copilotApiConfig.transcribeAudioUrl !== undefined;\n\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n\n const handleDivClick = (event: React.MouseEvent<HTMLDivElement>) => {\n const target = event.target as HTMLElement;\n\n // If the user clicked a button or inside a button, don't focus the textarea\n if (target.closest(\"button\")) return;\n\n // If the user clicked the textarea, do nothing (it's already focused)\n if (target.tagName === \"TEXTAREA\") return;\n\n // Otherwise, focus the textarea\n textareaRef.current?.focus();\n };\n\n const [text, setText] = useState(\"\");\n const send = () => {\n if (inProgress) return;\n onSend(text);\n setText(\"\");\n\n textareaRef.current?.focus();\n };\n\n // tylerslaton:\n //\n // This scrolls CopilotKit into view always. Reading the commit history, it was likely\n // added to fix a bug but it is causing issues now.\n //\n // For the future, if we want this behavior again, we will need to find a way to do it without\n // forcing CopilotKit to always be in view. This code causes this because focusing an element\n // in most browsers will scroll that element into view.\n //\n // useEffect(() => {\n // if (isVisible) {\n // textareaRef.current?.focus();\n // }\n // }, [isVisible]);\n\n const { pushToTalkState, setPushToTalkState } = usePushToTalk({\n sendFunction: onSend,\n inProgress,\n });\n\n const isInProgress = inProgress || pushToTalkState === \"transcribing\";\n const buttonIcon =\n isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;\n const showPushToTalk =\n pushToTalkConfigured &&\n (pushToTalkState === \"idle\" || pushToTalkState === \"recording\") &&\n !inProgress;\n\n const canSend = useMemo(() => {\n const interruptEvent = copilotContext.langGraphInterruptAction?.event;\n const interruptInProgress =\n interruptEvent?.name === \"LangGraphInterruptEvent\" && !interruptEvent?.response;\n\n return (\n !isInProgress && text.trim().length > 0 && pushToTalkState === \"idle\" && !interruptInProgress\n );\n }, [copilotContext.langGraphInterruptAction?.event, isInProgress, text, pushToTalkState]);\n\n const canStop = useMemo(() => {\n return isInProgress && !hideStopButton;\n }, [isInProgress, hideStopButton]);\n\n const sendDisabled = !canSend && !canStop;\n\n return (\n <div className={`copilotKitInputContainer ${showPoweredBy ? \"poweredByContainer\" : \"\"}`}>\n <div className=\"copilotKitInput\" onClick={handleDivClick}>\n <AutoResizingTextarea\n ref={textareaRef}\n placeholder={context.labels.placeholder}\n autoFocus={false}\n maxRows={MAX_NEWLINES}\n value={text}\n onChange={(event) => setText(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === \"Enter\" && !event.shiftKey) {\n event.preventDefault();\n if (canSend) {\n send();\n }\n }\n }}\n />\n <div className=\"copilotKitInputControls\">\n {onUpload && (\n <button onClick={onUpload} className=\"copilotKitInputControlButton\">\n {context.icons.uploadIcon}\n </button>\n )}\n\n <div style={{ flexGrow: 1 }} />\n\n {showPushToTalk && (\n <button\n onClick={() =>\n setPushToTalkState(pushToTalkState === \"idle\" ? \"recording\" : \"transcribing\")\n }\n className={\n pushToTalkState === \"recording\"\n ? \"copilotKitInputControlButton copilotKitPushToTalkRecording\"\n : \"copilotKitInputControlButton\"\n }\n >\n {context.icons.pushToTalkIcon}\n </button>\n )}\n <button\n disabled={sendDisabled}\n onClick={isInProgress && !hideStopButton ? onStop : send}\n data-copilotkit-in-progress={inProgress}\n data-test-id={inProgress ? \"copilot-chat-request-in-progress\" : \"copilot-chat-ready\"}\n className=\"copilotKitInputControlButton\"\n >\n {buttonIcon}\n </button>\n </div>\n </div>\n <PoweredByTag showPoweredBy={showPoweredBy} />\n </div>\n );\n};\n","import React, { useMemo, useState } from \"react\";\nimport * as DefaultIcons from \"./Icons\";\nimport { ThumbsDownIcon, ThumbsUpIcon } from \"./Icons\";\n\n/**\n * Icons for CopilotChat component.\n */\nexport interface CopilotChatIcons {\n /**\n * The icon to use for the open chat button.\n * @default <OpenIcon />\n */\n openIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button.\n * @default <CloseIcon />\n */\n closeIcon?: React.ReactNode;\n\n /**\n * The icon to use for the close chat button in the header.\n * @default <HeaderCloseIcon />\n */\n headerCloseIcon?: React.ReactNode;\n\n /**\n * The icon to use for the send button.\n * @default <SendIcon />\n */\n sendIcon?: React.ReactNode;\n\n /**\n * The icon to use for the activity indicator.\n * @default <ActivityIcon />\n */\n activityIcon?: React.ReactNode;\n\n /**\n * The icon to use for the spinner.\n * @default <SpinnerIcon />\n */\n spinnerIcon?: React.ReactNode;\n\n /**\n * The icon to use for the stop button.\n * @default <StopIcon />\n */\n stopIcon?: React.ReactNode;\n\n /**\n * The icon to use for the regenerate button.\n * @default <RegenerateIcon />\n */\n regenerateIcon?: React.ReactNode;\n\n /**\n * The icons to use for push to talk.\n * @default <PushToTalkIcon />\n */\n\n pushToTalkIcon?: React.ReactNode;\n\n /**\n * The icons to use for copy assistant response\n * @default <CopyIcon />\n */\n\n copyIcon?: React.ReactNode;\n\n /**\n * The icon to use for thumbs up/response approval.\n * @default <ThumbsUpIcon />\n */\n\n thumbsUpIcon?: React.ReactNode;\n\n /**\n * The icon to use for thumbs down/response rejection.\n * @default <ThumbsDownIcon />\n */\n\n thumbsDownIcon?: React.ReactNode;\n\n /**\n * The icon to use for the upload button.\n * @default <UploadIcon />\n */\n uploadIcon?: React.ReactNode;\n}\n\n/**\n * Labels for CopilotChat component.\n */\nexport interface CopilotChatLabels {\n /**\n * The initial message(s) to display in the chat window.\n */\n initial?: string | string[];\n\n /**\n * The title to display in the header.\n * @default \"CopilotKit\"\n */\n title?: string;\n\n /**\n * The placeholder to display in the input.\n * @default \"Type a message...\"\n */\n placeholder?: string;\n\n /**\n * The message to display when an error occurs.\n * @default \"❌ An error occurred. Please try again.\"\n */\n error?: string;\n\n /**\n * The label to display on the stop button.\n * @default \"Stop generating\"\n */\n stopGenerating?: string;\n\n /**\n * The label to display on the regenerate button.\n * @default \"Regenerate response\"\n */\n regenerateResponse?: string;\n\n /**\n * The label for the copy button.\n * @default \"Copy to clipboard\"\n */\n copyToClipboard?: string;\n\n /**\n * The label for the thumbs up button.\n * @default \"Thumbs up\"\n */\n thumbsUp?: string;\n\n /**\n * The label for the thumbs down button.\n * @default \"Thumbs down\"\n */\n thumbsDown?: string;\n\n /**\n * The text to display when content is copied.\n * @default \"Copied!\"\n */\n copied?: string;\n}\n\ninterface ChatContext {\n labels: Required<CopilotChatLabels>;\n icons: Required<CopilotChatIcons>;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContext = React.createContext<ChatContext | undefined>(undefined);\n\nexport function useChatContext(): ChatContext {\n const context = React.useContext(ChatContext);\n if (context === undefined) {\n throw new Error(\n \"Context not found. Did you forget to wrap your app in a <ChatContextProvider> component?\",\n );\n }\n return context;\n}\n\ninterface ChatContextProps {\n // temperature?: number;\n // instructions?: string;\n // maxFeedback?: number;\n labels?: CopilotChatLabels;\n icons?: CopilotChatIcons;\n children?: React.ReactNode;\n open: boolean;\n setOpen: (open: boolean) => void;\n}\n\nexport const ChatContextProvider = ({\n // temperature,\n // instructions,\n // maxFeedback,\n labels,\n icons,\n children,\n open,\n setOpen,\n}: ChatContextProps) => {\n const memoizedLabels = useMemo(\n () => ({\n ...{\n initial: \"\",\n title: \"CopilotKit\",\n placeholder: \"Type a message...\",\n error: \"❌ An error occurred. Please try again.\",\n stopGenerating: \"Stop generating\",\n regenerateResponse: \"Regenerate response\",\n copyToClipboard: \"Copy to clipboard\",\n thumbsUp: \"Thumbs up\",\n thumbsDown: \"Thumbs down\",\n copied: \"Copied!\",\n },\n ...labels,\n }),\n [labels],\n );\n\n const memoizedIcons = useMemo(\n () => ({\n ...{\n openIcon: DefaultIcons.OpenIcon,\n closeIcon: DefaultIcons.CloseIcon,\n headerCloseIcon: DefaultIcons.HeaderCloseIcon,\n sendIcon: DefaultIcons.SendIcon,\n activityIcon: DefaultIcons.ActivityIcon,\n spinnerIcon: DefaultIcons.SpinnerIcon,\n stopIcon: DefaultIcons.StopIcon,\n regenerateIcon: DefaultIcons.RegenerateIcon,\n pushToTalkIcon: DefaultIcons.MicrophoneIcon,\n copyIcon: DefaultIcons.CopyIcon,\n thumbsUpIcon: DefaultIcons.ThumbsUpIcon,\n thumbsDownIcon: DefaultIcons.ThumbsDownIcon,\n uploadIcon: DefaultIcons.UploadIcon,\n },\n ...icons,\n }),\n [icons],\n );\n\n const context = useMemo(\n () => ({\n labels: memoizedLabels,\n icons: memoizedIcons,\n open,\n setOpen,\n }),\n [memoizedLabels, memoizedIcons, open, setOpen],\n );\n\n return <ChatContext.Provider value={context}>{children}</ChatContext.Provider>;\n};\n","import React, { useState, useRef, useEffect, forwardRef, useImperativeHandle } from \"react\";\n\ninterface AutoResizingTextareaProps {\n maxRows?: number;\n placeholder?: string;\n value: string;\n onChange: (event: React.ChangeEvent<HTMLTextAreaElement>) => void;\n onKeyDown?: (event: React.KeyboardEvent<HTMLTextAreaElement>) => void;\n autoFocus?: boolean;\n}\n\nconst AutoResizingTextarea = forwardRef<HTMLTextAreaElement, AutoResizingTextareaProps>(\n ({ maxRows = 1, placeholder, value, onChange, onKeyDown, autoFocus }, ref) => {\n const internalTextareaRef = useRef<HTMLTextAreaElement>(null);\n const [maxHeight, setMaxHeight] = useState<number>(0);\n\n useImperativeHandle(ref, () => internalTextareaRef.current as HTMLTextAreaElement);\n\n useEffect(() => {\n const calculateMaxHeight = () => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n const singleRowHeight = textarea.scrollHeight;\n setMaxHeight(singleRowHeight * maxRows);\n if (autoFocus) {\n textarea.focus();\n }\n }\n };\n\n calculateMaxHeight();\n }, [maxRows]);\n\n useEffect(() => {\n const textarea = internalTextareaRef.current;\n if (textarea) {\n textarea.style.height = \"auto\";\n textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;\n }\n }, [value, maxHeight]);\n\n return (\n <textarea\n ref={internalTextareaRef}\n value={value}\n onChange={onChange}\n onKeyDown={onKeyDown}\n placeholder={placeholder}\n style={{\n overflow: \"auto\",\n resize: \"none\",\n maxHeight: `${maxHeight}px`,\n }}\n rows={1}\n />\n );\n },\n);\n\nexport default AutoResizingTextarea;\n","import { useCopilotContext, useCopilotMessagesContext } from \"@copilotkit/react-core\";\nimport { Message, TextMessage } from \"@copilotkit/runtime-client-gql\";\nimport { MutableRefObject, useEffect, useRef, useState } from \"react\";\n\nexport const checkMicrophonePermission = async () => {\n try {\n const permissionStatus = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n if (permissionStatus.state === \"granted\") {\n return true;\n } else {\n return false;\n }\n } catch (err) {\n console.error(\"Error checking microphone permission\", err);\n }\n};\n\nexport const requestMicAndPlaybackPermission = async () => {\n try {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n const audioContext = new window.AudioContext();\n await audioContext.resume();\n return { stream, audioContext };\n } catch (err) {\n console.error(\"Error requesting microphone and playback permissions\", err);\n return null;\n }\n};\n\nconst startRecording = async (\n mediaStreamRef: MutableRefObject<MediaStream | null>,\n mediaRecorderRef: MutableRefObject<MediaRecorder | null>,\n audioContextRef: MutableRefObject<AudioContext | null>,\n recordedChunks: Blob[],\n onStop: () => void,\n) => {\n if (!mediaStreamRef.current || !audioContextRef.current) {\n mediaStreamRef.current = await navigator.mediaDevices.getUserMedia({ audio: true });\n audioContextRef.current = new window.AudioContext();\n await audioContextRef.current.resume();\n }\n\n mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current!);\n mediaRecorderRef.current.start(1000);\n mediaRecorderRef.current.ondataavailable = (event) => {\n recordedChunks.push(event.data);\n };\n mediaRecorderRef.current.onstop = onStop;\n};\n\nconst stopRecording = (mediaRecorderRef: MutableRefObject<MediaRecorder | null>) => {\n if (mediaRecorderRef.current && mediaRecorderRef.current.state !== \"inactive\") {\n mediaRecorderRef.current.stop();\n }\n};\n\nconst transcribeAudio = async (recordedChunks: Blob[], transcribeAudioUrl: string) => {\n const completeBlob = new Blob(recordedChunks, { type: \"audio/mp4\" });\n const formData = new FormData();\n formData.append(\"file\", completeBlob, \"recording.mp4\");\n\n const response = await fetch(transcribeAudioUrl, {\n method: \"POST\",\n body: formData,\n });\n\n if (!response.ok) {\n throw new Error(`Error: ${response.statusText}`);\n }\n\n const transcription = await response.json();\n return transcription.text;\n};\n\nconst playAudioResponse = (text: string, textToSpeechUrl: string, audioContext: AudioContext) => {\n const encodedText = encodeURIComponent(text);\n const url = `${textToSpeechUrl}?text=${encodedText}`;\n\n fetch(url)\n .then((response) => response.arrayBuffer())\n .then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer))\n .then((audioBuffer) => {\n const source = audioContext.createBufferSource();\n source.buffer = audioBuffer;\n source.connect(audioContext.destination);\n source.start(0);\n })\n .catch((error) => {\n console.error(\"Error with decoding audio data\", error);\n });\n};\n\nexport type PushToTalkState = \"idle\" | \"recording\" | \"transcribing\";\n\nexport type SendFunction = (text: string) => Promise<Message>;\n\nexport const usePushToTalk = ({\n sendFunction,\n inProgress,\n}: {\n sendFunction: SendFunction;\n inProgress: boolean;\n}) => {\n const [pushToTalkState, setPushToTalkState] = useState<PushToTalkState>(\"idle\");\n const mediaStreamRef = useRef<MediaStream | null>(null);\n const audioContextRef = useRef<AudioContext | null>(null);\n const mediaRecorderRef = useRef<MediaRecorder | null>(null);\n const recordedChunks = useRef<Blob[]>([]);\n const generalContext = useCopilotContext();\n const messagesContext = useCopilotMessagesContext();\n const context = { ...generalContext, ...messagesContext };\n const [startReadingFromMessageId, setStartReadingFromMessageId] = useState<string | null>(null);\n\n useEffect(() => {\n if (pushToTalkState === \"recording\") {\n startRecording(\n mediaStreamRef,\n mediaRecorderRef,\n audioContextRef,\n recordedChunks.current,\n () => {\n setPushToTalkState(\"transcribing\");\n },\n );\n } else {\n stopRecording(mediaRecorderRef);\n if (pushToTalkState === \"transcribing\") {\n transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl!).then(\n async (transcription) => {\n recordedChunks.current = [];\n setPushToTalkState(\"idle\");\n const message = await sendFunction(transcription);\n setStartReadingFromMessageId(message.id);\n },\n );\n }\n }\n\n return () => {\n stopRecording(mediaRecorderRef);\n };\n }, [pushToTalkState]);\n\n useEffect(() => {\n if (inProgress === false && startReadingFromMessageId) {\n const lastMessageIndex = context.messages.findIndex(\n (message) => message.id === startReadingFromMessageId,\n );\n\n const messagesAfterLast = context.messages\n .slice(lastMessageIndex + 1)\n .filter(\n (message) => message.isTextMessage() && message.role === \"assistant\",\n ) as TextMessage[];\n\n const text = messagesAfterLast.map((message) => message.content).join(\"\\n\");\n playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl!, audioContextRef.current!);\n\n setStartReadingFromMessageId(null);\n }\n }, [startReadingFromMessageId, inProgress]);\n\n return { pushToTalkState, setPushToTalkState };\n};\n","export const useDarkMode = () => {\n if (typeof window === \"undefined\") return false;\n return (\n document.documentElement.classList.contains(\"dark\") ||\n document.body.classList.contains(\"dark\") ||\n document.documentElement.getAttribute(\"data-theme\") === \"dark\" ||\n document.body.getAttribute(\"data-theme\") === \"dark\" ||\n window.matchMedia(\"(prefers-color-scheme: dark)\").matches\n );\n};\n","import React from \"react\";\nimport { useDarkMode } from \"../../hooks/use-dark-mode\";\n\nexport function PoweredByTag({ showPoweredBy = true }: { showPoweredBy?: boolean }) {\n const isDark = useDarkMode();\n\n if (!showPoweredBy) {\n return null;\n }\n\n const poweredByStyle = {\n visibility: \"visible\",\n display: \"block\",\n position: \"static\",\n textAlign: \"center\",\n fontSize: \"12px\",\n padding: \"3px 0\",\n color: isDark ? \"rgb(69, 69, 69)\" : \"rgb(214, 214, 214)\",\n };\n\n return (\n <div>\n {/*@ts-expect-error -- expecting position not to be a string, but it can be.*/}\n <p className=\"poweredBy\" style={poweredByStyle}>\n Powered by CopilotKit\n </p>\n </div>\n );\n}\n"],"mappings":"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","names":["import_react","React","import_react","import_jsx_runtime","import_react","import_react_core","import_jsx_runtime","import_jsx_runtime","_a"]}
|
|
@@ -1414,8 +1414,15 @@ function PoweredByTag({ showPoweredBy = true }) {
|
|
|
1414
1414
|
// src/components/chat/Input.tsx
|
|
1415
1415
|
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
1416
1416
|
var MAX_NEWLINES = 6;
|
|
1417
|
-
var Input = ({
|
|
1418
|
-
|
|
1417
|
+
var Input = ({
|
|
1418
|
+
inProgress,
|
|
1419
|
+
onSend,
|
|
1420
|
+
isVisible = false,
|
|
1421
|
+
onStop,
|
|
1422
|
+
onUpload,
|
|
1423
|
+
hideStopButton = false
|
|
1424
|
+
}) => {
|
|
1425
|
+
var _a, _b;
|
|
1419
1426
|
const context = useChatContext();
|
|
1420
1427
|
const copilotContext = (0, import_react_core6.useCopilotContext)();
|
|
1421
1428
|
const showPoweredBy = !((_a = copilotContext.copilotApiConfig) == null ? void 0 : _a.publicApiKey);
|
|
@@ -1444,15 +1451,18 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
1444
1451
|
inProgress
|
|
1445
1452
|
});
|
|
1446
1453
|
const isInProgress = inProgress || pushToTalkState === "transcribing";
|
|
1447
|
-
const buttonIcon = isInProgress ? context.icons.stopIcon : context.icons.sendIcon;
|
|
1454
|
+
const buttonIcon = isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;
|
|
1448
1455
|
const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
|
|
1449
|
-
const canSend = () => {
|
|
1456
|
+
const canSend = (0, import_react9.useMemo)(() => {
|
|
1450
1457
|
var _a2;
|
|
1451
1458
|
const interruptEvent = (_a2 = copilotContext.langGraphInterruptAction) == null ? void 0 : _a2.event;
|
|
1452
1459
|
const interruptInProgress = (interruptEvent == null ? void 0 : interruptEvent.name) === "LangGraphInterruptEvent" && !(interruptEvent == null ? void 0 : interruptEvent.response);
|
|
1453
|
-
return
|
|
1454
|
-
};
|
|
1455
|
-
const
|
|
1460
|
+
return !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress;
|
|
1461
|
+
}, [(_b = copilotContext.langGraphInterruptAction) == null ? void 0 : _b.event, isInProgress, text, pushToTalkState]);
|
|
1462
|
+
const canStop = (0, import_react9.useMemo)(() => {
|
|
1463
|
+
return isInProgress && !hideStopButton;
|
|
1464
|
+
}, [isInProgress, hideStopButton]);
|
|
1465
|
+
const sendDisabled = !canSend && !canStop;
|
|
1456
1466
|
return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `copilotKitInputContainer ${showPoweredBy ? "poweredByContainer" : ""}`, children: [
|
|
1457
1467
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
|
|
1458
1468
|
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
@@ -1467,7 +1477,7 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
1467
1477
|
onKeyDown: (event) => {
|
|
1468
1478
|
if (event.key === "Enter" && !event.shiftKey) {
|
|
1469
1479
|
event.preventDefault();
|
|
1470
|
-
if (canSend
|
|
1480
|
+
if (canSend) {
|
|
1471
1481
|
send();
|
|
1472
1482
|
}
|
|
1473
1483
|
}
|
|
@@ -1489,7 +1499,7 @@ var Input = ({ inProgress, onSend, isVisible = false, onStop, onUpload }) => {
|
|
|
1489
1499
|
"button",
|
|
1490
1500
|
{
|
|
1491
1501
|
disabled: sendDisabled,
|
|
1492
|
-
onClick: isInProgress ? onStop : send,
|
|
1502
|
+
onClick: isInProgress && !hideStopButton ? onStop : send,
|
|
1493
1503
|
"data-copilotkit-in-progress": inProgress,
|
|
1494
1504
|
"data-test-id": inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready",
|
|
1495
1505
|
className: "copilotKitInputControlButton",
|
|
@@ -2695,7 +2705,8 @@ function CopilotChat({
|
|
|
2695
2705
|
AssistantMessage: AssistantMessage2 = AssistantMessage,
|
|
2696
2706
|
UserMessage: UserMessage2 = UserMessage,
|
|
2697
2707
|
imageUploadsEnabled,
|
|
2698
|
-
inputFileAccept = "image/*"
|
|
2708
|
+
inputFileAccept = "image/*",
|
|
2709
|
+
hideStopButton
|
|
2699
2710
|
}) {
|
|
2700
2711
|
const { additionalInstructions, setChatInstructions } = (0, import_react_core10.useCopilotContext)();
|
|
2701
2712
|
const [selectedImages, setSelectedImages] = (0, import_react13.useState)([]);
|
|
@@ -2878,7 +2889,8 @@ function CopilotChat({
|
|
|
2878
2889
|
onUpload: imageUploadsEnabled ? () => {
|
|
2879
2890
|
var _a;
|
|
2880
2891
|
return (_a = fileInputRef.current) == null ? void 0 : _a.click();
|
|
2881
|
-
} : void 0
|
|
2892
|
+
} : void 0,
|
|
2893
|
+
hideStopButton
|
|
2882
2894
|
}
|
|
2883
2895
|
)
|
|
2884
2896
|
] });
|