Message Parser & Streaming
Relevant source files
The following files were used as context for generating this wiki page:
The Message Parser and Streaming system is responsible for processing real-time LLM responses as they arrive in chunks. Its primary role is to detect and extract structured data—specifically "artifacts" and "actions"—from the raw text stream while sanitizing the content for display in the chat interface. By intercepting these custom tags before they are rendered as markdown, the system triggers UI updates in the workbench and executes automated tasks like file creation or terminal commands.
This system ensures that the AI's instructions are translated into actionable state changes within the application's runtime environment, allowing the user to see code updates and project structures evolve dynamically as the AI "types."
Architecture & Data Flow
The architecture follows a unidirectional flow where raw message chunks from the AI SDK are fed into a stateful parser. The parser identifies specific XML-like tags (<boltArtifact> and <boltAction>) and triggers callbacks that update the global WorkbenchStore.
Streaming Data Pipeline
The following diagram illustrates the flow of a message chunk from the AI response through the parser to the UI and runtime.
The useMessageParser hook acts as the bridge between the React component lifecycle and the StreamingMessageParser logic. Sources: app/lib/hooks/useMessageParser.ts:39-65, app/lib/runtime/message-parser.ts:47-56
Core Components
StreamingMessageParser
The StreamingMessageParser class is the central engine of the system. It maintains a MessageState for each message ID to handle chunks that might split tags (e.g., a chunk ending with <boltArt). It uses a character-by-character scanning approach to identify opening and closing tags.
| Feature | Description |
|---|---|
| Incremental Parsing | Remembers the last processed position to avoid re-parsing previous chunks. |
| Tag Stripping | Removes artifact and action tags from the output string to prevent them from appearing in the user-facing markdown. |
| State Management | Tracks whether the parser is currently "inside" an artifact or an action to correctly attribute content. |
Sources: app/lib/runtime/message-parser.ts:60-180, app/lib/runtime/message-parser.spec.ts:16-50
Parser Callbacks
The parser communicates findings through a set of optional callbacks defined in ParserCallbacks.
Artifacts and Actions
The system recognizes two primary structural elements: Artifacts and Actions.
Artifacts
Artifacts are containers for a set of related actions (e.g., a project initialization). They are defined by the <boltArtifact> tag which requires a title and an id.
- Opening: Triggers
onArtifactOpen, making the workbench visible. - Closing: Triggers
onArtifactClose, marking the artifact as complete in the store.
Sources: app/lib/runtime/message-parser.ts:140-165, app/lib/stores/workbench.ts:241-260
Actions
Actions are specific tasks within an artifact, defined by <boltAction>.
- File Actions: Used to create or update files. The content between the tags is the file source code.
- Shell Actions: Used to run commands in the terminal. The content is the command string.
| Attribute | Type | Description |
|---|---|---|
type | "file" | "shell" | The category of the action. |
filePath | string | (Required for file type) The destination path in the filesystem. |
Sources: app/lib/runtime/message-parser.ts:193-215, app/lib/runtime/message-parser.spec.ts:98-110
Implementation Details
Tag Detection Logic
The parser identifies tags by checking the current character against the ARTIFACT_TAG_OPEN constant. If a potential match is found but the chunk ends before the tag is complete, the parser pauses and waits for the next chunk.
// Example of attribute extraction used by the parser
#extractAttribute(tag: string, attributeName: string): string | undefined {
const match = tag.match(new RegExp(`${attributeName}="([^"]*)"`, 'i'));
return match ? match[1] : undefined;
}
Sources: app/lib/runtime/message-parser.ts:217-220
Integration with Markdown
The chat interface uses a specialized Markdown component. It renders a hidden placeholder for artifacts, which the React component then replaces with a functional Artifact component based on the messageId.
div: ({ className, children, node, ...props }) => {
if (className?.includes('__boltArtifact__')) {
const messageId = node?.properties.dataMessageId as string;
return <Artifact messageId={messageId} />;
}
return <div className={className} {...props}>{children}</div>;
}
Sources: app/components/chat/Markdown.tsx:24-38, app/lib/runtime/message-parser.ts:223-233
Summary
The Message Parser & Streaming module transforms a flat text stream into a structured set of operations. By handling partial chunks and maintaining a strict internal state, it enables the "Bolt" experience where AI-generated code is simultaneously rendered as text and executed as filesystem/terminal operations in the background.