PREVIEW · h6-text-turn-route-20260808 · noindex

The text-turn route: plug your own LLM into an Alive avatar.

Step 5 of the quickstart says “point it to your model, boom done.” This page is the boom-done part: a sample relay you run on your own server, so your provider key stays in your environment — never on a browser page, never on NetShow. That relay is built and validated — the proof conversation ran through it verbatim — and this static preview shows the exact wiring, with the live hookup to follow. The wire monitor at the bottom shows every request this page makes.

THE AVATAR — TWO-LINE EMBED, SEALED PACKAGE

package loading… seal state idle model not called yet

THE CONVERSATION — WIRED FOR THE SAMPLE RELAY

Page side: one fetch('/turn') + the documented five-line feeder — the face thinks while the model thinks, speaks while it streams, settles when it's done. Server side: the sample relay forwards the turn to the configured model endpoint and streams the reply back as plain text.

THE PERSONA — RIDES THE SEALED FILE, SWAPPABLE HERE

This box is seeded from personality_desc inside the sealed file — the persona your customer typed in the studio travels with the avatar. On this preview the page sends it per turn; in production, set SYSTEM_PROMPT in the relay's environment instead and the relay pins it server-side, ignoring anything a visitor's browser sends.

WIRE YOUR OWN MODEL — THE WHOLE THING IS 1-2-3

Download the relay onto your server

⬇ text-turn-relay.mjs — one file, zero npm installs, Node 18+. It has one job: take a turn from your page, forward it to your model endpoint, stream the reply back. Read it — it's short on purpose.

Start it with your model endpoint in the environment

Your key comes from your shell, on your machine. It is never written into a file and the page never sees it. No key at all for local models.

OPENAI-COMPATIBLE (OPENAI · GROQ · MISTRAL · VLLM · LM STUDIO…)
MODEL_URL=https://api.openai.com/v1/chat/completions \
MODEL_NAME=gpt-4o-mini \
MODEL_KEY=$OPENAI_API_KEY \
node text-turn-relay.mjs
ANTHROPIC
MODEL_KIND=anthropic \
MODEL_URL=https://api.anthropic.com/v1/messages \
MODEL_NAME=claude-sonnet-5 \
MODEL_KEY=$ANTHROPIC_API_KEY \
node text-turn-relay.mjs
LOCAL MODEL — NO KEY AT ALL (OLLAMA SHOWN)
MODEL_URL=http://127.0.0.1:11434/v1/chat/completions \
MODEL_NAME=llama3.2 \
node text-turn-relay.mjs

Put /turn on the same origin as your page — then talk

The avatar element and the relay both live by the same-origin law. Proxy the route through the web server that already serves your page (this preview is wired for exactly that; its live proxy hookup follows):

NGINX — PROXY_BUFFERING OFF KEEPS THE STREAM STREAMING
location = /turn {
  proxy_pass http://127.0.0.1:8787/turn;
  proxy_buffering off;
  proxy_read_timeout 180s;
}

And the page side is the quickstart's five-line feeder plus one fetch:

YOUR-PAGE.JS — THE FEEDER MEETS THE RELAY
import { attachTextAgent } from '/alive-site/alive-adapter-text.js';
const feeder = attachTextAgent(document.querySelector('netshow-alive').session);

feeder.userSaid(question);
feeder.beginTurn();
const res = await fetch('/turn', { method: 'POST',
  headers: { 'content-type': 'application/json' },
  body: JSON.stringify({ user: question, history }) });
const reader = res.body.getReader(); const dec = new TextDecoder();
for (;;) { const { done, value } = await reader.read();
  if (done) break; feeder.delta(dec.decode(value, { stream: true })); }
feeder.endTurn();  // boom — done

THE CONTRACT — WHAT MOVES ON THE WIRE

requestPOST /turn · JSON · { user, system?, history? }user ≤ 4000 chars; history ≤ 40 turns of {role:'user'|'assistant', content}; system is ignored when the relay pins SYSTEM_PROMPT server-side
reply200 text/plain, streamed as the model streams — feed each chunk straight into feeder.delta(). Header X-Brain-Model names the configured model
errorsterse JSON: 400 bad turn shape · 429 relay busy · 502 model endpoint failed (details stay in the relay's server log — never in the browser)
keyslive in the relay's environment on your server, used in exactly one place (the upstream auth header), never logged, never on this wire

WIRE MONITOR — EVERY REQUEST THIS PAGE MAKES