ViteHub is still experimental. Expect bugs and breaking changes.
Message Parts
Render the complete AI SDK UIMessage part union with application escape hatches.
AgentMessageParts dispatches the parts already present in an AI SDK UIMessage. Text uses AgentMarkdown; reasoning and tools use Nuxt UI; files and sources use accessible links.
Preview
MessagePartsExample.vue
<script setup lang="ts">
import type { UIMessage } from "ai";
// SAFETY: Every fixture entry below is a concrete AI SDK UIMessage part variant.
const parts = [
{
type: "text",
text: "I found the failing layout rule and verified the fix.",
},
{
type: "reasoning",
text: "The virtual list used one fixed height even when an error added another line.",
state: "done",
},
{
type: "dynamic-tool",
toolCallId: "tool-1",
toolName: "run_tests",
title: "Run focused tests",
state: "output-available",
input: { command: "pnpm test invocation-ui" },
output: { passed: 10 },
},
{
type: "source-url",
sourceId: "vitehub-ui-docs",
url: "https://vitehub.dev/docs/ui",
title: "ViteHub UI documentation",
},
] as UIMessage["parts"];
</script>
<template>
<AgentMessageParts :parts="parts" />
</template>
Supported parts
| Part | Default rendering |
|---|---|
text | Streaming-aware Comark Markdown. |
reasoning | UChatReasoning. |
tool-*, dynamic-tool | UChatTool with input, output, error, and loading state. |
file | Named download or image preview. |
source-url, source-document | Source link or document label. |
step-start | No visual output unless slotted. |
data-*, custom, reasoning-file | fallback slot. |
Customize typed data
<AgentMessageParts :parts="message.parts">
<template #fallback="{ part }">
<WeatherCard
v-if="part.type === 'data-weather'"
:weather="part.data"
/>
</template>
</AgentMessageParts>
Use #part to intercept every part before the default dispatcher. Use the narrower #text, #reasoning, #tool, #file, #source, and #step slots when only one rendering needs to change.