@copilotkit/react-ui 1.10.0-next.1 → 1.10.0-next.11

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.
Files changed (108) hide show
  1. package/CHANGELOG.md +112 -0
  2. package/dist/{chunk-O7KTFUAN.mjs → chunk-226ZMOE3.mjs} +2 -2
  3. package/dist/{chunk-WHDNKXMP.mjs → chunk-BJHJBS5M.mjs} +46 -6
  4. package/dist/chunk-BJHJBS5M.mjs.map +1 -0
  5. package/dist/{chunk-FOSKS7AI.mjs → chunk-FFJHOZX6.mjs} +5 -5
  6. package/dist/{chunk-QELAC6XJ.mjs → chunk-GBP47ONN.mjs} +2 -2
  7. package/dist/chunk-GBP47ONN.mjs.map +1 -0
  8. package/dist/{chunk-7CAK2CNK.mjs → chunk-GDSZGYCE.mjs} +2 -2
  9. package/dist/{chunk-O7PYQO73.mjs → chunk-GJ4SX4JE.mjs} +153 -37
  10. package/dist/chunk-GJ4SX4JE.mjs.map +1 -0
  11. package/dist/{chunk-TCIZDWPC.mjs → chunk-J5ZZR6YB.mjs} +2 -2
  12. package/dist/chunk-J5ZZR6YB.mjs.map +1 -0
  13. package/dist/{chunk-QN7T3GWI.mjs → chunk-JY2CSDKN.mjs} +4 -6
  14. package/dist/chunk-JY2CSDKN.mjs.map +1 -0
  15. package/dist/chunk-MIVUCSGO.mjs +126 -0
  16. package/dist/chunk-MIVUCSGO.mjs.map +1 -0
  17. package/dist/{chunk-OQM7D3Z3.mjs → chunk-T5QU6KSB.mjs} +8 -4
  18. package/dist/chunk-T5QU6KSB.mjs.map +1 -0
  19. package/dist/{chunk-Q2467VHZ.mjs → chunk-W26XFBEG.mjs} +2 -2
  20. package/dist/chunk-W26XFBEG.mjs.map +1 -0
  21. package/dist/chunk-Y44VLEUH.mjs +222 -0
  22. package/dist/chunk-Y44VLEUH.mjs.map +1 -0
  23. package/dist/components/chat/Chat.d.ts +52 -15
  24. package/dist/components/chat/Chat.js +1136 -869
  25. package/dist/components/chat/Chat.js.map +1 -1
  26. package/dist/components/chat/Chat.mjs +9 -8
  27. package/dist/components/chat/Header.js +6 -8
  28. package/dist/components/chat/Header.js.map +1 -1
  29. package/dist/components/chat/Header.mjs +4 -4
  30. package/dist/components/chat/Messages.d.ts +1 -1
  31. package/dist/components/chat/Messages.js +984 -23
  32. package/dist/components/chat/Messages.js.map +1 -1
  33. package/dist/components/chat/Messages.mjs +9 -1
  34. package/dist/components/chat/Modal.d.ts +2 -2
  35. package/dist/components/chat/Modal.js +1267 -931
  36. package/dist/components/chat/Modal.js.map +1 -1
  37. package/dist/components/chat/Modal.mjs +14 -13
  38. package/dist/components/chat/Popup.d.ts +1 -1
  39. package/dist/components/chat/Popup.js +1269 -933
  40. package/dist/components/chat/Popup.js.map +1 -1
  41. package/dist/components/chat/Popup.mjs +15 -14
  42. package/dist/components/chat/Sidebar.d.ts +1 -1
  43. package/dist/components/chat/Sidebar.js +1269 -933
  44. package/dist/components/chat/Sidebar.js.map +1 -1
  45. package/dist/components/chat/Sidebar.mjs +15 -14
  46. package/dist/components/chat/Suggestion.js +1 -1
  47. package/dist/components/chat/Suggestion.js.map +1 -1
  48. package/dist/components/chat/Suggestion.mjs +1 -1
  49. package/dist/components/chat/Suggestions.js +1 -1
  50. package/dist/components/chat/Suggestions.js.map +1 -1
  51. package/dist/components/chat/Suggestions.mjs +2 -2
  52. package/dist/components/chat/index.d.ts +2 -2
  53. package/dist/components/chat/index.js +1271 -935
  54. package/dist/components/chat/index.js.map +1 -1
  55. package/dist/components/chat/index.mjs +22 -21
  56. package/dist/components/chat/messages/LegacyRenderMessage.d.ts +28 -0
  57. package/dist/components/chat/messages/LegacyRenderMessage.js +980 -0
  58. package/dist/components/chat/messages/LegacyRenderMessage.js.map +1 -0
  59. package/dist/components/chat/messages/LegacyRenderMessage.mjs +17 -0
  60. package/dist/components/chat/messages/LegacyRenderMessage.mjs.map +1 -0
  61. package/dist/components/chat/messages/RenderMessage.js +4 -0
  62. package/dist/components/chat/messages/RenderMessage.js.map +1 -1
  63. package/dist/components/chat/messages/RenderMessage.mjs +2 -2
  64. package/dist/components/chat/props.d.ts +94 -2
  65. package/dist/components/chat/props.js.map +1 -1
  66. package/dist/components/dev-console/console.d.ts +1 -0
  67. package/dist/components/dev-console/console.js +6 -8
  68. package/dist/components/dev-console/console.js.map +1 -1
  69. package/dist/components/dev-console/console.mjs +3 -3
  70. package/dist/components/dev-console/index.d.ts +1 -3
  71. package/dist/components/dev-console/index.js +7 -9
  72. package/dist/components/dev-console/index.js.map +1 -1
  73. package/dist/components/dev-console/index.mjs +5 -5
  74. package/dist/components/dev-console/utils.d.ts +2 -2
  75. package/dist/components/dev-console/utils.js +2 -4
  76. package/dist/components/dev-console/utils.js.map +1 -1
  77. package/dist/components/dev-console/utils.mjs +1 -1
  78. package/dist/components/index.d.ts +3 -5
  79. package/dist/components/index.js +1272 -936
  80. package/dist/components/index.js.map +1 -1
  81. package/dist/components/index.mjs +24 -23
  82. package/dist/index.d.ts +3 -5
  83. package/dist/index.js +1303 -967
  84. package/dist/index.js.map +1 -1
  85. package/dist/index.mjs +24 -23
  86. package/package.json +6 -6
  87. package/src/components/chat/Chat.tsx +241 -23
  88. package/src/components/chat/Messages.tsx +58 -5
  89. package/src/components/chat/Modal.tsx +128 -41
  90. package/src/components/chat/Popup.tsx +20 -0
  91. package/src/components/chat/Sidebar.tsx +22 -0
  92. package/src/components/chat/Suggestion.tsx +1 -1
  93. package/src/components/chat/messages/LegacyRenderMessage.tsx +143 -0
  94. package/src/components/chat/messages/RenderMessage.tsx +3 -0
  95. package/src/components/chat/props.ts +110 -1
  96. package/src/components/dev-console/utils.ts +1 -6
  97. package/dist/chunk-7RNOT3GM.mjs +0 -144
  98. package/dist/chunk-7RNOT3GM.mjs.map +0 -1
  99. package/dist/chunk-O7PYQO73.mjs.map +0 -1
  100. package/dist/chunk-OQM7D3Z3.mjs.map +0 -1
  101. package/dist/chunk-Q2467VHZ.mjs.map +0 -1
  102. package/dist/chunk-QELAC6XJ.mjs.map +0 -1
  103. package/dist/chunk-QN7T3GWI.mjs.map +0 -1
  104. package/dist/chunk-TCIZDWPC.mjs.map +0 -1
  105. package/dist/chunk-WHDNKXMP.mjs.map +0 -1
  106. /package/dist/{chunk-O7KTFUAN.mjs.map → chunk-226ZMOE3.mjs.map} +0 -0
  107. /package/dist/{chunk-FOSKS7AI.mjs.map → chunk-FFJHOZX6.mjs.map} +0 -0
  108. /package/dist/{chunk-7CAK2CNK.mjs.map → chunk-GDSZGYCE.mjs.map} +0 -0
@@ -395,559 +395,137 @@ var ChatContextProvider = ({
395
395
  };
396
396
 
397
397
  // src/components/chat/Messages.tsx
398
- var import_react2 = require("react");
398
+ var import_react6 = require("react");
399
399
  var import_react_core = require("@copilotkit/react-core");
400
+
401
+ // src/components/chat/messages/UserMessage.tsx
400
402
  var import_jsx_runtime3 = require("react/jsx-runtime");
401
- var Messages = ({
402
- inProgress,
403
- children,
404
- RenderMessage: RenderMessage2,
405
- AssistantMessage: AssistantMessage2,
406
- UserMessage: UserMessage2,
407
- onRegenerate,
408
- onCopy,
409
- onThumbsUp,
410
- onThumbsDown,
411
- markdownTagRenderers
412
- }) => {
413
- const { labels } = useChatContext();
414
- const { visibleMessages, interrupt } = (0, import_react_core.useCopilotChat)();
415
- const initialMessages = (0, import_react2.useMemo)(() => makeInitialMessages(labels.initial), [labels.initial]);
416
- const messages = [...initialMessages, ...visibleMessages];
417
- const { messagesContainerRef, messagesEndRef } = useScrollToBottom(messages);
418
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "copilotKitMessages", ref: messagesContainerRef, children: [
419
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "copilotKitMessagesContainer", children: [
420
- messages.map((message, index) => {
421
- const isCurrentMessage = index === messages.length - 1;
422
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
423
- RenderMessage2,
424
- {
425
- message,
426
- inProgress,
427
- index,
428
- isCurrentMessage,
429
- AssistantMessage: AssistantMessage2,
430
- UserMessage: UserMessage2,
431
- onRegenerate,
432
- onCopy,
433
- onThumbsUp,
434
- onThumbsDown,
435
- markdownTagRenderers
436
- },
437
- index
438
- );
439
- }),
440
- interrupt
441
- ] }),
442
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("footer", { className: "copilotKitMessagesFooter", ref: messagesEndRef, children })
443
- ] });
444
- };
445
- function makeInitialMessages(initial) {
446
- if (!initial)
447
- return [];
448
- if (Array.isArray(initial)) {
449
- return initial.map((message) => {
450
- return {
451
- id: message,
452
- role: "assistant",
453
- content: message
454
- };
455
- });
403
+ var UserMessage = (props) => {
404
+ const { message, ImageRenderer: ImageRenderer2 } = props;
405
+ const isImageMessage = message && "image" in message && message.image;
406
+ if (isImageMessage) {
407
+ const imageMessage = message;
408
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "copilotKitMessage copilotKitUserMessage", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ImageRenderer2, { image: imageMessage.image, content: imageMessage.content }) });
456
409
  }
