ai-sdk-ui-master
AI SDK UI Master
Expert skill for AI SDK UI (v6), ai package, and ai-elements in AgentStack with Mastra backend.
Stack Overview
| Package | Version | Purpose |
|---|---|---|
ai |
^6.0.97 | UIMessage, parts, createUIMessageStream, createUIMessageStreamResponse, type guards |
@ai-sdk/react |
^3.0.99 | useChat hook |
@mastra/ai-sdk |
^1.0.5 | toAISdkStream, chatRoute, networkRoute, workflowRoute |
| ai-elements | local | 50+ components in src/components/ai-elements/ |
Key File Map
| Purpose | Location |
|---|---|
| Chat provider | app/chat/providers/chat-context.tsx |
| Chat types | app/chat/providers/chat-context-types.ts |
| Message rendering | app/chat/components/chat-messages.tsx |
| Stream conversion | lib/client-stream-to-ai-sdk.ts |
| API chat route | app/api/chat/route.ts |
| MastraClient | lib/mastra-client.ts |
| Agent config | app/chat/config/agents.ts |
Base ai-elements (library components)
Reusable building blocks in src/components/ai-elements/ — not in tools/ or custom/.
| Category | Location | Reference |
|---|---|---|
| Conversation & Messaging | src/components/ai-elements/ |
Base: conversation-messaging |
| Code & Development | src/components/ai-elements/ |
Base: code-development |
| Reasoning & Debugging | src/components/ai-elements/ |
Base: reasoning-debugging |
| Input & Controls | src/components/ai-elements/ |
Base: input-controls |
| Visualization & Canvas | src/components/ai-elements/ |
Base: visualization-canvas |
| Media & Audio | src/components/ai-elements/ |
Base: media-audio |
| Agent & Tool (base) | src/components/ai-elements/ — Tool, ToolHeader, ToolContent, etc. |
Base: agent-tool |
| Other (base) | src/components/ai-elements/ — loader, context, sources, plan, … |
Base: other |
Custom tool UIs (project-specific)
Mastra tool result renderers in src/components/ai-elements/tools/. They use base ai-elements (e.g. tool.tsx).
| What | Location | Reference |
|---|---|---|
| Custom tool UIs ↔ Mastra | src/components/ai-elements/tools/ |
Part 3: Custom tool UIs |
| Backend → toolName → UI table | — | Backend → stream toolName → UI mapping |
| Other project-specific | src/components/ai-elements/custom/ |
Part 4: Other project-specific (custom/) |
Tool name → UI: Stream toolName is matched in app/chat/components/agent-tools.tsx; custom UIs live in src/components/ai-elements/tools/. Fallback uses base Tool/ToolHeader/ToolContent from tool.tsx. Types from ai-elements/tools/types.ts via InferUITool<typeof mastraTool>.
Mastra Backend (one reference per subdirectory)
| Purpose | Location | Reference |
|---|---|---|
| Mastra entry | src/mastra/index.ts |
mastra-reference.md |
| Agents (31+) | src/mastra/agents/ |
mastra-reference.md |
| Tools (60+) | src/mastra/tools/ |
mastra-reference.md |
| Networks (13) | src/mastra/networks/ |
mastra-reference.md |
| Workflows (15+) | src/mastra/workflows/ |
mastra-reference.md |
| Config | src/mastra/config/ |
mastra-reference.md |
| A2A coordination | src/mastra/a2a/ |
mastra-reference.md |
| MCP server | src/mastra/mcp/ |
mastra-reference.md |
| Evals/scorers | src/mastra/evals/ |
mastra-reference.md |
| Services | src/mastra/services/ |
mastra-reference.md |
| Data | src/mastra/data/ |
mastra-reference.md |
| Policy | src/mastra/policy/ |
mastra-reference.md |
Transport Pattern
Chat connects directly to Mastra API (NEXT_PUBLIC_MASTRA_API_URL, default http://localhost:4111). Do not use MastraClient for chat streaming.
import { useChat } from '@ai-sdk/react'
import { DefaultChatTransport } from 'ai'
import { RequestContext, MASTRA_RESOURCE_ID_KEY, MASTRA_THREAD_ID_KEY } from '@mastra/core/request-context'
const MASTRA_API_URL = process.env.NEXT_PUBLIC_MASTRA_API_URL ?? 'http://localhost:4111'
const transport = new DefaultChatTransport({
api: `${MASTRA_API_URL}/chat/${selectedAgent}`,
prepareSendMessagesRequest({ messages: outgoingMessages }) {
const last = outgoingMessages[outgoingMessages.length - 1]
const textPart = last?.parts?.find((p): p is TextUIPart => p.type === 'text')
const requestContext = new RequestContext()
requestContext.set(MASTRA_RESOURCE_ID_KEY, resourceId)
requestContext.set(MASTRA_THREAD_ID_KEY, threadId)
return {
body: {
id: selectedAgent,
messages: outgoingMessages,
memory: { thread: threadId, resource: resourceId },
resourceId,
data: { agentId: selectedAgent, threadId, input: textPart?.text ?? '' },
requestContext,
},
}
},
})
const { messages, sendMessage, stop, status } = useChat({ transport })
UIMessage Parts (AI SDK v6)
Use message.parts, not message.content. Each part has a type discriminator.
| Part Type | Type Guard | Purpose |
|---|---|---|
text |
isTextUIPart |
Text content |
reasoning |
isReasoningUIPart |
Thinking/reasoning |
tool-* / dynamic-tool |
isToolUIPart / isToolOrDynamicToolUIPart |
Tool invocations |
file |
isFileUIPart |
Attachments |
source-url / source-document |
— | Citations |
data |
isDataUIPart |
Structured data |
import {
isTextUIPart,
isReasoningUIPart,
isToolOrDynamicToolUIPart,
isFileUIPart,
isDataUIPart,
} from 'ai'
const textPart = message.parts?.find(isTextUIPart)
const content = textPart?.text ?? ''
const tools = message.parts?.filter(isToolOrDynamicToolUIPart)
const fileParts = message.parts?.filter(isFileUIPart)
AI Elements Integration Map
| Component File | AI Elements Used |
|---|---|
chat-messages.tsx |
Conversation, Message, CodeBlock, Attachments, AudioPlayer, Transcription, Image |
agent-reasoning.tsx |
Reasoning, ReasoningTrigger, ReasoningContent |
agent-chain-of-thought.tsx |
ChainOfThought, ChainOfThoughtHeader, ChainOfThoughtContent, ChainOfThoughtStep |
agent-tools.tsx |
Tool, ToolHeader, ToolInput, ToolOutput |
agent-sources.tsx |
Sources, SourcesTrigger, SourcesContent, Source |
agent-artifact.tsx |
Artifact, ArtifactHeader, ArtifactContent, ArtifactActions, ArtifactCode |
agent-sandbox.tsx |
Sandbox, FileTree, Terminal, TestResults, SchemaDisplay, StackTrace |
agent-workflow.tsx |
Canvas, Node, Edge, Panel |
chat-input.tsx |
PromptInput, SpeechInput, Context (token usage), ModelSelector |
Import from @/src/components/ai-elements/<component>:
import { Message, MessageContent, MessageResponse } from '@/src/components/ai-elements/message'
import { Reasoning, ReasoningTrigger, ReasoningContent } from '@/src/components/ai-elements/reasoning'
import { Tool, ToolHeader, ToolInput, ToolOutput } from '@/src/components/ai-elements/tool'
Agent Config Features
agentConfig.features controls which agent-* components render. Check before rendering:
const { agentConfig } = useChatContext()
if (agentConfig.features.reasoning) {
// Render AgentReasoning
}
if (agentConfig.features.tools) {
// Render AgentTools
}
if (agentConfig.features.sources) {
// Render AgentSources
}
if (agentConfig.features.artifacts) {
// Render AgentArtifact
}
See app/chat/config/agents.ts for full AgentFeatures schema.
Mastra Stream Conversion
Server-side (Next.js API routes)
import { toAISdkStream } from '@mastra/ai-sdk'
import { createUIMessageStream, createUIMessageStreamResponse } from 'ai'
const stream = await agent.stream(messages, { threadId, resourceId, requestContext })
const uiStream = createUIMessageStream({
originalMessages: messages,
execute: async ({ writer }) => {
const aiStream = toAISdkStream(stream, {
from: 'agent',
sendReasoning: true,
sendSources: true,
})
for await (const value of aiStream) {
await writer.write(value)
}
},
})
return createUIMessageStreamResponse({ stream: uiStream })
Mastra chatRoute config (src/mastra/index.ts)
chatRoute({
path: '/chat/:agentId',
sendStart: true,
sendFinish: true,
sendReasoning: true,
sendSources: true,
})
MastraClient vs Direct Transport
| Use Case | Approach |
|---|---|
| Chat streaming | DefaultChatTransport → Mastra API directly |
| Network streaming | DefaultChatTransport → /network/:agentId |
| Workflow streaming | DefaultChatTransport → /workflow/:workflowId |
| Dashboard (agents, workflows, traces, threads) | MastraClient from lib/mastra-client.ts |
Do not use MastraClient for chat/network/workflow streaming.
Anti-Patterns
- Do not use MastraClient for chat streaming — use DefaultChatTransport.
- Use
message.partsnotmessage.content— AI SDK v6 is parts-based. - Import type guards from
ai— not custom implementations. - Check agentConfig.features before rendering agent-* components.
- Use RequestContext for multi-tenancy (resourceId, threadId) in prepareSendMessagesRequest.
Quick Reference
ChatContext value (useChatContext)
messages,status,isLoading,errorsendMessage(text, files?),stopGeneration(),clearMessages()selectedAgent,agentConfig,selectAgent(id)streamingContent,streamingReasoning,toolInvocations,sourcesthreadId,resourceId,setThreadId,setResourceIdwebPreview,setWebPreview,checkpoints,createCheckpoint,restoreCheckpoint
Endpoints
- Chat:
${MASTRA_API_URL}/chat/${agentId} - Network:
${MASTRA_API_URL}/network/${agentId} - Workflow:
${MASTRA_API_URL}/workflow/${workflowId}
Additional Resources
- AI Elements (one ref per category): ai-elements-reference.md
- Mastra backend (one ref per subdir): mastra-reference.md
- Agent config, API routes: reference.md
- Agent config schema:
app/chat/config/agents.ts - app/api/mastra routes: agents, workflows, threads, traces, tools, vectors, memory
More from ssdeanx/agentstack
test-cases
This skill should be used when generating comprehensive test cases from PRD documents or user requirements. Triggers when users request test case generation, QA planning, test scenario creation, or need structured test documentation. Produces detailed test cases covering functional, edge case, error handling, and state transition scenarios.
25product-requirements
Interactive Product Owner skill for requirements gathering, analysis, and PRD generation. Triggers when users request product requirements, feature specification, PRD creation, or need help understanding and documenting project requirements. Uses quality scoring and iterative dialogue to ensure comprehensive requirements before generating professional PRD documents.
22gemini
Execute Gemini CLI for AI-powered code analysis and generation. Use when you need to leverage Google's Gemini models for complex reasoning tasks.
21skill development
This skill should be used when the user wants to "create a skill", "add a skill to plugin", "write a new skill", "improve skill description", "organize skill content", or needs guidance on skill structure, progressive disclosure, or skill development best practices for Claude Code plugins.
21browser
This skill should be used for browser automation tasks using Chrome DevTools Protocol (CDP). Triggers when users need to launch Chrome with remote debugging, navigate pages, execute JavaScript in browser context, capture screenshots, or interactively select DOM elements. No MCP server required.
20plugin structure
This skill should be used when the user asks to "create a plugin", "scaffold a plugin", "understand plugin structure", "organize plugin components", "set up plugin.json", "use ${CLAUDE_PLUGIN_ROOT}", "add commands/agents/skills/hooks", "configure auto-discovery", or needs guidance on plugin directory layout, manifest configuration, component organization, file naming conventions, or Claude Code plugin architecture best practices.
20