UNPKG

@mastra/core

Version:

Mastra is a framework for building AI-powered applications and agents with a modern TypeScript stack.

280 lines (218 loc) • 9.08 kB
# 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). `toAISdkStream()` keeps the existing AI SDK v5/default behavior. If your app is typed against AI SDK v6, pass `version: 'v6'` in the options object. ## Structured output in UI streams When the source agent stream includes a final structured output object, `toAISdkStream()` emits it as a custom AI SDK UI data part: ```json { "type": "data-structured-output", "data": { "object": {} } } ``` The `object` field contains your full structured output value. This maps Mastra's final structured output chunk into the AI SDK UI stream. Partial structured output chunks are not emitted. ## 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: **version** (`'v5' | 'v6'`): Selects the AI SDK stream contract to emit. Omit it or pass \`'v5'\` for the existing default behavior. Pass \`'v6'\` when your app is typed against AI SDK v6 response helpers. (Default: `'v5'`) **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<string, unknown> | 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, }) } ``` ### Converting an agent stream for AI SDK v6 ```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', version: 'v6', })) { 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<ChunkType> const chunkStream = new ReadableStream<ChunkType>({ 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) } ```