457
- return [
458
- {
459
- id: initial,
460
- role: "system",
461
- content: initial
462
- }
463
- ];
464
- }
465
- function useScrollToBottom(messages) {
466
- const messagesEndRef = (0, import_react2.useRef)(null);
467
- const messagesContainerRef = (0, import_react2.useRef)(null);
468
- const isProgrammaticScrollRef = (0, import_react2.useRef)(false);
469
- const isUserScrollUpRef = (0, import_react2.useRef)(false);
470
- const scrollToBottom = () => {
471
- if (messagesContainerRef.current && messagesEndRef.current) {
472
- isProgrammaticScrollRef.current = true;
473
- messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
474
- }
475
- };
476
- const handleScroll = () => {
477
- if (isProgrammaticScrollRef.current) {
478
- isProgrammaticScrollRef.current = false;
410
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "copilotKitMessage copilotKitUserMessage", children: message == null ? void 0 : message.content });
411
+ };
412
+
413
+ // src/components/chat/Markdown.tsx
414
+ var import_react3 = require("react");
415
+ var import_react_markdown = __toESM(require("react-markdown"));
416
+
417
+ // src/components/chat/CodeBlock.tsx
418
+ var import_react2 = require("react");
419
+ var import_react_syntax_highlighter = require("react-syntax-highlighter");
420
+
421
+ // src/hooks/use-copy-to-clipboard.tsx
422
+ var React2 = __toESM(require("react"));
423
+ function useCopyToClipboard({ timeout = 2e3 }) {
424
+ const [isCopied, setIsCopied] = React2.useState(false);
425
+ const copyToClipboard = (value) => {
426
+ var _a;
427
+ if (typeof window === "undefined" || !((_a = navigator.clipboard) == null ? void 0 : _a.writeText)) {
479
428
  return;
480
429
  }
481
- if (messagesContainerRef.current) {
482
- const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
483
- isUserScrollUpRef.current = scrollTop + clientHeight < scrollHeight;
484
- }
485
- };
486
- (0, import_react2.useEffect)(() => {
487
- const container = messagesContainerRef.current;
488
- if (container) {
489
- container.addEventListener("scroll", handleScroll);
490
- }
491
- return () => {
492
- if (container) {
493
- container.removeEventListener("scroll", handleScroll);
494
- }
495
- };
496
- }, []);
497
- (0, import_react2.useEffect)(() => {
498
- const container = messagesContainerRef.current;
499
- if (!container) {
430
+ if (!value) {
500
431
  return;
501
432
  }
502
- const mutationObserver = new MutationObserver(() => {
503
- if (!isUserScrollUpRef.current) {
504
- scrollToBottom();
505
- }
506
- });
507
- mutationObserver.observe(container, {
508
- childList: true,
509
- subtree: true,
510
- characterData: true
433
+ navigator.clipboard.writeText(value).then(() => {
434
+ setIsCopied(true);
435
+ setTimeout(() => {
436
+ setIsCopied(false);
437
+ }, timeout);
511
438
  });
512
- return () => {
513
- mutationObserver.disconnect();
514
- };
515
- }, []);
516
- (0, import_react2.useEffect)(() => {
517
- isUserScrollUpRef.current = false;
518
- scrollToBottom();
519
- }, [messages.filter((m) => m.role === "user").length]);
520
- return { messagesEndRef, messagesContainerRef };
439
+ };
440
+ return { isCopied, copyToClipboard };
521
441
  }
522
442
 
523
- // src/components/chat/Input.tsx
524
- var import_react5 = require("react");
525
-
526
- // src/components/chat/Textarea.tsx
527
- var import_react3 = require("react");
443
+ // src/components/chat/CodeBlock.tsx
528
444
  var import_jsx_runtime4 = require("react/jsx-runtime");
529
- var AutoResizingTextarea = (0, import_react3.forwardRef)(
530
- ({
531
- maxRows = 1,
532
- placeholder,
533
- value,
534
- onChange,
535
- onKeyDown,
536
- onCompositionStart,
537
- onCompositionEnd,
538
- autoFocus
539
- }, ref) => {
540
- const internalTextareaRef = (0, import_react3.useRef)(null);
541
- const [maxHeight, setMaxHeight] = (0, import_react3.useState)(0);
542
- (0, import_react3.useImperativeHandle)(ref, () => internalTextareaRef.current);
543
- (0, import_react3.useEffect)(() => {
544
- const calculateMaxHeight = () => {
545
- const textarea = internalTextareaRef.current;
546
- if (textarea) {
547
- textarea.style.height = "auto";
548
- const singleRowHeight = textarea.scrollHeight;
549
- setMaxHeight(singleRowHeight * maxRows);
550
- if (autoFocus) {
551
- textarea.focus();
552
- }
553
- }
554
- };
555
- calculateMaxHeight();
556
- }, [maxRows]);
557
- (0, import_react3.useEffect)(() => {
558
- const textarea = internalTextareaRef.current;
559
- if (textarea) {
560
- textarea.style.height = "auto";
561
- textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
562
- }
563
- }, [value, maxHeight]);
564
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
565
- "textarea",
445
+ var programmingLanguages = {
446
+ javascript: ".js",
447
+ python: ".py",
448
+ java: ".java",
449
+ c: ".c",
450
+ cpp: ".cpp",
451
+ "c++": ".cpp",
452
+ "c#": ".cs",
453
+ ruby: ".rb",
454
+ php: ".php",
455
+ swift: ".swift",
456
+ "objective-c": ".m",
457
+ kotlin: ".kt",
458
+ typescript: ".ts",
459
+ go: ".go",
460
+ perl: ".pl",
461
+ rust: ".rs",
462
+ scala: ".scala",
463
+ haskell: ".hs",
464
+ lua: ".lua",
465
+ shell: ".sh",
466
+ sql: ".sql",
467
+ html: ".html",
468
+ css: ".css"
469
+ // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
470
+ };
471
+ var generateRandomString = (length, lowercase = false) => {
472
+ const chars = "ABCDEFGHJKLMNPQRSTUVWXY3456789";
473
+ let result = "";
474
+ for (let i = 0; i < length; i++) {
475
+ result += chars.charAt(Math.floor(Math.random() * chars.length));
476
+ }
477
+ return lowercase ? result.toLowerCase() : result;
478
+ };
479
+ var CodeBlock = (0, import_react2.memo)(({ language, value }) => {
480
+ const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2e3 });
481
+ const downloadAsFile = () => {
482
+ if (typeof window === "undefined") {
483
+ return;
484
+ }
485
+ const fileExtension = programmingLanguages[language] || ".file";
486
+ const suggestedFileName = `file-${generateRandomString(3, true)}${fileExtension}`;
487
+ const fileName = window.prompt("Enter file name", suggestedFileName);
488
+ if (!fileName) {
489
+ return;
490
+ }
491
+ const blob = new Blob([value], { type: "text/plain" });
492
+ const url = URL.createObjectURL(blob);
493
+ const link = document.createElement("a");
494
+ link.download = fileName;
495
+ link.href = url;
496
+ link.style.display = "none";
497
+ document.body.appendChild(link);
498
+ link.click();
499
+ document.body.removeChild(link);
500
+ URL.revokeObjectURL(url);
501
+ };
502
+ const onCopy = () => {
503
+ if (isCopied)
504
+ return;
505
+ copyToClipboard(value);
506
+ };
507
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "copilotKitCodeBlock", children: [
508
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "copilotKitCodeBlockToolbar", children: [
509
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "copilotKitCodeBlockToolbarLanguage", children: language }),
510
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "copilotKitCodeBlockToolbarButtons", children: [
511
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "copilotKitCodeBlockToolbarButton", onClick: downloadAsFile, children: DownloadIcon }),
512
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { className: "copilotKitCodeBlockToolbarButton", onClick: onCopy, children: isCopied ? CheckIcon : CopyIcon })
513
+ ] })
514
+ ] }),
515
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
516
+ import_react_syntax_highlighter.Prism,
566
517
  {
567
- ref: internalTextareaRef,
568
- value,
569
- onChange,
570
- onKeyDown,
571
- onCompositionStart,
572
- onCompositionEnd,
573
- placeholder,
574
- style: {
575
- overflow: "auto",
576
- resize: "none",
577
- maxHeight: `${maxHeight}px`
518
+ language,
519
+ style: highlightStyle,
520
+ PreTag: "div",
521
+ customStyle: {
522
+ margin: 0,
523
+ borderBottomLeftRadius: "0.375rem",
524
+ borderBottomRightRadius: "0.375rem"
578
525
  },
579
- rows: 1
526
+ children: value
580
527
  }
581
- );
582
- }
583
- );
584
- var Textarea_default = AutoResizingTextarea;
585
-
586
- // src/hooks/use-push-to-talk.tsx
587
- var import_react_core2 = require("@copilotkit/react-core");
588
- var import_runtime_client_gql = require("@copilotkit/runtime-client-gql");
589
- var import_react4 = require("react");
590
- var startRecording = (mediaStreamRef, mediaRecorderRef, audioContextRef, recordedChunks, onStop) => __async(void 0, null, function* () {
591
- if (!mediaStreamRef.current || !audioContextRef.current) {
592
- mediaStreamRef.current = yield navigator.mediaDevices.getUserMedia({ audio: true });
593
- audioContextRef.current = new window.AudioContext();
594
- yield audioContextRef.current.resume();
595
- }
596
- mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current);
597
- mediaRecorderRef.current.start(1e3);
598
- mediaRecorderRef.current.ondataavailable = (event) => {
599
- recordedChunks.push(event.data);
600
- };
601
- mediaRecorderRef.current.onstop = onStop;
602
- });
603
- var stopRecording = (mediaRecorderRef) => {
604
- if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
605
- mediaRecorderRef.current.stop();
606
- }
607
- };
608
- var transcribeAudio = (recordedChunks, transcribeAudioUrl) => __async(void 0, null, function* () {
609
- const completeBlob = new Blob(recordedChunks, { type: "audio/mp4" });
610
- const formData = new FormData();
611
- formData.append("file", completeBlob, "recording.mp4");
612
- const response = yield fetch(transcribeAudioUrl, {
613
- method: "POST",
614
- body: formData
615
- });
616
- if (!response.ok) {
617
- throw new Error(`Error: ${response.statusText}`);
618
- }
619
- const transcription = yield response.json();
620
- return transcription.text;
621
- });
622
- var playAudioResponse = (text, textToSpeechUrl, audioContext) => {
623
- const encodedText = encodeURIComponent(text);
624
- const url = `${textToSpeechUrl}?text=${encodedText}`;
625
- fetch(url).then((response) => response.arrayBuffer()).then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer)).then((audioBuffer) => {
626
- const source = audioContext.createBufferSource();
627
- source.buffer = audioBuffer;
628
- source.connect(audioContext.destination);
629
- source.start(0);
630
- }).catch((error) => {
631
- console.error("Error with decoding audio data", error);
632
- });
633
- };
634
- var usePushToTalk = ({
635
- sendFunction,
636
- inProgress
637
- }) => {
638
- const [pushToTalkState, setPushToTalkState] = (0, import_react4.useState)("idle");
639
- const mediaStreamRef = (0, import_react4.useRef)(null);
640
- const audioContextRef = (0, import_react4.useRef)(null);
641
- const mediaRecorderRef = (0, import_react4.useRef)(null);
642
- const recordedChunks = (0, import_react4.useRef)([]);
643
- const generalContext = (0, import_react_core2.useCopilotContext)();
644
- const messagesContext = (0, import_react_core2.useCopilotMessagesContext)();
645
- const context = __spreadValues(__spreadValues({}, generalContext), messagesContext);
646
- const [startReadingFromMessageId, setStartReadingFromMessageId] = (0, import_react4.useState)(null);
647
- (0, import_react4.useEffect)(() => {
648
- if (pushToTalkState === "recording") {
649
- startRecording(
650
- mediaStreamRef,
651
- mediaRecorderRef,
652
- audioContextRef,
653
- recordedChunks.current,
654
- () => {
655
- setPushToTalkState("transcribing");
656
- }
657
- );
658
- } else {
659
- stopRecording(mediaRecorderRef);
660
- if (pushToTalkState === "transcribing") {
661
- transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl).then(
662
- (transcription) => __async(void 0, null, function* () {
663
- recordedChunks.current = [];
664
- setPushToTalkState("idle");
665
- const message = yield sendFunction(transcription);
666
- setStartReadingFromMessageId(message.id);
667
- })
668
- );
669
- }
670
- }
671
- return () => {
672
- stopRecording(mediaRecorderRef);
673
- };
674
- }, [pushToTalkState]);
675
- (0, import_react4.useEffect)(() => {
676
- if (inProgress === false && startReadingFromMessageId) {
677
- const lastMessageIndex = context.messages.findIndex(
678
- (message) => message.id === startReadingFromMessageId
679
- );
680
- const aguiMessages = (0, import_runtime_client_gql.gqlToAGUI)(context.messages);
681
- const messagesAfterLast = aguiMessages.slice(lastMessageIndex + 1).filter((message) => message.role === "assistant");
682
- const text = messagesAfterLast.map((message) => message.content).join("\n");
683
- playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl, audioContextRef.current);
684
- setStartReadingFromMessageId(null);
685
- }
686
- }, [startReadingFromMessageId, inProgress]);
687
- return { pushToTalkState, setPushToTalkState };
688
- };
689
-
690
- // src/components/chat/Input.tsx
691
- var import_react_core3 = require("@copilotkit/react-core");
692
-
693
- // src/hooks/use-dark-mode.ts
694
- var useDarkMode = () => {
695
- if (typeof window === "undefined")
696
- return false;
697
- return document.documentElement.classList.contains("dark") || document.body.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark" || document.body.getAttribute("data-theme") === "dark" || window.matchMedia("(prefers-color-scheme: dark)").matches;
698
- };
699
-
700
- // src/components/chat/PoweredByTag.tsx
701
- var import_jsx_runtime5 = require("react/jsx-runtime");
702
- function PoweredByTag({ showPoweredBy = true }) {
703
- const isDark = useDarkMode();
704
- if (!showPoweredBy) {
705
- return null;
706
- }
707
- const poweredByStyle = {
708
- visibility: "visible",
709
- display: "block",
710
- position: "static",
711
- textAlign: "center",
712
- fontSize: "12px",
713
- padding: "3px 0",
714
- color: isDark ? "rgb(69, 69, 69)" : "rgb(214, 214, 214)"
715
- };
716
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: "poweredBy", style: poweredByStyle, children: "Powered by CopilotKit" }) });
717
- }
718
-
719
- // src/components/chat/Input.tsx
720
- var import_jsx_runtime6 = require("react/jsx-runtime");
721
- var MAX_NEWLINES = 6;
722
- var Input = ({
723
- inProgress,
724
- onSend,
725
- isVisible = false,
726
- onStop,
727
- onUpload,
728
- hideStopButton = false
729
- }) => {
730
- var _a, _b;
731
- const context = useChatContext();
732
- const copilotContext = (0, import_react_core3.useCopilotContext)();
733
- const showPoweredBy = !((_a = copilotContext.copilotApiConfig) == null ? void 0 : _a.publicApiKey);
734
- const pushToTalkConfigured = copilotContext.copilotApiConfig.textToSpeechUrl !== void 0 && copilotContext.copilotApiConfig.transcribeAudioUrl !== void 0;
735
- const textareaRef = (0, import_react5.useRef)(null);
736
- const [isComposing, setIsComposing] = (0, import_react5.useState)(false);
737
- const handleDivClick = (event) => {
738
- var _a2;
739
- const target = event.target;
740
- if (target.closest("button"))
741
- return;
742
- if (target.tagName === "TEXTAREA")
743
- return;
744
- (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
745
- };
746
- const [text, setText] = (0, import_react5.useState)("");
747
- const send = () => {
748
- var _a2;
749
- if (inProgress)
750
- return;
751
- onSend(text);
752
- setText("");
753
- (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
754
- };
755
- const { pushToTalkState, setPushToTalkState } = usePushToTalk({
756
- sendFunction: onSend,
757
- inProgress
758
- });
759
- const isInProgress = inProgress || pushToTalkState === "transcribing";
760
- const buttonIcon = isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;
761
- const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
762
- const canSend = (0, import_react5.useMemo)(() => {
763
- var _a2;
764
- const interruptEvent = (_a2 = copilotContext.langGraphInterruptAction) == null ? void 0 : _a2.event;
765
- const interruptInProgress = (interruptEvent == null ? void 0 : interruptEvent.name) === "LangGraphInterruptEvent" && !(interruptEvent == null ? void 0 : interruptEvent.response);
766
- return !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress;
767
- }, [(_b = copilotContext.langGraphInterruptAction) == null ? void 0 : _b.event, isInProgress, text, pushToTalkState]);
768
- const canStop = (0, import_react5.useMemo)(() => {
769
- return isInProgress && !hideStopButton;
770
- }, [isInProgress, hideStopButton]);
771
- const sendDisabled = !canSend && !canStop;
772
- return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: `copilotKitInputContainer ${showPoweredBy ? "poweredByContainer" : ""}`, children: [
773
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
774
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
775
- Textarea_default,
776
- {
777
- ref: textareaRef,
778
- placeholder: context.labels.placeholder,
779
- autoFocus: false,
780
- maxRows: MAX_NEWLINES,
781
- value: text,
782
- onChange: (event) => setText(event.target.value),
783
- onCompositionStart: () => setIsComposing(true),
784
- onCompositionEnd: () => setIsComposing(false),
785
- onKeyDown: (event) => {
786
- if (event.key === "Enter" && !event.shiftKey && !isComposing) {
787
- event.preventDefault();
788
- if (canSend) {
789
- send();
790
- }
791
- }
792
- }
793
- }
794
- ),
795
- /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "copilotKitInputControls", children: [
796
- onUpload && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("button", { onClick: onUpload, className: "copilotKitInputControlButton", children: context.icons.uploadIcon }),
797
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { flexGrow: 1 } }),
798
- showPushToTalk && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
799
- "button",
800
- {
801
- onClick: () => setPushToTalkState(pushToTalkState === "idle" ? "recording" : "transcribing"),
802
- className: pushToTalkState === "recording" ? "copilotKitInputControlButton copilotKitPushToTalkRecording" : "copilotKitInputControlButton",
803
- children: context.icons.pushToTalkIcon
804
- }
805
- ),
806
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
807
- "button",
808
- {
809
- disabled: sendDisabled,
810
- onClick: isInProgress && !hideStopButton ? onStop : send,
811
- "data-copilotkit-in-progress": inProgress,
812
- "data-test-id": inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready",
813
- className: "copilotKitInputControlButton",
814
- children: buttonIcon
815
- }
816
- )
817
- ] })
818
- ] }),
819
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PoweredByTag, { showPoweredBy })
820
- ] });
821
- };
822
-
823
- // src/components/chat/messages/UserMessage.tsx
824
- var import_jsx_runtime7 = require("react/jsx-runtime");
825
- var UserMessage = (props) => {
826
- const { message, ImageRenderer: ImageRenderer2 } = props;
827
- const isImageMessage = message && "image" in message && message.image;
828
- if (isImageMessage) {
829
- const imageMessage = message;
830
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "copilotKitMessage copilotKitUserMessage", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ImageRenderer2, { image: imageMessage.image, content: imageMessage.content }) });
831
- }
832
- return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "copilotKitMessage copilotKitUserMessage", children: message == null ? void 0 : message.content });
833
- };
834
-
835
- // src/components/chat/Markdown.tsx
836
- var import_react7 = require("react");
837
- var import_react_markdown = __toESM(require("react-markdown"));
838
-
839
- // src/components/chat/CodeBlock.tsx
840
- var import_react6 = require("react");
841
- var import_react_syntax_highlighter = require("react-syntax-highlighter");
842
-
843
- // src/hooks/use-copy-to-clipboard.tsx
844
- var React4 = __toESM(require("react"));
845
- function useCopyToClipboard({ timeout = 2e3 }) {
846
- const [isCopied, setIsCopied] = React4.useState(false);
847
- const copyToClipboard = (value) => {
848
- var _a;
849
- if (typeof window === "undefined" || !((_a = navigator.clipboard) == null ? void 0 : _a.writeText)) {
850
- return;
851
- }
852
- if (!value) {
853
- return;
854
- }
855
- navigator.clipboard.writeText(value).then(() => {
856
- setIsCopied(true);
857
- setTimeout(() => {
858
- setIsCopied(false);
859
- }, timeout);
860
- });
861
- };
862
- return { isCopied, copyToClipboard };
863
- }
864
-
865
- // src/components/chat/CodeBlock.tsx
866
- var import_jsx_runtime8 = require("react/jsx-runtime");
867
- var programmingLanguages = {
868
- javascript: ".js",
869
- python: ".py",
870
- java: ".java",
871
- c: ".c",
872
- cpp: ".cpp",
873
- "c++": ".cpp",
874
- "c#": ".cs",
875
- ruby: ".rb",
876
- php: ".php",
877
- swift: ".swift",
878
- "objective-c": ".m",
879
- kotlin: ".kt",
880
- typescript: ".ts",
881
- go: ".go",
882
- perl: ".pl",
883
- rust: ".rs",
884
- scala: ".scala",
885
- haskell: ".hs",
886
- lua: ".lua",
887
- shell: ".sh",
888
- sql: ".sql",
889
- html: ".html",
890
- css: ".css"
891
- // add more file extensions here, make sure the key is same as language prop in CodeBlock.tsx component
892
- };
893
- var generateRandomString = (length, lowercase = false) => {
894
- const chars = "ABCDEFGHJKLMNPQRSTUVWXY3456789";
895
- let result = "";
896
- for (let i = 0; i < length; i++) {
897
- result += chars.charAt(Math.floor(Math.random() * chars.length));
898
- }
899
- return lowercase ? result.toLowerCase() : result;
900
- };
901
- var CodeBlock = (0, import_react6.memo)(({ language, value }) => {
902
- const { isCopied, copyToClipboard } = useCopyToClipboard({ timeout: 2e3 });
903
- const downloadAsFile = () => {
904
- if (typeof window === "undefined") {
905
- return;
906
- }
907
- const fileExtension = programmingLanguages[language] || ".file";
908
- const suggestedFileName = `file-${generateRandomString(3, true)}${fileExtension}`;
909
- const fileName = window.prompt("Enter file name", suggestedFileName);
910
- if (!fileName) {
911
- return;
912
- }
913
- const blob = new Blob([value], { type: "text/plain" });
914
- const url = URL.createObjectURL(blob);
915
- const link = document.createElement("a");
916
- link.download = fileName;
917
- link.href = url;
918
- link.style.display = "none";
919
- document.body.appendChild(link);
920
- link.click();
921
- document.body.removeChild(link);
922
- URL.revokeObjectURL(url);
923
- };
924
- const onCopy = () => {
925
- if (isCopied)
926
- return;
927
- copyToClipboard(value);
928
- };
929
- return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "copilotKitCodeBlock", children: [
930
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "copilotKitCodeBlockToolbar", children: [
931
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { className: "copilotKitCodeBlockToolbarLanguage", children: language }),
932
- /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("div", { className: "copilotKitCodeBlockToolbarButtons", children: [
933
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "copilotKitCodeBlockToolbarButton", onClick: downloadAsFile, children: DownloadIcon }),
934
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("button", { className: "copilotKitCodeBlockToolbarButton", onClick: onCopy, children: isCopied ? CheckIcon : CopyIcon })
935
- ] })
936
- ] }),
937
- /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
938
- import_react_syntax_highlighter.Prism,
939
- {
940
- language,
941
- style: highlightStyle,
942
- PreTag: "div",
943
- customStyle: {
944
- margin: 0,
945
- borderBottomLeftRadius: "0.375rem",
946
- borderBottomRightRadius: "0.375rem"
947
- },
948
- children: value
949
- }
950
- )
528
+ )
951
529
  ] });
