streamText()

Stream text responses in real-time

Stream text responses in real-time. Returns helpers to consume the stream or convert it to HTTP responses.

import { streamText } from '@yourgpt/llm-sdk';
import { openai } from '@yourgpt/llm-sdk/openai';

const result = await streamText({
  model: openai('gpt-4o'),
  prompt: 'Tell me a story.',
});

// Option 1: Iterate over text chunks
for await (const chunk of result.textStream) {
  process.stdout.write(chunk);
}

// Option 2: Get complete text (waits for stream to finish)
const text = await result.text;

// Option 3: Return as HTTP Response
return result.toTextStreamResponse();

Parameters

const result = await streamText({
  // Required: Language model to use
  model: openai('gpt-4o'),

  // Content (at least one required)
  prompt: 'Hello',              // Simple prompt
  messages: [...],              // Chat history
  system: 'Be concise.',        // System instruction

  // Optional: Tools for function calling
  tools: { ... },
  maxSteps: 5,                  // Max LLM calls for tool loops

  // Optional: Generation settings
  temperature: 0.7,
  maxTokens: 4096,
});

Response Object

const result = await streamText({ ... });

// Streams
result.textStream     // AsyncIterable<string> - text only
result.fullStream     // AsyncIterable<StreamPart> - all events

// Promises (resolve when stream completes)
result.text           // Promise<string> - full text
result.usage          // Promise<TokenUsage> - token counts
result.finishReason   // Promise<FinishReason>

// HTTP Response helpers
result.toTextStreamResponse()   // text/plain stream
result.toDataStreamResponse()   // SSE with structured events

API Route Examples

app/api/chat/route.ts
import { streamText } from '@yourgpt/llm-sdk';
import { openai } from '@yourgpt/llm-sdk/openai';

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

  const result = await streamText({
    model: openai('gpt-4o'),
    system: 'You are helpful.',
    messages,
  });

  return result.toTextStreamResponse();
}
server.ts
import { createServer } from 'http';
import { streamText } from '@yourgpt/llm-sdk';
import { openai } from '@yourgpt/llm-sdk/openai';

createServer(async (req, res) => {
  const body = await getBody(req);
  const { messages } = JSON.parse(body);

  const result = await streamText({
    model: openai('gpt-4o'),
    system: 'You are helpful.',
    messages,
  });

  const response = result.toTextStreamResponse();
  res.writeHead(200, Object.fromEntries(response.headers));

  const reader = response.body!.getReader();
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    res.write(value);
  }
  res.end();
}).listen(3001);

function getBody(req: any): Promise<string> {
  return new Promise((resolve) => {
    let data = '';
    req.on('data', (chunk: any) => data += chunk);
    req.on('end', () => resolve(data));
  });
}

Response Types

Text Stream Response

Simple text streaming. Best for basic chat without tools.

return result.toTextStreamResponse();
Content-Type: text/plain; charset=utf-8

Hello! How can I help you?

Data Stream Response

SSE format with structured events. Use when you need tool calls, usage info, or step-by-step data.

return result.toDataStreamResponse();
Content-Type: text/event-stream

data: {"type":"text-delta","text":"Hello"}
data: {"type":"text-delta","text":"!"}
data: {"type":"tool-call-complete","toolCall":{...}}
data: {"type":"tool-result","toolCallId":"...","result":{...}}
data: {"type":"finish","finishReason":"stop","usage":{...}}
data: [DONE]

With Tools

import { streamText, tool } from '@yourgpt/llm-sdk';
import { z } from 'zod';

const result = await streamText({
  model: openai('gpt-4o'),
  prompt: 'What is the weather in Tokyo?',
  tools: {
    getWeather: tool({
      description: 'Get weather for a city',
      parameters: z.object({ city: z.string() }),
      execute: async ({ city }) => ({ temp: 22, condition: 'sunny' }),
    }),
  },
  maxSteps: 5,
});

return result.toDataStreamResponse();

Use toDataStreamResponse() with tools to receive tool call and result events.


Consuming the Full Stream

For custom handling of all events:

for await (const part of result.fullStream) {
  switch (part.type) {
    case 'text-delta':
      console.log('Text:', part.text);
      break;
    case 'tool-call-complete':
      console.log('Tool called:', part.toolCall.name);
      break;
    case 'tool-result':
      console.log('Tool result:', part.result);
      break;
    case 'step-start':
      console.log('Starting step:', part.step);
      break;
    case 'step-finish':
      console.log('Step done:', part.finishReason);
      break;
    case 'finish':
      console.log('Complete:', part.usage);
      break;
    case 'error':
      console.error('Error:', part.error);
      break;
  }
}

Stream Part Types

TypeDescriptionProperties
text-deltaText chunktext: string
tool-call-completeTool was calledtoolCall: { id, name, args }
tool-resultTool returnedtoolCallId, result
step-startNew step beganstep: number
step-finishStep completedstep, finishReason
finishStream donefinishReason, usage
errorError occurrederror: Error

Custom Response Headers

return result.toTextStreamResponse({
  status: 200,
  headers: {
    'X-Custom-Header': 'value',
  },
});

Abort Handling

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

  const result = await streamText({
    model: openai('gpt-4o'),
    messages,
    signal: req.signal, // Pass abort signal
  });

  return result.toTextStreamResponse();
}

Next Steps

On this page