Skip to main content

PersonaPlex

PersonaPlex is PolarGrid’s real-time voice conversation endpoint. It streams Opus audio in both directions over a single WebSocket, with a persona prompt and voice selected at connect time.

PersonaPlex vs. the Modular Pipeline Agent

PersonaPlex is not listed in GET /v1/models — that endpoint only returns the Triton-served request/response models (qwen-3.5-27b, whisper-large-v3-turbo, cohere-transcribe-03-2026, kokoro-82m, tada-3b-ml). PersonaPlex runs as a separate moshi-backend LiveKit agent pod with its own WebSocket endpoint and wire protocol.

Connecting

Open a WebSocket to the voice endpoint with your pg_* API key as the token query parameter.

Open the WebSocket

Default region is yto-01 (Toronto) if you omit it. As an alternative to the token query parameter, you can pass the credential via the WebSocket subprotocol header:

Voices

Pass one of the following as the voice query parameter. Do not include the .pt suffix.

Wire protocol

All frames are binary. The first byte is a type tag; the remaining bytes are the payload.

Client → Server

Server → Client

0x03 eos marks end-of-turn, not end-of-reply. Sending eos after your audio tells the agent you are done speaking. The agent completes its full reply after receiving eos. In builds prior to June 2026, eos interrupted the agent’s in-flight reply, causing truncated responses. If you integrated during the alpha and added workarounds for that behavior, retest without them.

Gotchas

Wait for the 0x00 handshake before sending any audio. The first audio bytes you send must be the Opus Ogg BOS (beginning-of-stream) page. If audio arrives before the handshake — or without a valid BOS page — the server closes the connection with code 1000.
Disable your WebSocket library’s heartbeat / ping. The upstream moshi runtime does not respond to RFC 6455 pongs, so a client-side ping timer will tear down an otherwise healthy session. Most libraries expose this as a ping_interval or heartbeat option — set it to 0 or None.
Sessions are billed by wall-clock duration. Close the socket as soon as the conversation is idle; an open connection keeps accruing cost even with no audio flowing.

Quickstart

Both examples below do the same thing: connect to PersonaPlex, send a pre-recorded audio file, and save the response audio to disk. Pick the language you prefer.

Prerequisites

  • A PolarGrid API key (get one here)
  • An input audio file (WAV, mono, 24 kHz recommended — other sample rates will be resampled)

Python

Usage:

Node.js

Usage:
The Node.js example reads a pre-encoded Ogg/Opus file to keep the code short. If you need to encode from WAV at runtime, use ffmpeg as a subprocess or the @discordjs/opus package to encode PCM frames, then wrap them in Ogg pages (see the Python example for the page structure).