952
530
  });
953
531
  CodeBlock.displayName = "CodeBlock";
@@ -1232,316 +810,896 @@ var highlightStyle = {
1232
810
  boxShadow: "inset 5px 0 0 #f7d87c",
1233
811
  zIndex: "0"
1234
812
  }
1235
- };
813
+ };
814
+
815
+ // src/components/chat/Markdown.tsx
816
+ var import_remark_gfm = __toESM(require("remark-gfm"));
817
+ var import_remark_math = __toESM(require("remark-math"));
818
+ var import_rehype_raw = __toESM(require("rehype-raw"));
819
+ var import_jsx_runtime5 = require("react/jsx-runtime");
820
+ var defaultComponents = {
821
+ a(_a) {
822
+ var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
823
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("a", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { target: "_blank", rel: "noopener noreferrer", children }));
824
+ },
825
+ // @ts-expect-error -- inline
826
+ code(_c) {
827
+ var _d = _c, { children, className, inline } = _d, props = __objRest(_d, ["children", "className", "inline"]);
828
+ if (Array.isArray(children) && children.length) {
829
+ if (children[0] == "\u258D") {
830
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
831
+ "span",
832
+ {
833
+ style: {
834
+ animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
835
+ marginTop: "0.25rem"
836
+ },
837
+ children: "\u258D"
838
+ }
839
+ );
840
+ }
841
+ children[0] = (children == null ? void 0 : children[0]).replace("`\u258D`", "\u258D");
842
+ }
843
+ const match = /language-(\w+)/.exec(className || "");
844
+ const hasLanguage = match && match[1];
845
+ const content = String(children);
846
+ const hasNewlines = content.includes("\n");
847
+ const isInline = !hasLanguage && !hasNewlines;
848
+ if (isInline) {
849
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
850
+ "code",
851
+ __spreadProps(__spreadValues({
852
+ className: `copilotKitMarkdownElement copilotKitInlineCode ${className || ""}`
853
+ }, props), {
854
+ children
855
+ })
856
+ );
857
+ }
858
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
859
+ CodeBlock,
860
+ __spreadValues({
861
+ language: match && match[1] || "",
862
+ value: String(children).replace(/\n$/, "")
863
+ }, props),
864
+ Math.random()
865
+ );
866
+ },
867
+ h1: (_e) => {
868
+ var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
869
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h1", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
870
+ },
871
+ h2: (_g) => {
872
+ var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
873
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
874
+ },
875
+ h3: (_i) => {
876
+ var _j = _i, { children } = _j, props = __objRest(_j, ["children"]);
877
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
878
+ },
879
+ h4: (_k) => {
880
+ var _l = _k, { children } = _l, props = __objRest(_l, ["children"]);
881
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h4", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
882
+ },
883
+ h5: (_m) => {
884
+ var _n = _m, { children } = _n, props = __objRest(_n, ["children"]);
885
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h5", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
886
+ },
887
+ h6: (_o) => {
888
+ var _p = _o, { children } = _p, props = __objRest(_p, ["children"]);
889
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h6", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
890
+ },
891
+ p: (_q) => {
892
+ var _r = _q, { children } = _r, props = __objRest(_r, ["children"]);
893
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
894
+ },
895
+ pre: (_s) => {
896
+ var _t = _s, { children } = _t, props = __objRest(_t, ["children"]);
897
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("pre", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
898
+ },
899
+ blockquote: (_u) => {
900
+ var _v = _u, { children } = _v, props = __objRest(_v, ["children"]);
901
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("blockquote", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
902
+ },
903
+ ul: (_w) => {
904
+ var _x = _w, { children } = _x, props = __objRest(_x, ["children"]);
905
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("ul", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
906
+ },
907
+ li: (_y) => {
908
+ var _z = _y, { children } = _z, props = __objRest(_z, ["children"]);
909
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("li", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
910
+ }
911
+ };
912
+ var MemoizedReactMarkdown = (0, import_react3.memo)(
913
+ import_react_markdown.default,
914
+ (prevProps, nextProps) => prevProps.children === nextProps.children && prevProps.components === nextProps.components
915
+ );
916
+ var Markdown = ({ content, components }) => {
917
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: "copilotKitMarkdown", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
918
+ MemoizedReactMarkdown,
919
+ {
920
+ components: __spreadValues(__spreadValues({}, defaultComponents), components),
921
+ remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
922
+ rehypePlugins: [import_rehype_raw.default],
923
+ children: content
924
+ }
925
+ ) });
926
+ };
927
+
928
+ // src/components/chat/messages/AssistantMessage.tsx
929
+ var import_react4 = require("react");
930
+ var import_jsx_runtime6 = require("react/jsx-runtime");
931
+ var AssistantMessage = (props) => {
932
+ var _a;
933
+ const { icons, labels } = useChatContext();
934
+ const {
935
+ message,
936
+ isLoading,
937
+ onRegenerate,
938
+ onCopy,
939
+ onThumbsUp,
940
+ onThumbsDown,
941
+ isCurrentMessage,
942
+ markdownTagRenderers
943
+ } = props;
944
+ const [copied, setCopied] = (0, import_react4.useState)(false);
945
+ const handleCopy = () => {
946
+ const content2 = (message == null ? void 0 : message.content) || "";
947
+ if (content2 && onCopy) {
948
+ navigator.clipboard.writeText(content2);
949
+ setCopied(true);
950
+ onCopy(content2);
951
+ setTimeout(() => setCopied(false), 2e3);
952
+ } else if (content2) {
953
+ navigator.clipboard.writeText(content2);
954
+ setCopied(true);
955
+ setTimeout(() => setCopied(false), 2e3);
956
+ }
957
+ };
958
+ const handleRegenerate = () => {
959
+ if (onRegenerate)
960
+ onRegenerate();
961
+ };
962
+ const handleThumbsUp = () => {
963
+ if (onThumbsUp && message)
964
+ onThumbsUp(message);
965
+ };
966
+ const handleThumbsDown = () => {
967
+ if (onThumbsDown && message)
968
+ onThumbsDown(message);
969
+ };
970
+ const LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: icons.activityIcon });
971
+ const content = (message == null ? void 0 : message.content) || "";
972
+ const subComponent = (_a = message == null ? void 0 : message.generativeUI) == null ? void 0 : _a.call(message);
973
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
974
+ content && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "copilotKitMessage copilotKitAssistantMessage", children: [
975
+ content && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Markdown, { content, components: markdownTagRenderers }),
976
+ content && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
977
+ "div",
978
+ {
979
+ className: `copilotKitMessageControls ${isCurrentMessage ? "currentMessage" : ""}`,
980
+ children: [
981
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
982
+ "button",
983
+ {
984
+ className: "copilotKitMessageControlButton",
985
+ onClick: handleRegenerate,
986
+ "aria-label": labels.regenerateResponse,
987
+ title: labels.regenerateResponse,
988
+ children: icons.regenerateIcon
989
+ }
990
+ ),
991
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
992
+ "button",
993
+ {
994
+ className: "copilotKitMessageControlButton",
995
+ onClick: handleCopy,
996
+ "aria-label": labels.copyToClipboard,
997
+ title: labels.copyToClipboard,
998
+ children: copied ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: "10px", fontWeight: "bold" }, children: "\u2713" }) : icons.copyIcon
999
+ }
1000
+ ),
1001
+ onThumbsUp && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1002
+ "button",
1003
+ {
1004
+ className: "copilotKitMessageControlButton",
1005
+ onClick: handleThumbsUp,
1006
+ "aria-label": labels.thumbsUp,
1007
+ title: labels.thumbsUp,
1008
+ children: icons.thumbsUpIcon
1009
+ }
1010
+ ),
1011
+ onThumbsDown && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1012
+ "button",
1013
+ {
1014
+ className: "copilotKitMessageControlButton",
1015
+ onClick: handleThumbsDown,
1016
+ "aria-label": labels.thumbsDown,
1017
+ title: labels.thumbsDown,
1018
+ children: icons.thumbsDownIcon
1019
+ }
1020
+ )
1021
+ ]
1022
+ }
1023
+ )
1024
+ ] }),
1025
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { marginBottom: "0.5rem" }, children: subComponent }),
1026
+ isLoading && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(LoadingIcon, {})
1027
+ ] });
1028
+ };
1029
+
1030
+ // src/components/chat/messages/ImageRenderer.tsx
1031
+ var import_react5 = require("react");
1032
+ var import_jsx_runtime7 = require("react/jsx-runtime");
1033
+ var ImageRenderer = ({ image, content, className = "" }) => {
1034
+ const [imageError, setImageError] = (0, import_react5.useState)(false);
1035
+ const imageSrc = `data:image/${image.format};base64,${image.bytes}`;
1036
+ const altText = content || "User uploaded image";
1037
+ const handleImageError = () => {
1038
+ setImageError(true);
1039
+ };
1040
+ if (imageError) {
1041
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `copilotKitImageRendering copilotKitImageRenderingError ${className}`, children: [
1042
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "copilotKitImageRenderingErrorMessage", children: "Failed to load image" }),
1043
+ content && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "copilotKitImageRenderingContent", children: content })
1044
+ ] });
1045
+ }
1046
+ return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: `copilotKitImageRendering ${className}`, children: [
1047
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
1048
+ "img",
1049
+ {
1050
+ src: imageSrc,
1051
+ alt: altText,
1052
+ className: "copilotKitImageRenderingImage",
1053
+ onError: handleImageError
1054
+ }
1055
+ ),
1056
+ content && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "copilotKitImageRenderingContent", children: content })
1057
+ ] });
1058
+ };
1059
+
1060
+ // src/components/chat/messages/RenderMessage.tsx
1061
+ var import_jsx_runtime8 = require("react/jsx-runtime");
1062
+ function RenderMessage(_a) {
1063
+ var _b = _a, {
1064
+ UserMessage: UserMessage2 = UserMessage,
1065
+ AssistantMessage: AssistantMessage2 = AssistantMessage,
1066
+ ImageRenderer: ImageRenderer2 = ImageRenderer
1067
+ } = _b, props = __objRest(_b, [
1068
+ "UserMessage",
1069
+ "AssistantMessage",
1070
+ "ImageRenderer"
1071
+ ]);
1072
+ var _a2;
1073
+ const {
1074
+ message,
1075
+ inProgress,
1076
+ index,
1077
+ isCurrentMessage,
1078
+ onRegenerate,
1079
+ onCopy,
1080
+ onThumbsUp,
1081
+ onThumbsDown,
1082
+ markdownTagRenderers
1083
+ } = props;
1084
+ switch (message.role) {
1085
+ case "user":
1086
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1087
+ UserMessage2,
1088
+ {
1089
+ rawData: message,
1090
+ "data-message-role": "user",
1091
+ message,
1092
+ ImageRenderer: ImageRenderer2
1093
+ },
1094
+ index
1095
+ );
1096
+ case "assistant":
1097
+ return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
1098
+ AssistantMessage2,
1099
+ {
1100
+ "data-message-role": "assistant",
1101
+ subComponent: (_a2 = message.generativeUI) == null ? void 0 : _a2.call(message),
1102
+ rawData: message,
1103
+ message,
1104
+ isLoading: inProgress && isCurrentMessage && !message.content,
1105
+ isGenerating: inProgress && isCurrentMessage && !!message.content,
1106
+ isCurrentMessage,
1107
+ onRegenerate: () => onRegenerate == null ? void 0 : onRegenerate(message.id),
1108
+ onCopy,
1109
+ onThumbsUp,
1110
+ onThumbsDown,
1111
+ markdownTagRenderers,
1112
+ ImageRenderer: ImageRenderer2
1113
+ },
1114
+ index
1115
+ );
1116
+ }
1117
+ }
1118
+
1119
+ // src/components/chat/messages/LegacyRenderMessage.tsx
1120
+ var import_runtime_client_gql = require("@copilotkit/runtime-client-gql");
1121
+ var import_jsx_runtime9 = require("react/jsx-runtime");
1122
+ var LegacyRenderMessage = ({
1123
+ message,
1124
+ inProgress,
1125
+ index,
1126
+ isCurrentMessage,
1127
+ actionResult,
1128
+ AssistantMessage: AssistantMessage2,
1129
+ UserMessage: UserMessage2,
1130
+ ImageRenderer: ImageRenderer2,
1131
+ onRegenerate,
1132
+ onCopy,
1133
+ onThumbsUp,
1134
+ onThumbsDown,
1135
+ markdownTagRenderers,
1136
+ legacyProps
1137
+ }) => {
1138
+ var _a;
1139
+ const {
1140
+ RenderTextMessage,
1141
+ RenderActionExecutionMessage,
1142
+ RenderAgentStateMessage,
1143
+ RenderResultMessage,
1144
+ RenderImageMessage
1145
+ } = legacyProps;
1146
+ const deprecatedMessage = (_a = (0, import_runtime_client_gql.aguiToGQL)(message)[0]) != null ? _a : void 0;
1147
+ if (deprecatedMessage.isTextMessage() && RenderTextMessage) {
1148
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1149
+ RenderTextMessage,
1150
+ {
1151
+ message,
1152
+ inProgress,
1153
+ index,
1154
+ isCurrentMessage,
1155
+ AssistantMessage: AssistantMessage2,
1156
+ UserMessage: UserMessage2,
1157
+ onRegenerate,
1158
+ onCopy,
1159
+ onThumbsUp,
1160
+ onThumbsDown,
1161
+ markdownTagRenderers
1162
+ }
1163
+ );
1164
+ }
1165
+ if (deprecatedMessage.isActionExecutionMessage() && RenderActionExecutionMessage) {
1166
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1167
+ RenderActionExecutionMessage,
1168
+ {
1169
+ message,
1170
+ inProgress,
1171
+ index,
1172
+ isCurrentMessage,
1173
+ actionResult,
1174
+ AssistantMessage: AssistantMessage2,
1175
+ UserMessage: UserMessage2
1176
+ }
1177
+ );
1178
+ }
1179
+ if (deprecatedMessage.isAgentStateMessage() && RenderAgentStateMessage) {
1180
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1181
+ RenderAgentStateMessage,
1182
+ {
1183
+ message,
1184
+ inProgress,
1185
+ index,
1186
+ isCurrentMessage,
1187
+ AssistantMessage: AssistantMessage2,
1188
+ UserMessage: UserMessage2
1189
+ }
1190
+ );
1191
+ }
1192
+ if (deprecatedMessage.isResultMessage() && RenderResultMessage) {
1193
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1194
+ RenderResultMessage,
1195
+ {
1196
+ message,
1197
+ inProgress,
1198
+ index,
1199
+ isCurrentMessage,
1200
+ AssistantMessage: AssistantMessage2,
1201
+ UserMessage: UserMessage2
1202
+ }
1203
+ );
1204
+ }
1205
+ if (deprecatedMessage.isImageMessage() && RenderImageMessage) {
1206
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1207
+ RenderImageMessage,
1208
+ {
1209
+ message,
1210
+ inProgress,
1211
+ index,
1212
+ isCurrentMessage,
1213
+ AssistantMessage: AssistantMessage2,
1214
+ UserMessage: UserMessage2
1215
+ }
1216
+ );
1217
+ }
1218
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1219
+ RenderMessage,
1220
+ {
1221
+ message,
1222
+ inProgress,
1223
+ index,
1224
+ isCurrentMessage,
1225
+ AssistantMessage: AssistantMessage2,
1226
+ UserMessage: UserMessage2,
1227
+ ImageRenderer: ImageRenderer2,
1228
+ onRegenerate,
1229
+ onCopy,
1230
+ onThumbsUp,
1231
+ onThumbsDown,
1232
+ markdownTagRenderers
1233
+ }
1234
+ );
1235
+ };
1236
+
1237
+ // src/components/chat/Messages.tsx
1238
+ var import_jsx_runtime10 = require("react/jsx-runtime");
1239
+ var Messages = ({
1240
+ inProgress,
1241
+ children,
1242
+ RenderMessage: RenderMessage2,
1243
+ AssistantMessage: AssistantMessage2,
1244
+ UserMessage: UserMessage2,
1245
+ ImageRenderer: ImageRenderer2,
1246
+ onRegenerate,
1247
+ onCopy,
1248
+ onThumbsUp,
1249
+ onThumbsDown,
1250
+ markdownTagRenderers,
1251
+ // Legacy props
1252
+ RenderTextMessage,
1253
+ RenderActionExecutionMessage,
1254
+ RenderAgentStateMessage,
1255
+ RenderResultMessage,
1256
+ RenderImageMessage
1257
+ }) => {
1258
+ const { labels } = useChatContext();
1259
+ const { messages: visibleMessages, interrupt } = (0, import_react_core.useCopilotChatInternal)();
1260
+ const initialMessages = (0, import_react6.useMemo)(() => makeInitialMessages(labels.initial), [labels.initial]);
1261
+ const messages = [...initialMessages, ...visibleMessages];
1262
+ const { messagesContainerRef, messagesEndRef } = useScrollToBottom(messages);
1263
+ const hasLegacyProps = !!(RenderTextMessage || RenderActionExecutionMessage || RenderAgentStateMessage || RenderResultMessage || RenderImageMessage);
1264
+ (0, import_react6.useEffect)(() => {
1265
+ if (hasLegacyProps) {
1266
+ console.warn(
1267
+ "[CopilotKit] Legacy message render props (RenderTextMessage, RenderActionExecutionMessage, etc.) are deprecated. Please use the unified 'RenderMessage' prop instead. See migration guide: https://docs.copilotkit.ai/migration/render-message"
1268
+ );
1269
+ }
1270
+ }, [hasLegacyProps]);
1271
+ const legacyProps = (0, import_react6.useMemo)(
1272
+ () => ({
1273
+ RenderTextMessage,
1274
+ RenderActionExecutionMessage,
1275
+ RenderAgentStateMessage,
1276
+ RenderResultMessage,
1277
+ RenderImageMessage
1278
+ }),
1279
+ [
1280
+ RenderTextMessage,
1281
+ RenderActionExecutionMessage,
1282
+ RenderAgentStateMessage,
1283
+ RenderResultMessage,
1284
+ RenderImageMessage
1285
+ ]
1286
+ );
1287
+ const MessageRenderer = hasLegacyProps ? (props) => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LegacyRenderMessage, __spreadProps(__spreadValues({}, props), { legacyProps })) : RenderMessage2;
1288
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "copilotKitMessages", ref: messagesContainerRef, children: [
1289
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "copilotKitMessagesContainer", children: [
1290
+ messages.map((message, index) => {
1291
+ const isCurrentMessage = index === messages.length - 1;
1292
+ return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1293
+ MessageRenderer,
1294
+ {
1295
+ message,
1296
+ inProgress,
1297
+ index,
1298
+ isCurrentMessage,
1299
+ AssistantMessage: AssistantMessage2,
1300
+ UserMessage: UserMessage2,
1301
+ ImageRenderer: ImageRenderer2,
1302
+ onRegenerate,
1303
+ onCopy,
1304
+ onThumbsUp,
1305
+ onThumbsDown,
1306
+ markdownTagRenderers
1307
+ },
1308
+ index
1309
+ );
1310
+ }),
1311
+ interrupt
1312
+ ] }),
1313
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("footer", { className: "copilotKitMessagesFooter", ref: messagesEndRef, children })
1314
+ ] });
1315
+ };
1316
+ function makeInitialMessages(initial) {
1317
+ if (!initial)
1318
+ return [];
1319
+ if (Array.isArray(initial)) {
1320
+ return initial.map((message) => {
1321
+ return {
1322
+ id: message,
1323
+ role: "assistant",
1324
+ content: message
1325
+ };
1326
+ });
1327
+ }
1328
+ return [
1329
+ {
1330
+ id: initial,
1331
+ role: "assistant",
1332
+ content: initial
1333
+ }
1334
+ ];
1335
+ }
1336
+ function useScrollToBottom(messages) {
1337
+ const messagesEndRef = (0, import_react6.useRef)(null);
1338
+ const messagesContainerRef = (0, import_react6.useRef)(null);
1339
+ const isProgrammaticScrollRef = (0, import_react6.useRef)(false);
1340
+ const isUserScrollUpRef = (0, import_react6.useRef)(false);
1341
+ const scrollToBottom = () => {
1342
+ if (messagesContainerRef.current && messagesEndRef.current) {
1343
+ isProgrammaticScrollRef.current = true;
1344
+ messagesContainerRef.current.scrollTop = messagesContainerRef.current.scrollHeight;
1345
+ }
1346
+ };
1347
+ const handleScroll = () => {
1348
+ if (isProgrammaticScrollRef.current) {
1349
+ isProgrammaticScrollRef.current = false;
1350
+ return;
1351
+ }
1352
+ if (messagesContainerRef.current) {
1353
+ const { scrollTop, scrollHeight, clientHeight } = messagesContainerRef.current;
1354
+ isUserScrollUpRef.current = scrollTop + clientHeight < scrollHeight;
1355
+ }
1356
+ };
1357
+ (0, import_react6.useEffect)(() => {
1358
+ const container = messagesContainerRef.current;
1359
+ if (container) {
1360
+ container.addEventListener("scroll", handleScroll);
1361
+ }
1362
+ return () => {
1363
+ if (container) {
1364
+ container.removeEventListener("scroll", handleScroll);
1365
+ }
1366
+ };
1367
+ }, []);
1368
+ (0, import_react6.useEffect)(() => {
1369
+ const container = messagesContainerRef.current;
1370
+ if (!container) {
1371
+ return;
1372
+ }
1373
+ const mutationObserver = new MutationObserver(() => {
1374
+ if (!isUserScrollUpRef.current) {
1375
+ scrollToBottom();
1376
+ }
1377
+ });
1378
+ mutationObserver.observe(container, {
1379
+ childList: true,
1380
+ subtree: true,
1381
+ characterData: true
1382
+ });
1383
+ return () => {
1384
+ mutationObserver.disconnect();
1385
+ };
1386
+ }, []);
1387
+ (0, import_react6.useEffect)(() => {
1388
+ isUserScrollUpRef.current = false;
1389
+ scrollToBottom();
1390
+ }, [messages.filter((m) => m.role === "user").length]);
1391
+ return { messagesEndRef, messagesContainerRef };
1392
+ }
1393
+
1394
+ // src/components/chat/Input.tsx
1395
+ var import_react9 = require("react");
1396
+
1397
+ // src/components/chat/Textarea.tsx
1398
+ var import_react7 = require("react");
1399
+ var import_jsx_runtime11 = require("react/jsx-runtime");
1400
+ var AutoResizingTextarea = (0, import_react7.forwardRef)(
1401
+ ({
1402
+ maxRows = 1,
1403
+ placeholder,
1404
+ value,
1405
+ onChange,
1406
+ onKeyDown,
1407
+ onCompositionStart,
1408
+ onCompositionEnd,
1409
+ autoFocus
1410
+ }, ref) => {
1411
+ const internalTextareaRef = (0, import_react7.useRef)(null);
1412
+ const [maxHeight, setMaxHeight] = (0, import_react7.useState)(0);
1413
+ (0, import_react7.useImperativeHandle)(ref, () => internalTextareaRef.current);
1414
+ (0, import_react7.useEffect)(() => {
1415
+ const calculateMaxHeight = () => {
1416
+ const textarea = internalTextareaRef.current;
1417
+ if (textarea) {
1418
+ textarea.style.height = "auto";
1419
+ const singleRowHeight = textarea.scrollHeight;
1420
+ setMaxHeight(singleRowHeight * maxRows);
1421
+ if (autoFocus) {
1422
+ textarea.focus();
1423
+ }
1424
+ }
1425
+ };
1426
+ calculateMaxHeight();
1427
+ }, [maxRows]);
1428
+ (0, import_react7.useEffect)(() => {
1429
+ const textarea = internalTextareaRef.current;
1430
+ if (textarea) {
1431
+ textarea.style.height = "auto";
1432
+ textarea.style.height = `${Math.min(textarea.scrollHeight, maxHeight)}px`;
1433
+ }
1434
+ }, [value, maxHeight]);
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1436
+ "textarea",
1437
+ {
1438
+ ref: internalTextareaRef,
1439
+ value,
1440
+ onChange,
1441
+ onKeyDown,
1442
+ onCompositionStart,
1443
+ onCompositionEnd,
1444
+ placeholder,
1445
+ style: {
1446
+ overflow: "auto",
1447
+ resize: "none",
1448
+ maxHeight: `${maxHeight}px`
1449
+ },
1450
+ rows: 1
1451
+ }
1452
+ );
1453
+ }
1454
+ );
1455
+ var Textarea_default = AutoResizingTextarea;
1236
1456
 
