Summary
The copy and save/download buttons rendered on formatted code blocks in the chat UI do not function. Clicking them has no visible effect — no clipboard write, no file download, no feedback state.
Repro
- Start a conversation and ask the agent to produce a code block (e.g., "write a Python hello world").
- Hover over the rendered code block — copy and save buttons appear.
- Click the copy button.
- Observe: clipboard is not updated (paste confirms nothing was written).
- Click the save/download button.
- Observe: no file download is triggered.
Root cause
Code blocks are rendered by the <Streamdown> component (web/src/components/MessageList.tsx:317), which provides its own built-in copy and download buttons on code fences. These buttons are part of the library's default rendering and are not wired to any custom handlers in the NimbleBrain integration.
The custom CopyButton component in MessageList.tsx:32 operates at the message level (copies the full raw markdown text of the message), not at the individual code block level. It is a separate button from the ones Streamdown renders inside each code block.
The Streamdown code block buttons likely rely on browser clipboard and download APIs that either:
- Require a user gesture in a Secure Context, which may not be satisfied in the current render path, or
- Are broken by the way the Streamdown component is mounted (e.g., inside an iframe, shadow DOM, or focus-trapped container that intercepts events)
No error handling exists anywhere in the copy flow — navigator.clipboard.writeText() calls are fire-and-forget with no try/catch (MessageList.tsx:36, ToolAccordion.tsx:218). Silent failures leave users with no feedback.
What would help
- Determine whether Streamdown's built-in buttons work in isolation (outside NimbleBrain's layout)
- If the issue is library-level: replace Streamdown's default code block rendering with a custom component that calls
navigator.clipboard.writeText() directly with proper error handling and user feedback
- If the issue is context-level (iframe / CSP / Secure Context): ensure the chat panel is served in a context where clipboard and download APIs are permitted
- Add try/catch around all
navigator.clipboard.writeText() calls and display a visible error state when the write fails
Key files
web/src/components/MessageList.tsx:317–327 — Streamdown instantiation (code block rendering)
web/src/components/MessageList.tsx:32–51 — message-level CopyButton (separate from code block buttons)
web/src/components/ToolAccordion.tsx:213–242 — tool result CopyButton (same pattern, no error handling)
web/src/index.css:298–300 — Streamdown code block styling
Summary
The copy and save/download buttons rendered on formatted code blocks in the chat UI do not function. Clicking them has no visible effect — no clipboard write, no file download, no feedback state.
Repro
Root cause
Code blocks are rendered by the
<Streamdown>component (web/src/components/MessageList.tsx:317), which provides its own built-in copy and download buttons on code fences. These buttons are part of the library's default rendering and are not wired to any custom handlers in the NimbleBrain integration.The custom
CopyButtoncomponent inMessageList.tsx:32operates at the message level (copies the full raw markdown text of the message), not at the individual code block level. It is a separate button from the ones Streamdown renders inside each code block.The Streamdown code block buttons likely rely on browser clipboard and download APIs that either:
No error handling exists anywhere in the copy flow —
navigator.clipboard.writeText()calls are fire-and-forget with no try/catch (MessageList.tsx:36,ToolAccordion.tsx:218). Silent failures leave users with no feedback.What would help
navigator.clipboard.writeText()directly with proper error handling and user feedbacknavigator.clipboard.writeText()calls and display a visible error state when the write failsKey files
web/src/components/MessageList.tsx:317–327— Streamdown instantiation (code block rendering)web/src/components/MessageList.tsx:32–51— message-level CopyButton (separate from code block buttons)web/src/components/ToolAccordion.tsx:213–242— tool result CopyButton (same pattern, no error handling)web/src/index.css:298–300— Streamdown code block styling