Runlane
Recipes

Streaming

Stream model output through your application and keep the final result on the run.

Run-scoped output streaming is not available in Runlane today. A task may consume a provider stream during its current attempt, while your application publishes chunks to its own realtime channel.

Stream a chat response through your application

The Runlane task and final output schema below are real. The marked streamModelOutputThroughYourApp() call is pseudocode that must both consume the model stream and publish chunks through your application’s database, event service, or WebSocket backend:

src/tasks/streaming-chat.ts
import { task } from '@runlane/core'
import * as z from 'zod'

const messageSchema = z.object({ content: z.string(), role: z.enum(['assistant', 'user']) })
const chatResultSchema = z.object({ response: z.string(), tokensUsed: z.number().int().nonnegative() })

export const streamingChat = task({
  id: 'chat.stream',
  schema: z.object({ messages: z.array(messageSchema).min(1).max(50) }),
  output: chatResultSchema,
  async run({ messages }, context) {
    //////////////////////////////////
    // MAKE YOUR API CALLS HERE
    //////////////////////////////////
    const result = await streamModelOutputThroughYourApp({
      messages,
      runId: context.run.id,
      signal: context.signal,
    })

    return chatResultSchema.parse(result)
  },
})

Key application-owned chunks by context.run.id so clients can reconnect. The returned object becomes the run’s final JSON output only after the provider stream finishes.

Runlane does not store, replay, or serve the chunks produced inside the marked call. Your application must handle reconnect cursors, duplicate updates, authorization, and retention.

Keep live and final data separate

  • Live chunks belong to your application-owned realtime channel.
  • Operational observations belong to logs and telemetry.
  • Terminal status and final JSON output belong to the stored Runlane run.

Do not return a ReadableStream, Node stream, response object, or binary buffer as task output.

If the task is waiting for a final external result, use a release or wait token. Those are durable coordination tools, not live streams.

On this page