diff --git a/packages/ui/src/components/chat/MarkdownContent.test.tsx b/packages/ui/src/components/chat/MarkdownContent.test.tsx
index 9b5b3fc..c1a5654 100644
--- a/packages/ui/src/components/chat/MarkdownContent.test.tsx
+++ b/packages/ui/src/components/chat/MarkdownContent.test.tsx
@@ -34,6 +34,19 @@ describe('MarkdownContent', () => {
expect(container.querySelector('pre code')?.textContent).toContain('{"ok":true}');
});
+ it('renders untyped fenced code as a block rather than inline code', async () => {
+ const container = document.createElement('div');
+ const root = createRoot(container);
+
+ await act(async () => {
+ root.render();
+ });
+
+ expect(container.querySelector('pre code')?.className).toContain('font-mono');
+ expect(container.querySelector('pre code')?.className).not.toContain('rounded-[4px]');
+ expect(container.querySelector('p code')?.className).toContain('rounded-[4px]');
+ });
+
it('renders GFM tables and removes unsafe links', async () => {
const container = document.createElement('div');
const root = createRoot(container);
diff --git a/packages/ui/src/components/chat/MarkdownContent.tsx b/packages/ui/src/components/chat/MarkdownContent.tsx
index 0c01317..07e9613 100644
--- a/packages/ui/src/components/chat/MarkdownContent.tsx
+++ b/packages/ui/src/components/chat/MarkdownContent.tsx
@@ -3,6 +3,7 @@ import ReactMarkdown, { type Components } from 'react-markdown';
import remarkGfm from 'remark-gfm';
const SAFE_URL_PROTOCOLS = new Set(['http:', 'https:', 'mailto:', 'tel:']);
+const CodeBlockContext = React.createContext(false);
/**
* Keep agent-authored URLs useful without allowing navigation to executable
@@ -79,6 +80,22 @@ function useStreamingContent(content: string, streaming: boolean): string {
* is intentional. GFM adds the table, task-list, strike-through, and URL
* behaviours people expect from a research answer.
*/
+const MarkdownCode: NonNullable = ({ className, children, ...props }) => {
+ const isBlock = React.useContext(CodeBlockContext) || Boolean(className?.includes('language-'));
+ return (
+
+ {isBlock ? String(children).replace(/\n$/, '') : children}
+
+ );
+};
+
const components: Components = {
h1: ({ children }) => (
{children}
@@ -116,25 +133,13 @@ const components: Components = {
);
},
- code: ({ className, children, ...props }) => {
- const isBlock = Boolean(className?.includes('language-'));
- return (
-
- {isBlock ? String(children).replace(/\n$/, '') : children}
-
- );
- },
+ code: MarkdownCode,
pre: ({ children }) => (
-
- {children}
-
+
+
+ {children}
+
+
),
table: ({ children }) => (