### Install @mastra/ai-sdk with npm Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Install the necessary packages using npm to begin integrating Mastra with AI SDK UI. ```bash npm install @mastra/ai-sdk@latest @ai-sdk/react ai ``` -------------------------------- ### Install @mastra/ai-sdk with Bun Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Install the necessary packages using Bun to begin integrating Mastra with AI SDK UI. ```bash bun add @mastra/ai-sdk@latest @ai-sdk/react ai ``` -------------------------------- ### Install @mastra/ai-sdk with pnpm Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Install the necessary packages using pnpm to begin integrating Mastra with AI SDK UI. ```bash pnpm add @mastra/ai-sdk@latest @ai-sdk/react ai ``` -------------------------------- ### handleChatStream() API route setup Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Sets up a chat route at the /chat endpoint using an agent with the ID weatherAgent. The version is explicitly set to v7 to match the installed AI SDK. ```typescript import { handleChatStream } from '@mastra/ai-sdk' import { createUIMessageStreamResponse } from 'ai' import { mastra } from '@/src/mastra' export async function POST(req: Request) { const params = await req.json() const stream = await handleChatStream({ mastra, agentId: 'weatherAgent', version: 'v7', params, }) return createUIMessageStreamResponse({ stream }) } ``` -------------------------------- ### Install @mastra/ai-sdk with Yarn Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Install the necessary packages using Yarn to begin integrating Mastra with AI SDK UI. ```bash yarn add @mastra/ai-sdk@latest @ai-sdk/react ai ``` -------------------------------- ### handleNetworkStream() API route setup Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Sets up a network route at the /network endpoint using an agent with the ID routingAgent. ```typescript import { handleNetworkStream } from '@mastra/ai-sdk' import { createUIMessageStreamResponse } from 'ai' import { mastra } from '@/src/mastra' export async function POST(req: Request) { const params = await req.json() const stream = await handleNetworkStream({ mastra, agentId: 'routingAgent', params, }) return createUIMessageStreamResponse({ stream }) } ``` -------------------------------- ### handleWorkflowStream() API route setup Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Sets up a workflow route at the /workflow endpoint using a workflow with the ID weatherWorkflow. ```typescript import { handleWorkflowStream } from '@mastra/ai-sdk' import { createUIMessageStreamResponse } from 'ai' import { mastra } from '@/src/mastra' export async function POST(req: Request) { const params = await req.json() const stream = await handleWorkflowStream({ mastra, workflowId: 'weatherWorkflow', params, }) return createUIMessageStreamResponse({ stream }) } ``` -------------------------------- ### Implement Workflow Suspend/Resume with User Approval Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui This component uses useChat to manage workflow state, including starting a workflow and resuming it via approval or rejection. It accesses the suspend payload through step.suspendPayload and requires configured storage for persistence. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import { useMemo, useState } from 'react' import type { WorkflowDataPart } from '@mastra/ai-sdk' type WorkflowData = WorkflowDataPart['data'] export function ApprovalWorkflow() { const [requestId, setRequestId] = useState('') const [summary, setSummary] = useState('') const { messages, sendMessage, setMessages, status } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/workflow/approvalWorkflow', prepareSendMessagesRequest: ({ messages }) => { const lastMessage = messages[messages.length - 1] const text = lastMessage.parts.find(p => p.type === 'text')?.text const metadata = lastMessage.metadata as Record // Resuming: send runId, step, and resumeData if (text === 'Approve' || text === 'Reject') { return { body: { runId: metadata.runId, step: 'request-approval', resumeData: { approved: text === 'Approve' }, }, } } // Starting: send inputData return { body: { inputData: { requestId: metadata.requestId, summary: metadata.summary } }, } }, }), }) // Find suspended workflow const suspended = useMemo(() => { for (const m of messages) { for (const p of m.parts) { if (p.type === 'data-workflow' && (p.data as WorkflowData).status === 'suspended') { return { data: p.data as WorkflowData, runId: p.id } } } } return null }, [messages]) const handleApprove = () => { setMessages([]) sendMessage({ text: 'Approve', metadata: { runId: suspended?.runId } }) } const handleReject = () => { setMessages([]) sendMessage({ text: 'Reject', metadata: { runId: suspended?.runId } }) } return (
{!suspended ? (
{ e.preventDefault() setMessages([]) sendMessage({ text: 'Start', metadata: { requestId, summary } }) }} > setRequestId(e.target.value)} placeholder="Request ID" /> setSummary(e.target.value)} placeholder="Summary" />
) : (

{ (suspended.data.steps['request-approval']?.suspendPayload as { message: string }) ?.message }

)}
) } ``` -------------------------------- ### Emit custom events in a Mastra tool Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use writer.custom() within the execute function to send progress updates. Custom event types must start with 'data-'. ```typescript import { createTool } from '@mastra/core/tools' import { z } from 'zod' export const taskTool = createTool({ id: 'process-task', description: 'Process a task with progress updates', inputSchema: z.object({ task: z.string().describe('The task to process'), }), outputSchema: z.object({ result: z.string(), status: z.string(), }), execute: async (inputData, context) => { const { task } = inputData // Emit "in progress" custom event await context?.writer?.custom({ type: 'data-tool-progress', data: { status: 'in-progress', message: 'Gathering information...', }, }) // Simulate work await new Promise(resolve => setTimeout(resolve, 3000)) // Emit "done" custom event await context?.writer?.custom({ type: 'data-tool-progress', data: { status: 'done', message: `Successfully processed "${task}"`, }, }) return { result: `Task "${task}" has been completed successfully!`, status: 'completed', } }, }) ``` -------------------------------- ### Configure an agent to use the nested tool Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Initializes an agent configured with the nested agent tool. ```typescript import { Agent } from '@mastra/core/agent' import { nestedAgentTool } from '../tools/nested-agent-tool' export const forecastAgent = new Agent({ id: 'forecast-agent', instructions: 'Use the nested-agent-stream tool when asked about weather.', model: 'openai/gpt-5.6-sol', tools: { nestedAgentTool }, }) ``` -------------------------------- ### Create a workflow step with streaming Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Define a workflow step that uses the writer to pipe agent responses for real-time streaming. The step returns the final analysis and location for subsequent steps. ```typescript import { createStep, createWorkflow } from '@mastra/core/workflows' import { z } from 'zod' import { weatherAgent } from '../agents/weather-agent' const analyzeWeather = createStep({ id: 'analyze-weather', inputSchema: z.object({ location: z.string() }), outputSchema: z.object({ analysis: z.string(), location: z.string() }), execute: async ({ inputData, writer }) => { const response = await weatherAgent.stream( `Analyze the weather in ${inputData.location} and provide insights.`, ) // Pipe agent stream to step writer for real-time text streaming await response.fullStream.pipeTo(writer) return { analysis: await response.text, location: inputData.location, } }, }) const calculateScore = createStep({ id: 'calculate-score', inputSchema: z.object({ analysis: z.string(), location: z.string() }), outputSchema: z.object({ score: z.number(), summary: z.string() }), execute: async ({ inputData }) => { const score = inputData.analysis.includes('sunny') ? 85 : 50 return { score, summary: `Comfort score for ${inputData.location}: ${score}/100` } }, }) export const weatherWorkflow = createWorkflow({ id: 'weather-workflow', inputSchema: z.object({ location: z.string() }), outputSchema: z.object({ score: z.number(), summary: z.string() }), }) .then(analyzeWeather) .then(calculateScore) weatherWorkflow.commit() ``` -------------------------------- ### Mastra Server Backend for useCompletion Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Backend implementation using registerApiRoute to handle completion requests and stream responses via handleChatStream. ```ts import { Mastra } from '@mastra/core/mastra' import { registerApiRoute } from '@mastra/core/server' import { handleChatStream } from '@mastra/ai-sdk' import { createUIMessageStreamResponse } from 'ai' export const mastra = new Mastra({ server: { apiRoutes: [ registerApiRoute('/completion', { method: 'POST', handler: async c => { const { prompt } = await c.req.json() const mastra = c.get('mastra') const stream = await handleChatStream({ mastra, agentId: 'weatherAgent', params: { messages: [ { id: '1', role: 'user', parts: [ { type: 'text', text: prompt, }, ], }, ], }, }) return createUIMessageStreamResponse({ stream }) }, }), ], }, }) ``` -------------------------------- ### Set up networkRoute for Mastra server Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Configures a network route at the /network endpoint using the weatherAgent. ```typescript import { Mastra } from '@mastra/core' import { networkRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ server: { apiRoutes: [ networkRoute({ path: '/network', agent: 'weatherAgent', }), ], }, }) ``` -------------------------------- ### Set up chatRoute for Mastra server Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Configures a chat route at the /chat endpoint using the weatherAgent. ```typescript import { Mastra } from '@mastra/core' import { chatRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ server: { apiRoutes: [ chatRoute({ path: '/chat', agent: 'weatherAgent', }), ], }, }) ``` -------------------------------- ### Register workflow with storage Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Configures the Mastra instance with the approval workflow and LibSQL storage, which is required for persisting state during suspension. ```typescript import { Mastra } from '@mastra/core' import { workflowRoute } from '@mastra/ai-sdk' import { LibSQLStore } from '@mastra/libsql' export const mastra = new Mastra({ workflows: { approvalWorkflow }, storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:../mastra.db', }), server: { apiRoutes: [ workflowRoute({ path: '/workflow/approvalWorkflow', workflow: 'approvalWorkflow' }), ], }, }) ``` -------------------------------- ### Set up workflowRoute for Mastra server Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Configures a workflow route at the /workflow endpoint using the weatherWorkflow. ```typescript import { Mastra } from '@mastra/core' import { workflowRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ server: { apiRoutes: [ workflowRoute({ path: '/workflow', workflow: 'weatherWorkflow', }), ], }, }) ``` -------------------------------- ### Define a weather tool with outputSchema Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Define a tool using createTool with an outputSchema to ensure the frontend receives the expected data structure for rendering. ```typescript import { createTool } from '@mastra/core/tools' import { z } from 'zod' export const weatherTool = createTool({ id: 'get-weather', description: 'Get current weather for a location', inputSchema: z.object({ location: z.string().describe('The location to get the weather for'), }), outputSchema: z.object({ temperature: z.number(), feelsLike: z.number(), humidity: z.number(), windSpeed: z.number(), conditions: z.string(), location: z.string(), }), execute: async inputData => { const response = await fetch( `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${inputData.location}`, ) const data = await response.json() return { temperature: data.current.temp_c, feelsLike: data.current.feelslike_c, humidity: data.current.humidity, windSpeed: data.current.wind_kph, conditions: data.current.condition.text, location: data.location.name, } }, }) ``` -------------------------------- ### Create approval workflow step and workflow Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Defines a workflow step with suspend and resume schemas to handle user approval, followed by the workflow definition. ```typescript import { createStep, createWorkflow } from '@mastra/core/workflows' import { z } from 'zod' const requestApproval = createStep({ id: 'request-approval', inputSchema: z.object({ requestId: z.string(), summary: z.string() }), outputSchema: z.object({ approved: z.boolean(), requestId: z.string(), approvedBy: z.string().optional(), }), resumeSchema: z.object({ approved: z.boolean(), approverName: z.string().optional(), }), suspendSchema: z.object({ message: z.string(), requestId: z.string(), }), execute: async ({ inputData, resumeData, suspend, bail }) => { // User rejected - bail out if (resumeData?.approved === false) { return bail({ message: 'Request rejected' }) } // User approved - continue if (resumeData?.approved) { return { approved: true, requestId: inputData.requestId, approvedBy: resumeData.approverName || 'User', } } // First execution - suspend and wait return await suspend({ message: `Please approve: ${inputData.summary}`, requestId: inputData.requestId, }) }, }) export const approvalWorkflow = createWorkflow({ id: 'approval-workflow', inputSchema: z.object({ requestId: z.string(), summary: z.string() }), outputSchema: z.object({ approved: z.boolean(), requestId: z.string(), approvedBy: z.string().optional(), }), }).then(requestApproval) approvalWorkflow.commit() ``` -------------------------------- ### Create a tool with nested agent streaming Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Defines a tool that retrieves an agent, streams its response, and pipes the full stream to the tool's writer. ```typescript import { createTool } from '@mastra/core/tools' import { z } from 'zod' export const nestedAgentTool = createTool({ id: 'nested-agent-stream', description: 'Analyze weather using a nested agent', inputSchema: z.object({ city: z.string().describe('The city to analyze'), }), outputSchema: z.object({ summary: z.string(), }), execute: async (inputData, context) => { const agent = context?.mastra?.getAgent('weatherAgent') if (!agent) { return { summary: 'Weather agent not available' } } const stream = await agent.stream( `Analyze the weather in ${inputData.city} and provide a summary.`, ) // Pipe the agent's stream to emit data-tool-agent parts await stream.fullStream.pipeTo(context!.writer!) return { summary: (await stream.text) ?? 'No summary available' } }, }) ``` -------------------------------- ### Define a multi-step workflow Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Create a workflow with multiple steps that emit workflow state and step data upon execution. ```typescript import { createStep, createWorkflow } from '@mastra/core/workflows' import { z } from 'zod' const fetchWeather = createStep({ id: 'fetch-weather', inputSchema: z.object({ location: z.string(), }), outputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), execute: async ({ inputData }) => { // Fetch weather data... return { temperature: 22, conditions: 'Sunny' } }, }) const planActivities = createStep({ id: 'plan-activities', inputSchema: z.object({ temperature: z.number(), conditions: z.string(), }), outputSchema: z.object({ activities: z.string(), }), execute: async ({ inputData, mastra }) => { const agent = mastra?.getAgent('activityAgent') const response = await agent?.generate( `Suggest activities for ${inputData.conditions} weather at ${inputData.temperature}°C`, ) return { activities: response?.text || '' } }, }) export const activitiesWorkflow = createWorkflow({ id: 'activities-workflow', inputSchema: z.object({ location: z.string(), }), outputSchema: z.object({ activities: z.string(), }), }) .then(fetchWeather) .then(planActivities) activitiesWorkflow.commit() ``` -------------------------------- ### Frontend Implementation for useCompletion Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui A basic React component using the useCompletion hook to send prompts and display streamed responses. ```typescript import { useCompletion } from '@ai-sdk/react' export default function Page() { const { completion, input, handleInputChange, handleSubmit } = useCompletion({ api: '/api/completion', }) return (
{completion}
) } ``` -------------------------------- ### Render network data on the frontend Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the NetworkDataPart type to safely parse and render agent execution steps from data-network parts received via the AI SDK chat transport. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import type { NetworkDataPart } from '@mastra/ai-sdk' type NetworkData = NetworkDataPart['data'] function AgentStep({ step }: { step: NetworkData['steps'][number] }) { return (
{step.name} {step.status}
{step.input && (
Input:
{JSON.stringify(step.input, null, 2)}
)} {step.output && (
Output:
            {typeof step.output === 'string' ? step.output : JSON.stringify(step.output, null, 2)}
          
)}
) } export function NetworkChat() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/network', }), }) return (
{messages.map(message => (
{message.parts.map((part, index) => { if (part.type === 'data-network') { const networkData = part.data as NetworkData return (

Agent Network: {networkData.name}

{networkData.status}
{networkData.steps.map((step, stepIndex) => ( ))}
) } return null })}
))}
) } ``` -------------------------------- ### Next.js Backend for useCompletion Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Backend implementation for a Next.js route handler to process completion requests and stream responses. ```ts import { handleChatStream } from '@mastra/ai-sdk' import { createUIMessageStreamResponse } from 'ai' import { mastra } from '@/src/mastra' // Allow streaming responses up to 30 seconds export const maxDuration = 30 export async function POST(req: Request) { const { prompt }: { prompt: string } = await req.json() const stream = await handleChatStream({ mastra, agentId: 'weatherAgent', params: { messages: [ { id: '1', role: 'user', parts: [ { type: 'text', text: prompt, }, ], }, ], }, }) return createUIMessageStreamResponse({ stream }) } ``` -------------------------------- ### Render custom tool output component in Chat Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the useChat hook to process message parts and render a WeatherCard component based on the tool-weatherTool state. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import { WeatherCard } from './weather-card' import { Loader } from './loader' export function Chat() { const { messages, sendMessage } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat/weatherAgent', }), }) return (
{messages.map(message => (
{message.parts.map((part, index) => { // Handle user text messages if (part.type === 'text' && message.role === 'user') { return

{part.text}

} // Handle weather tool output if (part.type === 'tool-weatherTool') { switch (part.state) { case 'input-available': return case 'output-available': return case 'output-error': return
Error: {part.errorText}
default: return null } } return null })}
))}
) } ``` -------------------------------- ### Register and expose workflow via workflowRoute Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Register the workflow in the Mastra instance and expose it using workflowRoute to enable streaming events to the frontend. ```typescript import { Mastra } from '@mastra/core' import { workflowRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ workflows: { activitiesWorkflow }, server: { apiRoutes: [ workflowRoute({ path: '/workflow/activitiesWorkflow', workflow: 'activitiesWorkflow', }), ], }, }) ``` -------------------------------- ### Consume workflow stream on the frontend Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the useChat hook to connect to the workflow route and render data-workflow and data-workflow-step parts. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import type { WorkflowDataPart, WorkflowStepDataPart } from '@mastra/ai-sdk' type WorkflowData = WorkflowDataPart['data'] type WorkflowStepData = WorkflowStepDataPart['data'] type StepStatus = 'running' | 'success' | 'failed' | 'suspended' | 'waiting' function StepIndicator({ name, status, output, }: { name: string status: StepStatus output: unknown }) { return (
{name} {status}
{status === 'success' && output &&
{JSON.stringify(output, null, 2)}
}
) } export function WorkflowChat() { const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/workflow/activitiesWorkflow', prepareSendMessagesRequest: ({ messages }) => ({ body: { inputData: { location: messages[messages.length - 1]?.parts[0]?.text, }, }, }), }), }) return (
{messages.map(message => (
{message.parts.map((part, index) => { if (part.type === 'data-workflow') { const workflowData = part.data as WorkflowData const steps = Object.values(workflowData.steps) return (

Workflow: {workflowData.name}

Status: {workflowData.status}

{steps.map(step => ( ))}
) } if (part.type === 'data-workflow-step') { const stepData = part.data as WorkflowStepData return ( ) } return null })}
))}
) } ``` -------------------------------- ### Handle nested agent streams in the frontend Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui A React component using useChat to process data-tool-agent and data-tool-agent-step parts from the backend stream. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import { useState } from 'react' import type { AgentDataPart, AgentStepDataPart } from '@mastra/ai-sdk' export function NestedAgentChat() { const [input, setInput] = useState('') const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat/forecastAgent', }), }) return (
{ e.preventDefault() sendMessage({ text: input }) setInput('') }} > setInput(e.target.value)} placeholder="Enter a city" />
{messages.map(message => (
{message.parts.map((part, index) => { if (part.type === 'text') { return

{part.text}

} if (part.type === 'data-tool-agent') { const { id, data } = part as AgentDataPart return (
Nested Agent: {id} {data.text &&

{data.text}

}
) } if (part.type === 'data-tool-agent-step') { const { data } = part as AgentStepDataPart return (
Completed nested step {data.stepIndex + 1} {data.step.text &&

{data.step.text}

}
) } return null })}
))}
) } ``` -------------------------------- ### Register networkRoute in Mastra backend Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Expose the routing agent via networkRoute() within the Mastra server configuration to stream network execution events. ```typescript import { Mastra } from '@mastra/core' import { networkRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ agents: { routingAgent, researchAgent, weatherAgent }, server: { apiRoutes: [ networkRoute({ path: '/network', agent: 'routingAgent', }), ], }, }) ``` -------------------------------- ### Register workflow with workflowRoute Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Expose the workflow via an API route. Text streaming is enabled by default. ```typescript import { Mastra } from '@mastra/core' import { workflowRoute } from '@mastra/ai-sdk' export const mastra = new Mastra({ agents: { weatherAgent }, workflows: { weatherWorkflow }, server: { apiRoutes: [workflowRoute({ path: '/workflow/weather', workflow: 'weatherWorkflow' })], }, }) ``` -------------------------------- ### Render streaming output in React Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the useChat hook to consume streaming text and workflow progress data. The component handles both assistant text parts and data-workflow parts. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import { useState } from 'react' import type { WorkflowDataPart } from '@mastra/ai-sdk' type WorkflowData = WorkflowDataPart['data'] export function WeatherWorkflow() { const [location, setLocation] = useState('') const { messages, sendMessage, status } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/workflow/weather', prepareSendMessagesRequest: ({ messages }) => ({ body: { inputData: { location: messages[messages.length - 1].parts.find(p => p.type === 'text')?.text, }, }, }), }), }) return (
{ e.preventDefault() sendMessage({ text: location }) setLocation('') }} > setLocation(e.target.value)} placeholder="Enter city" />
{messages.map(message => (
{message.parts.map((part, index) => { // Streaming agent text if (part.type === 'text' && message.role === 'assistant') { return (
{status === 'streaming' && (

Agent analyzing...

)}

{part.text}

) } // Workflow step progress if (part.type === 'data-workflow') { const workflow = part.data as WorkflowData return (
{Object.entries(workflow.steps).map(([stepId, step]) => (
{stepId}: {step.status}
))}
) } return null })}
))}
) } ``` -------------------------------- ### Configure useChat with Mastra Memory Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the DefaultChatTransport to send only the latest message to the server while providing thread and resource identifiers for memory management. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' const { messages, sendMessage } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat/weatherAgent', prepareSendMessagesRequest({ messages }) { return { body: { messages: [messages[messages.length - 1]], memory: { thread: 'user-thread-123', resource: 'user-123', }, }, } }, }), }) ``` -------------------------------- ### useChat() hook implementation Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Consumes a chat API endpoint using the useChat hook with DefaultChatTransport. Ensure the api URL matches your configured route. ```ts import { useChat } from '@ai-sdk/react' import { useState } from 'react' import { DefaultChatTransport } from 'ai' export default function Chat() { const [inputValue, setInputValue] = useState('') const { messages, sendMessage } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat', }), }) const handleFormSubmit = (e: React.FormEvent) => { e.preventDefault() sendMessage({ text: inputValue }) } return (
{JSON.stringify(messages, null, 2)}
setInputValue(e.target.value)} placeholder="Name of the city" />
) } ``` -------------------------------- ### Implement RequestContext middleware in Mastra Server Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Add a server-level middleware to your Mastra configuration to extract data from the request body and set it into the RequestContext. ```typescript import { Mastra } from '@mastra/core' export const mastra = new Mastra({ server: { middleware: [ async (c, next) => { const requestContext = c.get('requestContext') if (c.req.method === 'POST') { const clonedReq = c.req.raw.clone() const body = await clonedReq.json() if (body?.data) { for (const [key, value] of Object.entries(body.data)) { requestContext.set(key, value) } } } await next() }, ], }, }) ``` -------------------------------- ### Handle custom events in a React frontend Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Filter message parts for the custom event type and render UI components based on the event data. ```typescript import { useChat } from '@ai-sdk/react' import { DefaultChatTransport } from 'ai' import { useMemo } from 'react' type ProgressData = { status: 'in-progress' | 'done' message: string } function ProgressIndicator({ progress }: { progress: ProgressData }) { return (
{progress.status === 'in-progress' ? ( ) : ( )} {progress.message}
) } export function TaskChat() { const { messages, sendMessage } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat/taskAgent', }), }) // Extract the latest progress event from messages const latestProgress = useMemo(() => { const allProgressParts: ProgressData[] = [] messages.forEach(message => { message.parts.forEach(part => { if (part.type === 'data-tool-progress') { allProgressParts.push(part.data as ProgressData) } }) }) return allProgressParts[allProgressParts.length - 1] }, [messages]) return (
{latestProgress && } {messages.map(message => (
{message.parts.map((part, index) => { if (part.type === 'text') { return

{part.text}

} return null })}
))}
) } ``` -------------------------------- ### Pass additional data with useChat Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use the sendMessage function from useChat to pass custom data from the frontend to the server, where it can be accessed as RequestContext. ```typescript import { useChat } from '@ai-sdk/react' import { useState } from 'react' import { DefaultChatTransport } from 'ai' export function ChatAdditional() { const [inputValue, setInputValue] = useState('') const { messages, sendMessage } = useChat({ transport: new DefaultChatTransport({ api: 'http://localhost:4111/chat-extra', }), }) const handleFormSubmit = (e: React.FormEvent) => { e.preventDefault() sendMessage( { text: inputValue }, { body: { data: { userId: 'user123', preferences: { language: 'en', temperature: 'celsius', }, }, }, }, ) } return (
{JSON.stringify(messages, null, 2)}
setInputValue(e.target.value)} placeholder="Name of the city" />
) } ``` -------------------------------- ### Transform streams with toAISdkStream Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Use toAISdkStream to convert Mastra streams to AI SDK-compatible format. Specify version: 'v6' if your application is typed against AI SDK v6. ```typescript import { toAISdkStream } from '@mastra/ai-sdk' const v5Stream = toAISdkStream(mastraStream, { from: 'agent' }) const v6Stream = toAISdkStream(mastraStream, { from: 'agent', version: 'v6' }) ``` -------------------------------- ### Handle RequestContext in Next.js API route Source: https://mastra.ai/integrations/agentic-ui/ai-sdk-ui Manually instantiate RequestContext in a Next.js POST route to process incoming data and pass it to handleChatStream. ```typescript import { handleChatStream } from '@mastra/ai-sdk' import { RequestContext } from '@mastra/core/request-context' import { createUIMessageStreamResponse } from 'ai' import { mastra } from '@/src/mastra' export async function POST(req: Request) { const { messages, data } = await req.json() const requestContext = new RequestContext() if (data) { for (const [key, value] of Object.entries(data)) { requestContext.set(key, value) } } const stream = await handleChatStream({ mastra, agentId: 'weatherAgent', params: { messages, requestContext, }, }) return createUIMessageStreamResponse({ stream }) } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.