1237
- // src/components/chat/Markdown.tsx
1238
- var import_remark_gfm = __toESM(require("remark-gfm"));
1239
- var import_remark_math = __toESM(require("remark-math"));
1240
- var import_rehype_raw = __toESM(require("rehype-raw"));
1241
- var import_jsx_runtime9 = require("react/jsx-runtime");
1242
- var defaultComponents = {
1243
- a(_a) {
1244
- var _b = _a, { children } = _b, props = __objRest(_b, ["children"]);
1245
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("a", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { target: "_blank", rel: "noopener noreferrer", children }));
1246
- },
1247
- // @ts-expect-error -- inline
1248
- code(_c) {
1249
- var _d = _c, { children, className, inline } = _d, props = __objRest(_d, ["children", "className", "inline"]);
1250
- if (Array.isArray(children) && children.length) {
1251
- if (children[0] == "\u258D") {
1252
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1253
- "span",
1254
- {
1255
- style: {
1256
- animation: "pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite",
1257
- marginTop: "0.25rem"
1258
- },
1259
- children: "\u258D"
1260
- }
1457
+ // src/hooks/use-push-to-talk.tsx
1458
+ var import_react_core2 = require("@copilotkit/react-core");
1459
+ var import_runtime_client_gql2 = require("@copilotkit/runtime-client-gql");
1460
+ var import_react8 = require("react");
1461
+ var startRecording = (mediaStreamRef, mediaRecorderRef, audioContextRef, recordedChunks, onStop) => __async(void 0, null, function* () {
1462
+ if (!mediaStreamRef.current || !audioContextRef.current) {
1463
+ mediaStreamRef.current = yield navigator.mediaDevices.getUserMedia({ audio: true });
1464
+ audioContextRef.current = new window.AudioContext();
1465
+ yield audioContextRef.current.resume();
1466
+ }
1467
+ mediaRecorderRef.current = new MediaRecorder(mediaStreamRef.current);
1468
+ mediaRecorderRef.current.start(1e3);
1469
+ mediaRecorderRef.current.ondataavailable = (event) => {
1470
+ recordedChunks.push(event.data);
1471
+ };
1472
+ mediaRecorderRef.current.onstop = onStop;
1473
+ });
1474
+ var stopRecording = (mediaRecorderRef) => {
1475
+ if (mediaRecorderRef.current && mediaRecorderRef.current.state !== "inactive") {
1476
+ mediaRecorderRef.current.stop();
1477
+ }
1478
+ };
1479
+ var transcribeAudio = (recordedChunks, transcribeAudioUrl) => __async(void 0, null, function* () {
1480
+ const completeBlob = new Blob(recordedChunks, { type: "audio/mp4" });
1481
+ const formData = new FormData();
1482
+ formData.append("file", completeBlob, "recording.mp4");
1483
+ const response = yield fetch(transcribeAudioUrl, {
1484
+ method: "POST",
1485
+ body: formData
1486
+ });
1487
+ if (!response.ok) {
1488
+ throw new Error(`Error: ${response.statusText}`);
1489
+ }
1490
+ const transcription = yield response.json();
1491
+ return transcription.text;
1492
+ });
1493
+ var playAudioResponse = (text, textToSpeechUrl, audioContext) => {
1494
+ const encodedText = encodeURIComponent(text);
1495
+ const url = `${textToSpeechUrl}?text=${encodedText}`;
1496
+ fetch(url).then((response) => response.arrayBuffer()).then((arrayBuffer) => audioContext.decodeAudioData(arrayBuffer)).then((audioBuffer) => {
1497
+ const source = audioContext.createBufferSource();
1498
+ source.buffer = audioBuffer;
1499
+ source.connect(audioContext.destination);
1500
+ source.start(0);
1501
+ }).catch((error) => {
1502
+ console.error("Error with decoding audio data", error);
1503
+ });
1504
+ };
1505
+ var usePushToTalk = ({
1506
+ sendFunction,
1507
+ inProgress
1508
+ }) => {
1509
+ const [pushToTalkState, setPushToTalkState] = (0, import_react8.useState)("idle");
1510
+ const mediaStreamRef = (0, import_react8.useRef)(null);
1511
+ const audioContextRef = (0, import_react8.useRef)(null);
1512
+ const mediaRecorderRef = (0, import_react8.useRef)(null);
1513
+ const recordedChunks = (0, import_react8.useRef)([]);
1514
+ const generalContext = (0, import_react_core2.useCopilotContext)();
1515
+ const messagesContext = (0, import_react_core2.useCopilotMessagesContext)();
1516
+ const context = __spreadValues(__spreadValues({}, generalContext), messagesContext);
1517
+ const [startReadingFromMessageId, setStartReadingFromMessageId] = (0, import_react8.useState)(null);
1518
+ (0, import_react8.useEffect)(() => {
1519
+ if (pushToTalkState === "recording") {
1520
+ startRecording(
1521
+ mediaStreamRef,
1522
+ mediaRecorderRef,
1523
+ audioContextRef,
1524
+ recordedChunks.current,
1525
+ () => {
1526
+ setPushToTalkState("transcribing");
1527
+ }
1528
+ );
1529
+ } else {
1530
+ stopRecording(mediaRecorderRef);
1531
+ if (pushToTalkState === "transcribing") {
1532
+ transcribeAudio(recordedChunks.current, context.copilotApiConfig.transcribeAudioUrl).then(
1533
+ (transcription) => __async(void 0, null, function* () {
1534
+ recordedChunks.current = [];
1535
+ setPushToTalkState("idle");
1536
+ const message = yield sendFunction(transcription);
1537
+ setStartReadingFromMessageId(message.id);
1538
+ })
1261
1539
  );
1262
1540
  }
1263
- children[0] = (children == null ? void 0 : children[0]).replace("`\u258D`", "\u258D");
1264
1541
  }
1265
- const match = /language-(\w+)/.exec(className || "");
1266
- const hasLanguage = match && match[1];
1267
- const content = String(children);
1268
- const hasNewlines = content.includes("\n");
1269
- const isInline = !hasLanguage && !hasNewlines;
1270
- if (isInline) {
1271
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1272
- "code",
1273
- __spreadProps(__spreadValues({
1274
- className: `copilotKitMarkdownElement copilotKitInlineCode ${className || ""}`
1275
- }, props), {
1276
- children
1277
- })
1542
+ return () => {
1543
+ stopRecording(mediaRecorderRef);
1544
+ };
1545
+ }, [pushToTalkState]);
1546
+ (0, import_react8.useEffect)(() => {
1547
+ if (inProgress === false && startReadingFromMessageId) {
1548
+ const lastMessageIndex = context.messages.findIndex(
1549
+ (message) => message.id === startReadingFromMessageId
1278
1550
  );
1551
+ const aguiMessages = (0, import_runtime_client_gql2.gqlToAGUI)(context.messages);
1552
+ const messagesAfterLast = aguiMessages.slice(lastMessageIndex + 1).filter((message) => message.role === "assistant");
1553
+ const text = messagesAfterLast.map((message) => message.content).join("\n");
1554
+ playAudioResponse(text, context.copilotApiConfig.textToSpeechUrl, audioContextRef.current);
1555
+ setStartReadingFromMessageId(null);
1279
1556
  }
1280
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1281
- CodeBlock,
1282
- __spreadValues({
1283
- language: match && match[1] || "",
1284
- value: String(children).replace(/\n$/, "")
1285
- }, props),
1286
- Math.random()
1287
- );
1288
- },
1289
- h1: (_e) => {
1290
- var _f = _e, { children } = _f, props = __objRest(_f, ["children"]);
1291
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h1", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1292
- },
1293
- h2: (_g) => {
1294
- var _h = _g, { children } = _h, props = __objRest(_h, ["children"]);
1295
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h2", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1296
- },
1297
- h3: (_i) => {
1298
- var _j = _i, { children } = _j, props = __objRest(_j, ["children"]);
1299
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h3", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1300
- },
1301
- h4: (_k) => {
1302
- var _l = _k, { children } = _l, props = __objRest(_l, ["children"]);
1303
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h4", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1304
- },
1305
- h5: (_m) => {
1306
- var _n = _m, { children } = _n, props = __objRest(_n, ["children"]);
1307
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h5", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1308
- },
1309
- h6: (_o) => {
1310
- var _p = _o, { children } = _p, props = __objRest(_p, ["children"]);
1311
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("h6", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1312
- },
1313
- p: (_q) => {
1314
- var _r = _q, { children } = _r, props = __objRest(_r, ["children"]);
1315
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("p", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1316
- },
1317
- pre: (_s) => {
1318
- var _t = _s, { children } = _t, props = __objRest(_t, ["children"]);
1319
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("pre", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1320
- },
1321
- blockquote: (_u) => {
1322
- var _v = _u, { children } = _v, props = __objRest(_v, ["children"]);
1323
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("blockquote", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1324
- },
1325
- ul: (_w) => {
1326
- var _x = _w, { children } = _x, props = __objRest(_x, ["children"]);
1327
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("ul", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1328
- },
1329
- li: (_y) => {
1330
- var _z = _y, { children } = _z, props = __objRest(_z, ["children"]);
1331
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("li", __spreadProps(__spreadValues({ className: "copilotKitMarkdownElement" }, props), { children }));
1332
- }
1557
+ }, [startReadingFromMessageId, inProgress]);
1558
+ return { pushToTalkState, setPushToTalkState };
1333
1559
  };
1334
- var MemoizedReactMarkdown = (0, import_react7.memo)(
1335
- import_react_markdown.default,
1336
- (prevProps, nextProps) => prevProps.children === nextProps.children && prevProps.components === nextProps.components
1337
- );
1338
- var Markdown = ({ content, components }) => {
1339
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "copilotKitMarkdown", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
1340
- MemoizedReactMarkdown,
1341
- {
1342
- components: __spreadValues(__spreadValues({}, defaultComponents), components),
1343
- remarkPlugins: [import_remark_gfm.default, import_remark_math.default],
1344
- rehypePlugins: [import_rehype_raw.default],
1345
- children: content
1346
- }
1347
- ) });
1560
+
1561
+ // src/components/chat/Input.tsx
1562
+ var import_react_core3 = require("@copilotkit/react-core");
1563
+
1564
+ // src/hooks/use-dark-mode.ts
1565
+ var useDarkMode = () => {
1566
+ if (typeof window === "undefined")
1567
+ return false;
1568
+ return document.documentElement.classList.contains("dark") || document.body.classList.contains("dark") || document.documentElement.getAttribute("data-theme") === "dark" || document.body.getAttribute("data-theme") === "dark" || window.matchMedia("(prefers-color-scheme: dark)").matches;
1348
1569
  };
1349
1570
 
1350
- // src/components/chat/messages/AssistantMessage.tsx
1351
- var import_react8 = require("react");
1352
- var import_jsx_runtime10 = require("react/jsx-runtime");
1353
- var AssistantMessage = (props) => {
1354
- var _a;
1355
- const { icons, labels } = useChatContext();
1356
- const {
1357
- message,
1358
- isLoading,
1359
- onRegenerate,
1360
- onCopy,
1361
- onThumbsUp,
1362
- onThumbsDown,
1363
- isCurrentMessage,
1364
- markdownTagRenderers
1365
- } = props;
1366
- const [copied, setCopied] = (0, import_react8.useState)(false);
1367
- const handleCopy = () => {
1368
- const content2 = (message == null ? void 0 : message.content) || "";
1369
- if (content2 && onCopy) {
1370
- navigator.clipboard.writeText(content2);
1371
- setCopied(true);
1372
- onCopy(content2);
1373
- setTimeout(() => setCopied(false), 2e3);
1374
- } else if (content2) {
1375
- navigator.clipboard.writeText(content2);
1376
- setCopied(true);
1377
- setTimeout(() => setCopied(false), 2e3);
1378
- }
1379
- };
1380
- const handleRegenerate = () => {
1381
- if (onRegenerate)
1382
- onRegenerate();
1571
+ // src/components/chat/PoweredByTag.tsx
1572
+ var import_jsx_runtime12 = require("react/jsx-runtime");
1573
+ function PoweredByTag({ showPoweredBy = true }) {
1574
+ const isDark = useDarkMode();
1575
+ if (!showPoweredBy) {
1576
+ return null;
1577
+ }
1578
+ const poweredByStyle = {
1579
+ visibility: "visible",
1580
+ display: "block",
1581
+ position: "static",
1582
+ textAlign: "center",
1583
+ fontSize: "12px",
1584
+ padding: "3px 0",
1585
+ color: isDark ? "rgb(69, 69, 69)" : "rgb(214, 214, 214)"
1383
1586
  };
1384
- const handleThumbsUp = () => {
1385
- if (onThumbsUp && message)
1386
- onThumbsUp(message);
1587
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("p", { className: "poweredBy", style: poweredByStyle, children: "Powered by CopilotKit" }) });
1588
+ }
1589
+
1590
+ // src/components/chat/Input.tsx
1591
+ var import_jsx_runtime13 = require("react/jsx-runtime");
1592
+ var MAX_NEWLINES = 6;
1593
+ var Input = ({
1594
+ inProgress,
1595
+ onSend,
1596
+ isVisible = false,
1597
+ onStop,
1598
+ onUpload,
1599
+ hideStopButton = false
1600
+ }) => {
1601
+ var _a, _b;
1602
+ const context = useChatContext();
1603
+ const copilotContext = (0, import_react_core3.useCopilotContext)();
1604
+ const showPoweredBy = !((_a = copilotContext.copilotApiConfig) == null ? void 0 : _a.publicApiKey);
1605
+ const pushToTalkConfigured = copilotContext.copilotApiConfig.textToSpeechUrl !== void 0 && copilotContext.copilotApiConfig.transcribeAudioUrl !== void 0;
1606
+ const textareaRef = (0, import_react9.useRef)(null);
1607
+ const [isComposing, setIsComposing] = (0, import_react9.useState)(false);
1608
+ const handleDivClick = (event) => {
1609
+ var _a2;
1610
+ const target = event.target;
1611
+ if (target.closest("button"))
1612
+ return;
1613
+ if (target.tagName === "TEXTAREA")
1614
+ return;
1615
+ (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
1387
1616
  };
1388
- const handleThumbsDown = () => {
1389
- if (onThumbsDown && message)
1390
- onThumbsDown(message);
1617
+ const [text, setText] = (0, import_react9.useState)("");
1618
+ const send = () => {
1619
+ var _a2;
1620
+ if (inProgress)
1621
+ return;
1622
+ onSend(text);
1623
+ setText("");
1624
+ (_a2 = textareaRef.current) == null ? void 0 : _a2.focus();
1391
1625
  };
1392
- const LoadingIcon = () => /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { children: icons.activityIcon });
1393
- const content = (message == null ? void 0 : message.content) || "";
1394
- const subComponent = (_a = message == null ? void 0 : message.generativeUI) == null ? void 0 : _a.call(message);
1395
- return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_jsx_runtime10.Fragment, { children: [
1396
- content && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "copilotKitMessage copilotKitAssistantMessage", children: [
1397
- content && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(Markdown, { content, components: markdownTagRenderers }),
1398
- content && !isLoading && /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(
1399
- "div",
1626
+ const { pushToTalkState, setPushToTalkState } = usePushToTalk({
1627
+ sendFunction: onSend,
1628
+ inProgress
1629
+ });
1630
+ const isInProgress = inProgress || pushToTalkState === "transcribing";
1631
+ const buttonIcon = isInProgress && !hideStopButton ? context.icons.stopIcon : context.icons.sendIcon;
1632
+ const showPushToTalk = pushToTalkConfigured && (pushToTalkState === "idle" || pushToTalkState === "recording") && !inProgress;
1633
+ const canSend = (0, import_react9.useMemo)(() => {
1634
+ var _a2;
1635
+ const interruptEvent = (_a2 = copilotContext.langGraphInterruptAction) == null ? void 0 : _a2.event;
1636
+ const interruptInProgress = (interruptEvent == null ? void 0 : interruptEvent.name) === "LangGraphInterruptEvent" && !(interruptEvent == null ? void 0 : interruptEvent.response);
1637
+ return !isInProgress && text.trim().length > 0 && pushToTalkState === "idle" && !interruptInProgress;
1638
+ }, [(_b = copilotContext.langGraphInterruptAction) == null ? void 0 : _b.event, isInProgress, text, pushToTalkState]);
1639
+ const canStop = (0, import_react9.useMemo)(() => {
1640
+ return isInProgress && !hideStopButton;
1641
+ }, [isInProgress, hideStopButton]);
1642
+ const sendDisabled = !canSend && !canStop;
1643
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: `copilotKitInputContainer ${showPoweredBy ? "poweredByContainer" : ""}`, children: [
1644
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "copilotKitInput", onClick: handleDivClick, children: [
1645
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1646
+ Textarea_default,
1400
1647
  {
1401
- className: `copilotKitMessageControls ${isCurrentMessage ? "currentMessage" : ""}`,
1402
- children: [
1403
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1404
- "button",
1405
- {
1406
- className: "copilotKitMessageControlButton",
1407
- onClick: handleRegenerate,
1408
- "aria-label": labels.regenerateResponse,
1409
- title: labels.regenerateResponse,
1410
- children: icons.regenerateIcon
1411
- }
1412
- ),
1413
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1414
- "button",
1415
- {
1416
- className: "copilotKitMessageControlButton",
1417
- onClick: handleCopy,
1418
- "aria-label": labels.copyToClipboard,
1419
- title: labels.copyToClipboard,
1420
- children: copied ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { style: { fontSize: "10px", fontWeight: "bold" }, children: "\u2713" }) : icons.copyIcon
1421
- }
1422
- ),
1423
- onThumbsUp && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1424
- "button",
1425
- {
1426
- className: "copilotKitMessageControlButton",
1427
- onClick: handleThumbsUp,
1428
- "aria-label": labels.thumbsUp,
1429
- title: labels.thumbsUp,
1430
- children: icons.thumbsUpIcon
1431
- }
1432
- ),
1433
- onThumbsDown && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
1434
- "button",
1435
- {
1436
- className: "copilotKitMessageControlButton",
1437
- onClick: handleThumbsDown,
1438
- "aria-label": labels.thumbsDown,
1439
- title: labels.thumbsDown,
1440
- children: icons.thumbsDownIcon
1648
+ ref: textareaRef,
1649
+ placeholder: context.labels.placeholder,
1650
+ autoFocus: false,
1651
+ maxRows: MAX_NEWLINES,
1652
+ value: text,
1653
+ onChange: (event) => setText(event.target.value),
1654
+ onCompositionStart: () => setIsComposing(true),
1655
+ onCompositionEnd: () => setIsComposing(false),
1656
+ onKeyDown: (event) => {
1657
+ if (event.key === "Enter" && !event.shiftKey && !isComposing) {
1658
+ event.preventDefault();
1659
+ if (canSend) {
1660
+ send();
1441
1661
  }
1442
- )
1443
- ]
1662
+ }
1663
+ }
1444
1664
  }
1445
- )
1665
+ ),
1666
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "copilotKitInputControls", children: [
1667
+ onUpload && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("button", { onClick: onUpload, className: "copilotKitInputControlButton", children: context.icons.uploadIcon }),
1668
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { style: { flexGrow: 1 } }),
1669
+ showPushToTalk && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1670
+ "button",
1671
+ {
1672
+ onClick: () => setPushToTalkState(pushToTalkState === "idle" ? "recording" : "transcribing"),
1673
+ className: pushToTalkState === "recording" ? "copilotKitInputControlButton copilotKitPushToTalkRecording" : "copilotKitInputControlButton",
1674
+ children: context.icons.pushToTalkIcon
1675
+ }
1676
+ ),
1677
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1678
+ "button",
1679
+ {
1680
+ disabled: sendDisabled,
1681
+ onClick: isInProgress && !hideStopButton ? onStop : send,
1682
+ "data-copilotkit-in-progress": inProgress,
1683
+ "data-test-id": inProgress ? "copilot-chat-request-in-progress" : "copilot-chat-ready",
1684
+ className: "copilotKitInputControlButton",
1685
+ children: buttonIcon
1686
+ }
1687
+ )
1688
+ ] })
1446
1689
  ] }),
