# toAISdkStream() Converts Mastra streams (agent, network, or workflow) to AI SDK-compatible streams. Use this function when you need to manually transform Mastra streams for use with AI SDK's `createUIMessageStream()` and `createUIMessageStreamResponse()`. This is useful when building custom streaming endpoints outside Mastra's provided route helpers such as [`chatRoute()`](https://mastra.ai/reference/ai-sdk/chat-route) or [`workflowRoute()`](https://mastra.ai/reference/ai-sdk/workflow-route). ## Usage example Next.js App Router example: ```typescript import { mastra } from "../../mastra"; import { createUIMessageStream, createUIMessageStreamResponse } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); const uiMessageStream = createUIMessageStream({ originalMessages: messages, execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: "agent" })) { await writer.write(part); } }, }); return createUIMessageStreamResponse({ stream: uiMessageStream, }); } ``` > **Tip:** Pass `messages` to `originalMessages` in `createUIMessageStream()` to avoid duplicated assistant messages in the UI. See [Troubleshooting: Repeated Assistant Messages](https://ai-sdk.dev/docs/troubleshooting/repeated-assistant-messages) for details. ## Parameters The first parameter is the Mastra stream to convert. It can be one of: - `MastraModelOutput` - An agent stream from `agent.stream()` - `MastraAgentNetworkStream` - A network stream from `agent.network()` - `MastraWorkflowStream` or `WorkflowRunOutput` - A workflow stream The second parameter is an options object: **from:** (`'agent' | 'network' | 'workflow'`): The type of Mastra stream being converted. (Default: `'agent'`) **lastMessageId?:** (`string`): (Agent only) The ID of the last message in the conversation. **sendStart?:** (`boolean`): (Agent only) Whether to send start events in the stream. (Default: `true`) **sendFinish?:** (`boolean`): (Agent only) Whether to send finish events in the stream. (Default: `true`) **sendReasoning?:** (`boolean`): (Agent only) Whether to include reasoning-delta chunks in the stream. Set to true to stream reasoning content from models that support extended thinking. (Default: `false`) **sendSources?:** (`boolean`): (Agent only) Whether to include source citations in the output. (Default: `false`) **includeTextStreamParts?:** (`boolean`): (Workflow only) Whether to include text stream parts in the output. (Default: `true`) **messageMetadata?:** (`(options: { part: UIMessageStreamPart }) => Record | undefined`): (Agent only) A function that receives the current stream part and returns metadata to attach to start and finish chunks. **onError?:** (`(error: unknown) => string`): (Agent only) A function to handle errors during stream conversion. Receives the error and should return a string representation. ## Examples ### Converting a workflow stream ```typescript import { mastra } from "../../mastra"; import { createUIMessageStream, createUIMessageStreamResponse } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; export async function POST(req: Request) { const { input } = await req.json(); const workflow = mastra.getWorkflow("myWorkflow"); const run = workflow.createRun(); const stream = await run.stream({ inputData: input }); const uiMessageStream = createUIMessageStream({ execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: "workflow" })) { await writer.write(part); } }, }); return createUIMessageStreamResponse({ stream: uiMessageStream, }); } ``` ### Converting a network stream ```typescript import { mastra } from "../../mastra"; import { createUIMessageStream, createUIMessageStreamResponse } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; export async function POST(req: Request) { const { messages } = await req.json(); const routingAgent = mastra.getAgent("routingAgent"); const stream = await routingAgent.network(messages); const uiMessageStream = createUIMessageStream({ execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: "network" })) { await writer.write(part); } }, }); return createUIMessageStreamResponse({ stream: uiMessageStream, }); } ``` ### Converting an agent stream with reasoning enabled ```typescript import { mastra } from "../../mastra"; import { createUIMessageStream, createUIMessageStreamResponse } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; export async function POST(req: Request) { const { messages } = await req.json(); const reasoningAgent = mastra.getAgent("reasoningAgent"); const stream = await reasoningAgent.stream(messages, { providerOptions: { openai: { reasoningEffort: "high" }, }, }); const uiMessageStream = createUIMessageStream({ originalMessages: messages, execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: "agent", sendReasoning: true, })) { await writer.write(part); } }, }); return createUIMessageStreamResponse({ stream: uiMessageStream, }); } ``` ### Using messageMetadata ```typescript import { mastra } from "../../mastra"; import { createUIMessageStream, createUIMessageStreamResponse } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; export async function POST(req: Request) { const { messages } = await req.json(); const myAgent = mastra.getAgent("weatherAgent"); const stream = await myAgent.stream(messages); const uiMessageStream = createUIMessageStream({ originalMessages: messages, execute: async ({ writer }) => { for await (const part of toAISdkStream(stream, { from: "agent", messageMetadata: ({ part }) => ({ timestamp: Date.now(), partType: part.type, }), })) { await writer.write(part); } }, }); return createUIMessageStreamResponse({ stream: uiMessageStream, }); } ``` ### Client-side stream transformation If you're using the Mastra client SDK (`@mastra/client-js`) on the client side and want to convert streams to AI SDK format: ```typescript import { MastraClient } from "@mastra/client-js"; import { createUIMessageStream } from "ai"; import { toAISdkStream } from "@mastra/ai-sdk"; import type { ChunkType, MastraModelOutput } from "@mastra/core/stream"; const client = new MastraClient({ baseUrl: "http://localhost:4111", }); const agent = client.getAgent("weatherAgent"); const response = await agent.stream("What is the weather in Tokyo?"); // Convert the client SDK stream to a ReadableStream const chunkStream = new ReadableStream({ async start(controller) { await response.processDataStream({ onChunk: async (chunk) => { controller.enqueue(chunk); }, }); controller.close(); }, }); // Transform to AI SDK format const uiMessageStream = createUIMessageStream({ execute: async ({ writer }) => { for await (const part of toAISdkStream( chunkStream as unknown as MastraModelOutput, { from: "agent" } )) { await writer.write(part); } }, }); for await (const part of uiMessageStream) { console.log(part); } ```