From 708e59e6c93cbebfb2e601c66e591ccdd41999b0 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 08:37:40 +0000 Subject: [PATCH 1/2] feat: filter thinking tags from copied assistant responses - Added stripThinkingTags utility function to remove ... tags - Updated SystemMessage copy functionality to use filtered content - Handles both complete and incomplete thinking tags - Cleans up extra whitespace after tag removal Fixes #118 Co-authored-by: AnthonyRonning --- frontend/src/components/markdown.tsx | 16 ++++++++++++++++ frontend/src/routes/_auth.chat.$chatId.tsx | 5 +++-- 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/markdown.tsx b/frontend/src/components/markdown.tsx index 67058d6b..af3e92b6 100644 --- a/frontend/src/components/markdown.tsx +++ b/frontend/src/components/markdown.tsx @@ -176,6 +176,22 @@ function parseThinkingTags(content: string, isComplete: boolean = false): Parsed return parts; } +export function stripThinkingTags(content: string): string { + // Handle the edge case: followed by only whitespace and no closing tag + if (/^\s*$/m.test(content) && !content.includes("")) { + return content.replace(/^\s*/m, ""); + } + + // Pattern to match tags (complete or incomplete) and remove them entirely + const thinkPattern = /([\s\S]*?)<\/think>|([\s\S]*?)$/g; + + // Replace all thinking tags with empty string and clean up extra whitespace + return content + .replace(thinkPattern, "") + .replace(/\n\s*\n\s*\n/g, "\n\n") // Replace multiple consecutive newlines with double newlines + .trim(); +} + export function PreCode(props: JSX.IntrinsicElements["pre"]) { const ref = useRef(null); diff --git a/frontend/src/routes/_auth.chat.$chatId.tsx b/frontend/src/routes/_auth.chat.$chatId.tsx index 115363fc..c3079900 100644 --- a/frontend/src/routes/_auth.chat.$chatId.tsx +++ b/frontend/src/routes/_auth.chat.$chatId.tsx @@ -4,7 +4,7 @@ import { AsteriskIcon, Check, Copy, UserIcon, ChevronDown, SquarePenIcon } from import ChatBox from "@/components/ChatBox"; import { useOpenAI } from "@/ai/useOpenAi"; import { useLocalState } from "@/state/useLocalState"; -import { Markdown } from "@/components/markdown"; +import { Markdown, stripThinkingTags } from "@/components/markdown"; import { ChatMessage, Chat, DEFAULT_MODEL_ID } from "@/state/LocalStateContext"; import { AlertDestructive } from "@/components/AlertDestructive"; import { Sidebar, SidebarToggle } from "@/components/Sidebar"; @@ -46,7 +46,8 @@ function SystemMessage({ const handleCopy = useCallback(async () => { try { - await navigator.clipboard.writeText(text); + const textWithoutThinking = stripThinkingTags(text); + await navigator.clipboard.writeText(textWithoutThinking); setIsCopied(true); setTimeout(() => setIsCopied(false), 2000); } catch (error) { From 8a59d2bef3f961bb931c34986c4a298a6fe24b87 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 12 Jun 2025 15:34:14 +0000 Subject: [PATCH 2/2] refactor: eliminate duplicate logic in stripThinkingTags - Refactor stripThinkingTags to reuse parseThinkingTags logic - Remove duplicate regex patterns and edge case handling - Improve newline normalization with better regex pattern - Addresses code review feedback about DRY violations Co-authored-by: AnthonyRonning --- frontend/src/components/markdown.tsx | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/frontend/src/components/markdown.tsx b/frontend/src/components/markdown.tsx index af3e92b6..f7924e89 100644 --- a/frontend/src/components/markdown.tsx +++ b/frontend/src/components/markdown.tsx @@ -177,19 +177,15 @@ function parseThinkingTags(content: string, isComplete: boolean = false): Parsed } export function stripThinkingTags(content: string): string { - // Handle the edge case: followed by only whitespace and no closing tag - if (/^\s*$/m.test(content) && !content.includes("")) { - return content.replace(/^\s*/m, ""); - } - - // Pattern to match tags (complete or incomplete) and remove them entirely - const thinkPattern = /([\s\S]*?)<\/think>|([\s\S]*?)$/g; - - // Replace all thinking tags with empty string and clean up extra whitespace - return content - .replace(thinkPattern, "") - .replace(/\n\s*\n\s*\n/g, "\n\n") // Replace multiple consecutive newlines with double newlines - .trim(); + return ( + parseThinkingTags(content, true) // leverage single source of truth + .filter((p) => p.type === "content") + .map((p) => p.content) + .join("") + // collapse ≥3 consecutive blank lines to two + .replace(/\n{3,}/g, "\n\n") + .trim() + ); } export function PreCode(props: JSX.IntrinsicElements["pre"]) {