Skip to main content
By the end of this tutorial you’ll have a Next.js 15 chatbot that takes user messages, streams responses from the Livepeer LLM pipeline token-by-token, and maintains conversation history. The LLM pipeline is OpenAI-compatible at the wire level: it accepts messages arrays, returns choices[0].delta.content chunks, and behaves like any other chat completions endpoint. The Orchestrator pool runs Ollama-backed inference on GPUs as small as 8 GB. This is the Persona 1 activation moment for text inference. The image generation tutorial proved the batch path; this one proves the streaming path. The wire format you’ll handle here works against any OpenAI-compatible endpoint, which means swapping providers is a URL change.

Required Tools

  • Node.js 20 or later
  • npm, pnpm, or yarn
  • A code editor
No API key needed for development. The community Gateway at dream-gateway.livepeer.cloud accepts unauthenticated POSTs to the LLM endpoint for experimentation.

Project Bootstrap

1

Create the project

2

Configure environment variables

Save as .env.local:
The warm model on the community Gateway is Llama 3.1 8B Instruct. Cold-start applies to any other model: 30 seconds to a few minutes for the first request while the Orchestrator loads the weights.

Streaming Route Handler

Server actions can’t stream responses cleanly. Route handlers can; the standard pattern for chat is a POST /api/chat handler that proxies the request to the LLM endpoint and pipes the SSE response back to the client. Save as src/app/api/chat/route.ts:
Three things to notice. export const runtime = 'edge' runs the handler on Edge runtime, which keeps cold-start low and streams responses without buffering. The stream: true flag in the request body asks the LLM endpoint for Server-Sent Events instead of a single JSON response. The handler pipes the response body directly through; no SSE parsing on the server side, no JSON deserialisation. The browser parses the stream.

SSE Wire Format

The LLM endpoint streams chunks in this shape:
Each data: line is one token (or a small group of tokens) wrapped in OpenAI’s chat completions chunk shape. The final chunk has empty content and finish_reason: "stop". The client concatenates the content fields as they arrive and renders them incrementally.

Chat UI Component

The UI maintains a list of messages and appends to the last assistant message as tokens stream in. Save as src/app/components/Chat.tsx:
The reader loop pulls bytes from the response stream, decodes them, and splits on newlines. The buffer handles the case where a chunk lands mid-line. For each complete data: line, the handler parses the JSON, extracts the token from choices[0].delta.content, and appends it to the last assistant message. The loop exits when finish_reason: "stop" arrives.

Page Composition

Save as src/app/page.tsx:
Run the dev server:
Open http://localhost:3000. Type a message, hit Send, and tokens stream into the response bubble.

Model Selection

The community Gateway routes any model value to whichever Orchestrator has the requested weights warm. Llama 3.1 8B Instruct is the default warm model on the network. Three other Ollama-compatible models are commonly available: Any Ollama-compatible model works. Cold-start (30 seconds to a few minutes) applies to models not currently loaded on any Orchestrator. For consistent latency in production, run your own Gateway with the target model pre-loaded; see .

Production Considerations

The community Gateway is shaped for experimentation. Production chat needs four changes. Authentication. Swap to a paid Gateway and add Authorization: Bearer ${process.env.LIVEPEER_API_KEY} to the fetch headers in the route handler. Conversation persistence. The current implementation holds messages in client state, which means refresh loses the conversation. Persist to a database keyed by user and session. Token usage and rate limits. The LLM pipeline charges per token of output. Add a per-user token budget enforced server-side, and a per-IP rate limit on the route handler. Cold-start handling. If the requested model is cold, the first response can take a few minutes. Add a warming request on app start that sends a one-token completion in the background, so by the time a user opens chat the model is ready. Full hardening guidance in .

Common Errors

The route handler couldn’t reach the Gateway. Confirm LIVEPEER_GATEWAY_URL is set; the Edge runtime doesn’t read variables from .env.local in production unless they’re declared in next.config.ts or as Edge-runtime env vars.
The Orchestrator timed out or the model unloaded. Retry the request; the network routes to a different Orchestrator on retry.
A proxy (Cloudflare, nginx, Vercel) is buffering. Confirm the Cache-Control: no-cache and Content-Type: text/event-stream headers are set on the response. For Cloudflare, disable response buffering on the route.
Some chunks contain comments or empty lines. The handler skips empty lines and wraps parse in try/catch; if you see frequent parse errors, log the raw line to identify the format drift.
Expected for non-warm models. Either use the warm default (meta-llama/Meta-Llama-3.1-8B-Instruct) or send a warming request on app start.
You have a streaming chatbot on the Livepeer LLM pipeline. The same endpoint shape works for any Ollama-compatible model; switch the model field to try Mistral, Gemma, or Qwen variants.

Next Steps

Eliza Plugin Tutorial

Build a full agent with character files, RAG, and multi-agent swarms.

AI Pipelines

The other ten pipelines: image gen, audio, vision, segmentation.

Model Support

Warm models, VRAM requirements, custom model paths.

Production Hardening

Rate limits, auth, observability, cold-start handling.
Last modified on May 22, 2026