diff --git a/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/ChatRow/index.jsx b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/ChatRow/index.jsx
index 115b09a9e7a..bf50e61f57d 100644
--- a/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/ChatRow/index.jsx
+++ b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/ChatRow/index.jsx
@@ -1,9 +1,11 @@
import truncate from "truncate";
-import { X, Trash, LinkSimple } from "@phosphor-icons/react";
+import { X } from "@phosphor-icons/react";
import ModalWrapper from "@/components/ModalWrapper";
import { useModal } from "@/hooks/useModal";
import paths from "@/utils/paths";
import Embed from "@/models/embed";
+import MarkdownRenderer from "../MarkdownRenderer";
+import { safeJsonParse } from "@/utils/request";
export default function ChatRow({ chat, onDelete }) {
const {
@@ -83,7 +85,11 @@ export default function ChatRow({ chat, onDelete }) {
+ }
closeModal={closeResponseModal}
/>
@@ -118,9 +124,9 @@ const TextPreview = ({ text, closeModal }) => {
@@ -132,11 +138,7 @@ const ConnectionDetails = ({
verbose = false,
connection_information,
}) => {
- let details = {};
- try {
- details = JSON.parse(connection_information);
- } catch {}
-
+ const details = safeJsonParse(connection_information, {});
if (Object.keys(details).length === 0) return null;
if (verbose) {
diff --git a/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/MarkdownRenderer.jsx b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/MarkdownRenderer.jsx
new file mode 100644
index 00000000000..11b4ca51c1e
--- /dev/null
+++ b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/MarkdownRenderer.jsx
@@ -0,0 +1,87 @@
+import { useState } from "react";
+import MarkdownIt from "markdown-it";
+import { CaretDown } from "@phosphor-icons/react";
+import "highlight.js/styles/github-dark.css";
+import DOMPurify from "@/utils/chat/purify";
+
+const md = new MarkdownIt({
+ html: true,
+ breaks: true,
+ highlight: function (str, lang) {
+ if (lang && hljs.getLanguage(lang)) {
+ try {
+ return hljs.highlight(str, { language: lang }).value;
+ } catch (__) {}
+ }
+ return ""; // use external default escaping
+ },
+});
+
+const ThoughtBubble = ({ thought }) => {
+ const [isExpanded, setIsExpanded] = useState(false);
+
+ if (!thought) return null;
+
+ const cleanThought = thought.replace(/<\/?think>/g, "").trim();
+ if (!cleanThought) return null;
+
+ return (
+
+
setIsExpanded(!isExpanded)}
+ className="cursor-pointer flex items-center gap-x-2 text-theme-text-secondary hover:text-theme-text-primary transition-colors mb-2"
+ >
+
+ View thoughts
+
+ {isExpanded && (
+
+ )}
+
+ );
+};
+
+function parseContent(content) {
+ const parts = [];
+ let lastIndex = 0;
+ content.replace(/([^]*?)<\/think>/g, (match, thinkContent, offset) => {
+ if (offset > lastIndex) {
+ parts.push({ type: "normal", text: content.slice(lastIndex, offset) });
+ }
+ parts.push({ type: "think", text: thinkContent });
+ lastIndex = offset + match.length;
+ });
+ if (lastIndex < content.length) {
+ parts.push({ type: "normal", text: content.slice(lastIndex) });
+ }
+ return parts;
+}
+
+export default function MarkdownRenderer({ content }) {
+ if (!content) return null;
+
+ const parts = parseContent(content);
+ return (
+
+ {parts.map((part, index) => {
+ const html = md.render(part.text);
+ if (part.type === "think")
+ return
;
+ return (
+
+ );
+ })}
+
+ );
+}
diff --git a/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/index.jsx b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/index.jsx
index 154094e297b..cd242422e71 100644
--- a/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/index.jsx
+++ b/frontend/src/pages/GeneralSettings/ChatEmbedWidgets/EmbedChats/index.jsx
@@ -55,6 +55,7 @@ export default function EmbedChatsView() {
const query = useQuery();
const [offset, setOffset] = useState(Number(query.get("offset") || 0));
const [canNext, setCanNext] = useState(false);
+ const [showThinking, setShowThinking] = useState(true);
const handleDumpChats = async (exportType) => {
const chats = await System.exportChats(exportType, "embed");
@@ -92,10 +93,15 @@ export default function EmbedChatsView() {
useEffect(() => {
async function fetchChats() {
- const { chats: _chats, hasPages = false } = await Embed.chats(offset);
- setChats(_chats);
- setCanNext(hasPages);
- setLoading(false);
+ setLoading(true);
+ await Embed.chats(offset)
+ .then(({ chats: _chats, hasPages = false }) => {
+ setChats(_chats);
+ setCanNext(hasPages);
+ })
+ .finally(() => {
+ setLoading(false);
+ });
}
fetchChats();
}, [offset]);
@@ -211,7 +217,7 @@ export default function EmbedChatsView() {
: "bg-theme-bg-secondary text-theme-text-primary hover:bg-theme-hover"
}`}
>
- {t("embed-chats.previous")}
+ {t("common.previous")}
)}