1447
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { style: { marginBottom: "0.5rem" }, children: subComponent }),
1448
- isLoading && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(LoadingIcon, {})
1449
- ] });
1450
- };
1451
-
1452
- // src/components/chat/messages/ImageRenderer.tsx
1453
- var import_react9 = require("react");
1454
- var import_jsx_runtime11 = require("react/jsx-runtime");
1455
- var ImageRenderer = ({ image, content, className = "" }) => {
1456
- const [imageError, setImageError] = (0, import_react9.useState)(false);
1457
- const imageSrc = `data:image/${image.format};base64,${image.bytes}`;
1458
- const altText = content || "User uploaded image";
1459
- const handleImageError = () => {
1460
- setImageError(true);
1461
- };
1462
- if (imageError) {
1463
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `copilotKitImageRendering copilotKitImageRenderingError ${className}`, children: [
1464
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "copilotKitImageRenderingErrorMessage", children: "Failed to load image" }),
1465
- content && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "copilotKitImageRenderingContent", children: content })
1466
- ] });
1467
- }
1468
- return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: `copilotKitImageRendering ${className}`, children: [
1469
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
1470
- "img",
1471
- {
1472
- src: imageSrc,
1473
- alt: altText,
1474
- className: "copilotKitImageRenderingImage",
1475
- onError: handleImageError
1476
- }
1477
- ),
1478
- content && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { className: "copilotKitImageRenderingContent", children: content })
1690
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(PoweredByTag, { showPoweredBy })
1479
1691
  ] });
