diff --git a/packages/ui/src/features/sessions/components/chat-thread/ChatMarkdown.tsx b/packages/ui/src/features/sessions/components/chat-thread/ChatMarkdown.tsx index 824801ac4d..c871c25187 100644 --- a/packages/ui/src/features/sessions/components/chat-thread/ChatMarkdown.tsx +++ b/packages/ui/src/features/sessions/components/chat-thread/ChatMarkdown.tsx @@ -1,3 +1,4 @@ +import { Check, Copy } from "@phosphor-icons/react"; import { Heading, Separator, @@ -14,11 +15,41 @@ import { splitMarkdownBlocks, } from "@posthog/ui/features/editor/components/splitMarkdownBlocks"; import { HighlightedCode } from "@posthog/ui/primitives/HighlightedCode"; -import { memo, useMemo } from "react"; +import { useCopy } from "@posthog/ui/primitives/useCopy"; +import { IconButton } from "@radix-ui/themes"; +import { memo, type ReactNode, useMemo } from "react"; import Markdown, { type Components } from "react-markdown"; import rehypeSanitize from "rehype-sanitize"; import remarkGfm from "remark-gfm"; +function ChatCodeBlock({ + code, + children, +}: { + code: string; + children: ReactNode; +}) { + const { copied, copy } = useCopy(); + + return ( +
+ {children}
+
+ inside it.
+ // Fenced blocks (carry a language, or span multiple lines) render as a boxed, copyable
+ // block; short inline spans stay inline. `pre` below is a passthrough so the box lives here,
+ // where the raw code string is in hand.
+ if (match || text.includes("\n")) {
return (
-
+
+ {match ? (
+
+ ) : (
+ {text}
+ )}
+
);
}
return (
@@ -65,11 +104,7 @@ const components: Components = {
);
},
- pre: ({ children }) => (
-
- {children}
-
- ),
+ pre: ({ children }) => <>{children}>,
h1: ({ children }) => (
++ ); } diff --git a/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx b/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx index 5a74c918d6..663878794d 100644 --- a/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx +++ b/packages/ui/src/features/sessions/components/chat-thread/ChatThread.tsx @@ -1,4 +1,11 @@ -import { CaretDown, ChatCircle, FileText, Scroll } from "@phosphor-icons/react"; +import { + CaretDown, + ChatCircle, + Check, + Copy, + FileText, + Scroll, +} from "@phosphor-icons/react"; import { WorkerPoolContextProvider } from "@pierre/diffs/react"; import { useService } from "@posthog/di/react"; import { @@ -64,10 +71,12 @@ import { } from "@posthog/ui/features/sessions/useSessionTaskId"; import { useSettingsStore } from "@posthog/ui/features/settings/settingsStore"; import { SkillButtonActionMessage } from "@posthog/ui/features/skill-buttons/components/SkillButtonActionMessage"; +import { useCopy } from "@posthog/ui/primitives/useCopy"; import { DIFF_WORKER_FACTORY, type DiffWorkerFactory, } from "@posthog/ui/shell/diffWorkerHost"; +import { IconButton, Tooltip } from "@radix-ui/themes"; import { AnimatePresence, motion, useReducedMotion } from "framer-motion"; import { memo, @@ -540,8 +549,10 @@ const AgentProse = memo(function AgentProse({ isStreaming?: boolean; }) { const smoothed = useSmoothedText(text); + const { copied, copy } = useCopy(); + return ( -{openFence.code}-