@AiStream
@AiStream(options?) is the method decorator that turns a Nest HTTP handler into
an AI SDK streaming endpoint. The handler returns an AI SDK stream result and the
decorator pipes it to the active HTTP adapter while preserving the full Nest
enhancer pipeline.
import { AiStream } from '@nest-native/ai-sdk';
import { Body, Controller, Post } from '@nestjs/common';
import { streamText } from 'ai';
@Controller('chat')
export class ChatController {
@Post()
@AiStream()
chat(@Body() body: ChatDto) {
return streamText({ model, prompt: body.prompt });
}
}
Internally, @AiStream is applyDecorators(SetMetadata(...), UseInterceptors(AiStreamInterceptor)).
Because it is an interceptor, the whole enhancer pipeline runs before the stream
opens — see Enhancer Pipeline.
What The Handler Returns
The handler returns an AI SDK stream result, synchronously or as a promise that
resolves to one. The package serializes it through the AI SDK's own
pipe*ToResponse helpers, so the wire protocol is exactly what the AI SDK
produces:
- For the default
ui-messageformat, the result must exposepipeUIMessageStreamToResponse(response, init)—streamTextresults do. - For the
textformat, the result must exposepipeTextStreamToResponse(response, init).
Custom streams built with createUIMessageStream return a bare ReadableStream;
wrap them in a tiny app-owned adapter that exposes
pipeUIMessageStreamToResponse. See Stream Formats.
Options
@AiStream accepts an AiStreamOptions object. Every field is optional.
format
@AiStream({ format: 'text' })
The wire format used to serialize the result. 'ui-message' (default) preserves
the AI SDK UI message stream protocol consumed by @ai-sdk/react and useChat.
'text' emits a plain text/plain delta stream. See
Stream Formats.
headers
@AiStream({ headers: { 'x-model': 'gpt-4o' } })
Extra response headers merged on top of AiModuleOptions.defaultHeaders.
Method-level keys win on conflict.
status
@AiStream({ status: 200 })
The HTTP status code for the streaming response. Defaults to 200. Because the
status is sent with the first byte, it applies only to a successful stream open —
a pre-stream rejection still uses the enhancer's HTTP status.
onError
@AiStream({ onError: () => 'The model is temporarily unavailable.' })
The in-stream error mapper for this route. It maps an error thrown during
stream production to the message carried by the AI SDK's documented error frame.
It overrides AiModuleOptions.onError. Only the ui-message format defines an
error frame, so this option is ignored for format: 'text'. When omitted, the AI
SDK's secret-safe default ('An error occurred.') is used, so raw provider errors
never leak. See Error Mapping.
Option Resolution
Headers and the error mapper resolve from two layers:
- Module defaults from
AiModule.forRoot({ defaultHeaders, onError }). - Method options from
@AiStream({ headers, onError }).
Method-level values win. Headers merge per-key (method keys override matching
default keys); onError is replaced wholesale by the method value when present.
Related
- @AiAbortSignal — cancel the AI SDK call on disconnect.
- Error Mapping — pre-stream vs in-stream errors.
- API Reference — the full type surface.