1480
1692
  };
1481
1693
 
1482
- // src/components/chat/messages/RenderMessage.tsx
1483
- var import_jsx_runtime12 = require("react/jsx-runtime");
1484
- function RenderMessage(_a) {
1485
- var _b = _a, {
1486
- UserMessage: UserMessage2 = UserMessage,
1487
- AssistantMessage: AssistantMessage2 = AssistantMessage,
1488
- ImageRenderer: ImageRenderer2 = ImageRenderer
1489
- } = _b, props = __objRest(_b, [
1490
- "UserMessage",
1491
- "AssistantMessage",
1492
- "ImageRenderer"
1493
- ]);
1494
- const {
1495
- message,
1496
- inProgress,
1497
- index,
1498
- isCurrentMessage,
1499
- onRegenerate,
1500
- onCopy,
1501
- onThumbsUp,
1502
- onThumbsDown,
1503
- markdownTagRenderers
1504
- } = props;
1505
- switch (message.role) {
1506
- case "user":
1507
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1508
- UserMessage2,
1509
- {
1510
- "data-message-role": "user",
1511
- message,
1512
- ImageRenderer: ImageRenderer2
1513
- },
1514
- index
1515
- );
1516
- case "assistant":
1517
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
1518
- AssistantMessage2,
1519
- {
1520
- "data-message-role": "assistant",
1521
- message,
1522
- isLoading: inProgress && isCurrentMessage && !message.content,
1523
- isGenerating: inProgress && isCurrentMessage && !!message.content,
1524
- isCurrentMessage,
1525
- onRegenerate: () => onRegenerate == null ? void 0 : onRegenerate(message.id),
1526
- onCopy,
1527
- onThumbsUp,
1528
- onThumbsDown,
1529
- markdownTagRenderers,
1530
- ImageRenderer: ImageRenderer2
1531
- },
1532
- index
1533
- );
1534
- }
1535
- }
1536
-
1537
1694
  // src/components/chat/Chat.tsx
