How to stream tool output?

I have an ai sdk tool used by a tool loop agent. I want to make the tool stream it’s output instead of waiting for one final result. Is this possible?

Hi eyueldk,

If you mean “stream progress to the UI while the tool is running,” yes, but I would treat that separately from the actual tool result.

For an AI SDK tool, execute still returns one final result back to the model. The model/agent loop will not consume partial tool chunks as incremental tool results. What you can do is stream custom UI data/status parts while the tool is executing, then return the final tool result normally.

One pattern is to wrap the response in createUIMessageStream and let the tool close over the stream writer:

import {
  createUIMessageStream,
  createUIMessageStreamResponse,
  streamText,
  tool,
  stepCountIs,
} from "ai"
import { z } from "zod"

export async function POST(req: Request) {
  const { messages } = await req.json()

  const stream = createUIMessageStream({
    execute: ({ writer }) => {
      const result = streamText({
        model,
        messages,
        tools: {
          longTask: tool({
            description: "Run a long task",
            inputSchema: z.object({
              query: z.string(),
            }),
            execute: async ({ query }, { toolCallId }) => {
              writer.write({
                type: "data-tool-progress",
                id: toolCallId,
                data: { status: "started" },
                transient: true,
              })

              const finalResult = await runLongTask(query)

              writer.write({
                type: "data-tool-progress",
                id: toolCallId,
                data: { status: "done" },
                transient: true,
              })

              return finalResult
            },
          }),
        },
        stopWhen: stepCountIs(5),
      })

      writer.merge(result.toUIMessageStream())
    },
  })

  return createUIMessageStreamResponse({ stream })
}

Then on the client, render those data-tool-progress parts with useChat / onData.

The custom data streaming docs are useful for this pattern:

If you need the model itself to react to each partial chunk, I’d split the work into smaller tool calls or return a summarized final result. Streaming progress to the user and feeding tool results back to the model are two different flows in the SDK.