Conversation export

Downloads a Markdown snapshot from explicit message text, attachments, and structured tool results.

YouComplete
Review the launch brief.
AssistantComplete
The brief has two decisions without owners.

Keep a Markdown snapshot

YouComplete
Review the launch brief.
AssistantComplete
The brief has two decisions without owners.

Use it for

  • Pass explicit message data to serializeConversation or ConversationDownload. No rendered DOM is scraped.
  • Use serializePart for application-specific export formatting. The download owns and releases its object URLs.

Avoid

  • Coercing arbitrary message objects into strings or claiming persistence from a local download.

React package

npm install @noorddev/vlak-react

Load the stylesheet once at your app root, then import the components you use.

import "@noorddev/vlak-react/css";
import { ConversationDownload } from "@noorddev/vlak-react";

Per-component imports are available at @noorddev/vlak-react/components/conversation-export.

Copy the source

npx @noorddev/vlak-cli add conversation-export

Adds the component and its dependencies to components/vlak/. Follow the StyleX setup to compile the source in your application.

shadcn registry

npx shadcn add https://vlak.dev/r/conversation-export.json

Installs the same source through the shadcn CLI.

import { ConversationDownload } from "@noorddev/vlak-react";

<ConversationDownload title="Project review" messages={[{ role: "user", content: "Review the brief" }, { role: "assistant", parts: [{ type: "text", text: "Two owners are missing." }] }]} />

See the integration example to compose these components with your application's model and data.

ConversationDownload

Downloads a Markdown snapshot using supplied message data, without reading rendered DOM.

PropTypeDefaultDescription
variant"primary" | "ghost" | "subtle"Solid ink primary, hairline ghost, or borderless subtle. One primary per view.
size"default" | "sm" | "icon"Icon buttons stay square at every breakpoint. Supply an accessible name.
groupedbooleanFlush into a ButtonGroup: no own stroke, one ink seam.
serializePart(part: ConversationExportPart, message: ConversationExportMessage) => string
messagesrequiredreadonly ConversationExportMessage[]
filenamestring"conversation.md"
onError(error: unknown) => void

Also accepts ButtonHTMLAttributes<HTMLButtonElement>.

The ref reaches HTMLButtonElement.

serializeConversation (function)

Serializes explicit text, file and tool parts; unsupported application objects are never stringified as messages.

KeysDoes
TabMoves through the supplied native controls in reading order
Enter, SpaceActivates focused buttons and disclosure summaries
  • Native attributes, className, style, and the forwarded ref reach the outer element.
  • Interactive content requires accessible names; progress text is not announced for every streamed token.

The same styles are available as CSS. Native HTML provides the static presentation; React or application code supplies state updates and actions.

npm install @noorddev/vlak
import "@noorddev/vlak/css";
<button class="rs-btn-subtle" type="button">Download conversation</button>

Classes

.rs-btn-subtle