1538
1695
  var import_react10 = __toESM(require("react"));
1539
1696
  var import_react_core5 = require("@copilotkit/react-core");
1540
1697
  var import_shared = require("@copilotkit/shared");
1698
+ var import_shared2 = require("@copilotkit/shared");
1541
1699
  var import_react_core6 = require("@copilotkit/react-core");
1542
1700
 
1543
1701
  // src/components/chat/ImageUploadQueue.tsx
1544
- var import_jsx_runtime13 = require("react/jsx-runtime");
1702
+ var import_jsx_runtime14 = require("react/jsx-runtime");
1545
1703
  var ImageUploadQueue = ({
1546
1704
  images,
1547
1705
  onRemoveImage,
@@ -1549,7 +1707,7 @@ var ImageUploadQueue = ({
1549
1707
  }) => {
1550
1708
  if (images.length === 0)
1551
1709
  return null;
1552
- return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1710
+ return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1553
1711
  "div",
1554
1712
  {
1555
1713
  className: `copilotKitImageUploadQueue ${className}`,
@@ -1560,7 +1718,7 @@ var ImageUploadQueue = ({
1560
1718
  margin: "8px",
1561
1719
  padding: "8px"
1562
1720
  },
1563
- children: images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
1721
+ children: images.map((image, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
1564
1722
  "div",
1565
1723
  {
1566
1724
  className: "copilotKitImageUploadQueueItem",
@@ -1573,7 +1731,7 @@ var ImageUploadQueue = ({
1573
1731
  overflow: "hidden"
1574
1732
  },
1575
1733
  children: [
1576
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1734
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1577
1735
  "img",
1578
1736
  {
1579
1737
  src: `data:${image.contentType};base64,${image.bytes}`,
@@ -1585,7 +1743,7 @@ var ImageUploadQueue = ({
1585
1743
  }
1586
1744
  }
1587
1745
  ),
1588
- /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
1746
+ /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1589
1747
  "button",
1590
1748
  {
1591
1749
  onClick: () => onRemoveImage(index),
@@ -1620,12 +1778,12 @@ var ImageUploadQueue = ({
1620
1778
 
1621
1779
  // src/components/chat/Suggestion.tsx
1622
1780
  var import_react_core4 = require("@copilotkit/react-core");
1623
- var import_jsx_runtime14 = require("react/jsx-runtime");
1781
+ var import_jsx_runtime15 = require("react/jsx-runtime");
1624
1782
  function Suggestion({ title, onClick, partial, className }) {
1625
1783
  if (!title)
1626
1784
  return null;
1627
- const { isLoading } = (0, import_react_core4.useCopilotChat)();
1628
- return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
1785
+ const { isLoading } = (0, import_react_core4.useCopilotChatInternal)();
1786
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1629
1787
  "button",
1630
1788
  {
1631
1789
  disabled: partial || isLoading,
@@ -1635,15 +1793,15 @@ function Suggestion({ title, onClick, partial, className }) {
1635
1793
  },
1636
1794
  className: className || (partial ? "suggestion loading" : "suggestion"),
1637
1795
  "data-test-id": "suggestion",
1638
- children: partial ? SmallSpinnerIcon : /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("span", { children: title })
1796
+ children: partial ? SmallSpinnerIcon : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { children: title })
1639
1797
  }
1640
1798
  );
1641
1799
  }
1642
1800
 
1643
1801
  // src/components/chat/Suggestions.tsx
1644
- var import_jsx_runtime15 = require("react/jsx-runtime");
1802
+ var import_jsx_runtime16 = require("react/jsx-runtime");
1645
1803
  function Suggestions({ suggestions, onSuggestionClick }) {
1646
- return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "suggestions", children: suggestions.map((suggestion, index) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
1804
+ return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: "suggestions", children: suggestions.map((suggestion, index) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
1647
1805
  Suggestion,
1648
1806
  {
1649
1807
  title: suggestion.title,
@@ -1657,7 +1815,7 @@ function Suggestions({ suggestions, onSuggestionClick }) {
1657
1815
  }
1658
1816
 
1659
1817
  // src/components/chat/Chat.tsx
1660
- var import_jsx_runtime16 = require("react/jsx-runtime");
1818
+ var import_jsx_runtime17 = require("react/jsx-runtime");
1661
1819
  function CopilotChat({
1662
1820
  instructions,
1663
1821
  suggestions = "auto",
@@ -1683,11 +1841,83 @@ function CopilotChat({
1683
1841
  ImageRenderer: ImageRenderer2 = ImageRenderer,
1684
1842
  imageUploadsEnabled,
1685
1843
  inputFileAccept = "image/*",
1686
- hideStopButton
1844
+ hideStopButton,
1845
+ observabilityHooks,
1846
+ renderError,
1847
+ // Legacy props - deprecated
1848
+ RenderTextMessage,
1849
+ RenderActionExecutionMessage,
1850
+ RenderAgentStateMessage,
1851
+ RenderResultMessage,
1852
+ RenderImageMessage
1687
1853
  }) {
1688
- const { additionalInstructions, setChatInstructions } = (0, import_react_core5.useCopilotContext)();
1854
+ const { additionalInstructions, setChatInstructions, copilotApiConfig, setBannerError } = (0, import_react_core5.useCopilotContext)();
1855
+ const { publicApiKey, chatApiEndpoint } = copilotApiConfig;
1689
1856
  const [selectedImages, setSelectedImages] = (0, import_react10.useState)([]);
1857
+ const [chatError, setChatError] = (0, import_react10.useState)(null);
1690
1858
  const fileInputRef = (0, import_react10.useRef)(null);
1859
+ const triggerObservabilityHook = (0, import_react10.useCallback)(
1860
+ (hookName, ...args) => {
1861
+ if (publicApiKey && (observabilityHooks == null ? void 0 : observabilityHooks[hookName])) {
1862
+ observabilityHooks[hookName](...args);
1863
+ }
1864
+ if ((observabilityHooks == null ? void 0 : observabilityHooks[hookName]) && !publicApiKey) {
1865
+ setBannerError(
1866
+ new import_shared.CopilotKitError({
1867
+ message: "observabilityHooks requires a publicApiKey to function.",
1868
+ code: import_shared.CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
1869
+ severity: import_shared.Severity.CRITICAL,
1870
+ visibility: import_shared.ErrorVisibility.BANNER
1871
+ })
1872
+ );
1873
+ import_shared.styledConsole.publicApiKeyRequired("observabilityHooks");
1874
+ }
1875
+ },
1876
+ [publicApiKey, observabilityHooks, setBannerError]
1877
+ );
1878
+ const triggerChatError = (0, import_react10.useCallback)(
1879
+ (error, operation, originalError) => {
1880
+ const errorMessage = (error == null ? void 0 : error.message) || (error == null ? void 0 : error.toString()) || "An error occurred";
1881
+ setChatError({
1882
+ message: errorMessage,
1883
+ operation,
1884
+ timestamp: Date.now()
1885
+ });
1886
+ if (publicApiKey && (observabilityHooks == null ? void 0 : observabilityHooks.onError)) {
1887
+ const errorEvent = {
1888
+ type: "error",
1889
+ timestamp: Date.now(),
1890
+ context: {
1891
+ source: "ui",
1892
+ request: {
1893
+ operation,
1894
+ url: chatApiEndpoint,
1895
+ startTime: Date.now()
1896
+ },
1897
+ technical: {
1898
+ environment: "browser",
1899
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0,
1900
+ stackTrace: originalError instanceof Error ? originalError.stack : void 0
1901
+ }
1902
+ },
1903
+ error
1904
+ };
1905
+ observabilityHooks.onError(errorEvent);
1906
+ }
1907
+ if ((observabilityHooks == null ? void 0 : observabilityHooks.onError) && !publicApiKey) {
1908
+ setBannerError(
1909
+ new import_shared.CopilotKitError({
1910
+ message: "observabilityHooks.onError requires a publicApiKey to function.",
1911
+ code: import_shared.CopilotKitErrorCode.MISSING_PUBLIC_API_KEY_ERROR,
1912
+ severity: import_shared.Severity.CRITICAL,
1913
+ visibility: import_shared.ErrorVisibility.BANNER
1914
+ })
1915
+ );
1916
+ import_shared.styledConsole.publicApiKeyRequired("observabilityHooks.onError");
1917
+ }
1918
+ },
1919
+ [publicApiKey, chatApiEndpoint, observabilityHooks, setBannerError]
1920
+ );
1691
1921
  (0, import_react10.useEffect)(() => {
1692
1922
  if (!imageUploadsEnabled)
1693
1923
  return;
@@ -1727,12 +1957,13 @@ function CopilotChat({
1727
1957
  const loadedImages = (yield Promise.all(imagePromises)).filter((img) => img !== null);
1728
1958
  setSelectedImages((prev) => [...prev, ...loadedImages]);
1729
1959
  } catch (error) {
1960
+ triggerChatError(error, "processClipboardImages", error);
1730
1961
  console.error("Error processing pasted images:", error);
1731
1962
  }
1732
1963
  });
1733
1964
  document.addEventListener("paste", handlePaste);
1734
1965
  return () => document.removeEventListener("paste", handlePaste);
1735
- }, [imageUploadsEnabled]);
1966
+ }, [imageUploadsEnabled, triggerChatError]);
1736
1967
  (0, import_react10.useEffect)(() => {
1737
1968
  if (!(additionalInstructions == null ? void 0 : additionalInstructions.length)) {
1738
1969
  setChatInstructions(instructions || "");
@@ -1746,7 +1977,7 @@ function CopilotChat({
1746
1977
  setChatInstructions(combinedAdditionalInstructions.join("\n") || "");
1747
1978
  }, [instructions, additionalInstructions]);
1748
1979
  const {
1749
- visibleMessages,
1980
+ messages,
1750
1981
  isLoading,
1751
1982
  sendMessage,
1752
1983
  stopGeneration,
@@ -1760,12 +1991,24 @@ function CopilotChat({
1760
1991
  onStopGeneration,
1761
1992
  onReloadMessages
1762
1993
  );
1994
+ const prevIsLoading = (0, import_react10.useRef)(isLoading);
1995
+ (0, import_react10.useEffect)(() => {
1996
+ if (prevIsLoading.current !== isLoading) {
1997
+ if (isLoading) {
1998
+ triggerObservabilityHook("onChatStarted");
1999
+ } else {
2000
+ triggerObservabilityHook("onChatStopped");
2001
+ }
2002
+ prevIsLoading.current = isLoading;
2003
+ }
2004
+ }, [isLoading, triggerObservabilityHook]);
1763
2005
  const handleSendMessage = (text) => {
1764
2006
  const images = selectedImages;
1765
2007
  setSelectedImages([]);
1766
2008
  if (fileInputRef.current) {
1767
2009
  fileInputRef.current.value = "";
1768
2010
  }
2011
+ triggerObservabilityHook("onMessageSent", text);
1769
2012
  return sendMessage(text, images);
1770
2013
  };
1771
2014
  const chatContext = import_react10.default.useContext(ChatContext);
@@ -1774,12 +2017,14 @@ function CopilotChat({
1774
2017
  if (onRegenerate) {
1775
2018
  onRegenerate(messageId);
1776
2019
  }
2020
+ triggerObservabilityHook("onMessageRegenerated", messageId);
1777
2021
  reloadMessages(messageId);
1778
2022
  };
1779
2023
  const handleCopy = (message) => {
1780
2024
  if (onCopy) {
1781
2025
  onCopy(message);
1782
2026
  }
2027
+ triggerObservabilityHook("onMessageCopied", message);
1783
2028
  };
1784
2029
  const handleImageUpload = (event) => __async(this, null, function* () {
1785
2030
  if (!event.target.files || event.target.files.length === 0) {
@@ -1809,28 +2054,52 @@ function CopilotChat({
1809
2054
  const loadedImages = yield Promise.all(fileReadPromises);
1810
2055
  setSelectedImages((prev) => [...prev, ...loadedImages]);
1811
2056
  } catch (error) {
2057
+ triggerChatError(error, "processUploadedImages", error);
1812
2058
  console.error("Error reading files:", error);
1813
2059
  }
1814
2060
  });
1815
2061
  const removeSelectedImage = (index) => {
1816
2062
  setSelectedImages((prev) => prev.filter((_, i) => i !== index));
1817
2063
  };
1818
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(WrappedCopilotChat, { icons, labels, className, children: [
1819
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2064
+ const handleThumbsUp = (message) => {
2065
+ if (onThumbsUp) {
2066
+ onThumbsUp(message);
2067
+ }
2068
+ triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsUp");
2069
+ };
2070
+ const handleThumbsDown = (message) => {
2071
+ if (onThumbsDown) {
2072
+ onThumbsDown(message);
2073
+ }
2074
+ triggerObservabilityHook("onFeedbackGiven", message.id, "thumbsDown");
2075
+ };
2076
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(WrappedCopilotChat, { icons, labels, className, children: [
2077
+ chatError && renderError && renderError(__spreadProps(__spreadValues({}, chatError), {
2078
+ onDismiss: () => setChatError(null),
2079
+ onRetry: () => {
2080
+ setChatError(null);
2081
+ }
2082
+ })),
2083
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1820
2084
  Messages2,
1821
2085
  {
1822
2086
  AssistantMessage: AssistantMessage2,
1823
2087
  UserMessage: UserMessage2,
1824
2088
  RenderMessage: RenderMessage2,
1825
- messages: visibleMessages,
2089
+ messages,
1826
2090
  inProgress: isLoading,
1827
2091
  onRegenerate: handleRegenerate,
1828
2092
  onCopy: handleCopy,
1829
- onThumbsUp,
1830
- onThumbsDown,
2093
+ onThumbsUp: handleThumbsUp,
2094
+ onThumbsDown: handleThumbsDown,
1831
2095
  markdownTagRenderers,
1832
2096
  ImageRenderer: ImageRenderer2,
1833
- children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2097
+ RenderTextMessage,
2098
+ RenderActionExecutionMessage,
2099
+ RenderAgentStateMessage,
2100
+ RenderResultMessage,
2101
+ RenderImageMessage,
2102
+ children: currentSuggestions.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1834
2103
  RenderSuggestionsList,
1835
2104
  {
1836
2105
  onSuggestionClick: handleSendMessage,
@@ -1839,9 +2108,9 @@ function CopilotChat({
1839
2108
  )
1840
2109
  }
1841
2110
  ),
1842
- imageUploadsEnabled && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
1843
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ImageUploadQueue, { images: selectedImages, onRemoveImage: removeSelectedImage }),
1844
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2111
+ imageUploadsEnabled && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
2112
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ImageUploadQueue, { images: selectedImages, onRemoveImage: removeSelectedImage }),
2113
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1845
2114
  "input",
1846
2115
  {
1847
2116
  type: "file",
@@ -1853,7 +2122,7 @@ function CopilotChat({
1853
2122
  }
1854
2123
  )
1855
2124
  ] }),
1856
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
2125
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
1857
2126
  Input2,
1858
2127
  {
1859
2128
  inProgress: isLoading,
@@ -1877,16 +2146,16 @@ function WrappedCopilotChat({
1877
2146
  }) {
1878
2147
  const chatContext = import_react10.default.useContext(ChatContext);
1879
2148
  if (!chatContext) {
1880
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ChatContextProvider, { icons, labels, open: true, setOpen: () => {
1881
- }, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { className: `copilotKitChat ${className != null ? className : ""}`, children }) });
2149
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ChatContextProvider, { icons, labels, open: true, setOpen: () => {
2150
+ }, children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: `copilotKitChat ${className != null ? className : ""}`, children }) });
1882
2151
  }
1883
- return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(import_jsx_runtime16.Fragment, { children });
2152
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(import_jsx_runtime17.Fragment, { children });
1884
2153
  }
1885
2154
  var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onSubmitMessage, onStopGeneration, onReloadMessages) => {
1886
2155
  var _a;
1887
2156
  const {
1888
- visibleMessages,
1889
- appendMessage,
2157
+ messages,
2158
+ sendMessage,
1890
2159
  setMessages,
1891
2160
  reloadMessages: defaultReloadMessages,
1892
2161
  stopGeneration: defaultStopGeneration,
@@ -1897,7 +2166,7 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1897
2166
  generateSuggestions,
1898
2167
  resetSuggestions: resetSuggestionsFromHook,
1899
2168
  isLoadingSuggestions
1900
- } = (0, import_react_core5.useCopilotChat)({
2169
+ } = (0, import_react_core5.useCopilotChatInternal)({
1901
2170
  makeSystemMessage
1902
2171
  });
1903
2172
  const generalContext = (0, import_react_core5.useCopilotContext)();
@@ -1932,12 +2201,12 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1932
2201
  if (Object.keys(generalContext.chatSuggestionConfiguration).length === 0) {
1933
2202
  return;
1934
2203
  }
1935
- if (visibleMessages.length === 0 && !hasGeneratedInitialSuggestions.current) {
2204
+ if (messages.length === 0 && !hasGeneratedInitialSuggestions.current) {
1936
2205
  hasGeneratedInitialSuggestions.current = true;
1937
2206
  generateSuggestionsWithErrorHandling("initial");
1938
2207
  return;
1939
2208
  }
1940
- if (visibleMessages.length > 0 && suggestions.length === 0) {
2209
+ if (messages.length > 0 && suggestions.length === 0) {
1941
2210
  generateSuggestionsWithErrorHandling("post-message");
1942
2211
  return;
1943
2212
  }
@@ -1945,7 +2214,7 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1945
2214
  chatSuggestions,
1946
2215
  isLoadingSuggestions,
1947
2216
  suggestionsFailed,
1948
- visibleMessages.length,
2217
+ messages.length,
1949
2218
  isLoading,
1950
2219
  suggestions.length,
1951
2220
  Object.keys(generalContext.chatSuggestionConfiguration).join(","),
@@ -1975,7 +2244,7 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1975
2244
  (0, import_react10.useEffect)(() => {
1976
2245
  onInProgress == null ? void 0 : onInProgress(isLoading);
1977
2246
  }, [onInProgress, isLoading]);
1978
- const sendMessage = (messageContent, imagesToUse) => __async(void 0, null, function* () {
2247
+ const safelySendMessage = (messageContent, imagesToUse) => __async(void 0, null, function* () {
1979
2248
  const images = imagesToUse || [];
1980
2249
  if (chatSuggestions === "auto" || chatSuggestions === "manual") {
1981
2250
  setSuggestions([]);
@@ -1983,7 +2252,7 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1983
2252
  let firstMessage = null;
1984
2253
  if (messageContent.trim().length > 0) {
1985
2254
  const textMessage = {
1986
- id: (0, import_shared.randomId)(),
2255
+ id: (0, import_shared2.randomId)(),
1987
2256
  role: "user",
1988
2257
  content: messageContent
1989
2258
  };
@@ -1994,7 +2263,7 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
1994
2263
  console.error("Error in onSubmitMessage:", error);
1995
2264
  }
1996
2265
  }
1997
- yield appendMessage(textMessage, {
2266
+ yield sendMessage(textMessage, {
1998
2267
  followUp: images.length === 0,
1999
2268
  clearSuggestions: chatSuggestions === "auto" || chatSuggestions === "manual"
2000
2269
  });
@@ -2005,25 +2274,24 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
2005
2274
  if (images.length > 0) {
2006
2275
  for (let i = 0; i < images.length; i++) {
2007
2276
  const imageMessage = {
2008
- id: (0, import_shared.randomId)(),
2277
+ id: (0, import_shared2.randomId)(),
2009
2278
  role: "user",
2010
2279
  image: {
2011
2280
  format: images[i].contentType.replace("image/", ""),
2012
2281
  bytes: images[i].bytes
2013
2282
  }
2014
2283
  };
2015
- yield appendMessage(imageMessage, { followUp: i === images.length - 1 });
2284
+ yield sendMessage(imageMessage, { followUp: i === images.length - 1 });
2016
2285
  if (!firstMessage) {
2017
2286
  firstMessage = imageMessage;
2018
2287
  }
2019
2288
  }
2020
2289
  }
2021
2290
  if (!firstMessage) {
2022
- return { role: "user", content: "", id: (0, import_shared.randomId)() };
2291
+ return { role: "user", content: "", id: (0, import_shared2.randomId)() };
2023
2292
  }
2024
2293
  return firstMessage;
2025
2294
  });
2026
- const messages = visibleMessages;
2027
2295
  const currentAgentName = (_a = generalContext.agentSession) == null ? void 0 : _a.agentName;
2028
2296
  const restartCurrentAgent = (hint) => __async(void 0, null, function* () {
2029
2297
  if (generalContext.agentSession) {
@@ -2047,9 +2315,9 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
2047
2315
  yield (0, import_react_core6.runAgent)(
2048
2316
  generalContext.agentSession.agentName,
2049
2317
  stableContext,
2050
- appendMessage,
2051
- runChatCompletion,
2052
- hint
2318
+ messagesContext.messages,
2319
+ sendMessage,
2320
+ runChatCompletion
2053
2321
  );
2054
2322
  }
2055
2323
  });
@@ -2105,10 +2373,9 @@ var useCopilotChatLogic = (chatSuggestions, makeSystemMessage, onInProgress, onS
2105
2373
  }
2106
2374
  return {
2107
2375
  messages,
2108
- visibleMessages,
2109
2376
  isLoading,
2110
2377
  suggestions,
2111
- sendMessage,
2378
+ sendMessage: safelySendMessage,
2112
2379
  stopGeneration,
2113
2380
  reloadMessages,
2114
2381
  resetSuggestions,