Web SDK
@glytos/web puts a conversation with your agent in your page - voice over
WebRTC, or text as a chat. Both are in the one package; use whichever you need.
It handles the microphone, the connection and the transcript stream.
npm install @glytos/webThe two-step flow
The SDK never sees your API key. Your server mints a short-lived web-call token; the page uses it.
On your server, mint a token naming the agent, and return it to your page:
import { Glytos } from '@glytos/node';
const glytos = new Glytos({ apiKey: process.env.GLYTOS_API_KEY! });
const { token, ws_url } = await glytos.calls.webToken({ workflow_uuid: agentUuid });
// return { token, ws_url } to your pageThis is POST /api/v1/calls/web-token with either workflow_uuid (a saved agent) or
agent (an inline agent definition) - exactly one of the two. The response carries
token, ws_url, workflow_uuid and expires_in, the token's lifetime in seconds.
The token is short-lived, so mint it when the visitor starts a call rather than when
the page loads. Minting one needs an API key with the workflow:run permission.
In the page, start the call with it:
import { GlytosWebCall } from '@glytos/web';
const call = new GlytosWebCall({ token, wsUrl: ws_url });
call.on('status', status => console.log(status));
call.on('transcript', message => console.log(message.role, message.text));
await call.start();Mint the token on your server. Putting an API key in the page hands anyone who views source the ability to spend your credit.
Ending a call
call.stop();Connectivity
The audio travels over WebRTC. By default the SDK gives the browser a single public
STUN server (stun:stun.l.google.com:19302) and no TURN server. That is enough on most
networks, but a browser behind a symmetric NAT or carrier-grade NAT (common on mobile
data and some corporate networks) cannot connect without a TURN relay. Pass your own
servers with iceServers:
const call = new GlytosWebCall({
token,
wsUrl: ws_url,
iceServers: [
{ urls: 'stun:stun.l.google.com:19302' },
{ urls: 'turn:turn.example.com:3478', username: 'user', credential: 'secret' },
],
});iceServers replaces the default rather than adding to it, so include a STUN server
too.
Chat
The same package embeds a text chat. Mint a short-lived chat token on your server
(POST /api/v1/chat/token with the agent's workflow_uuid) and hand it to the page:
import { GlytosChat } from '@glytos/web';
const chat = new GlytosChat({ token });
chat.on('token', t => append(t.delta)); // streamed deltas
chat.on('message', m => render(m)); // a complete message
chat.on('error', e => console.error(e));
await chat.start(); // opens the conversation, emits the greeting
await chat.stream('Hello!'); // streamed reply
await chat.send('And this?'); // buffered replystart, send and stream do not reject when a turn fails: they emit an error
event instead, so listen for it. uploadFile is the exception and throws.
Chat requests go to https://api.glytos.com by default. To target another host, pass
apiBase as the host root only - for example https://api.glytos.com - because the SDK
appends /api/v1/... itself. That differs from the server SDKs, whose baseUrl
includes /api/v1.
Attachments, images and resuming
// Attach a file to this conversation only (it does not join the knowledge base)
await chat.uploadFile(fileFromInput, fileFromInput.name);
// Send an image with a turn; a text-only model ignores it
await chat.send('What is on this label?', { images: [dataUri] });
// Persist the conversation id and resume it later
localStorage.setItem('glytos_chat', chat.sessionId ?? '');
const saved = localStorage.getItem('glytos_chat');
const resumed = new GlytosChat({ token, sessionUuid: saved || undefined });
await resumed.send('Where were we?'); // continues the saved conversationTo resume, go straight to send or stream. Do not call start() on a resumed chat:
start() always opens a new conversation and replaces the saved id. Chat tokens expire
too, so a conversation resumed later needs a freshly minted token for the same agent.
Per-turn instructions are deliberately not available here: this runs in a visitor's browser, so such a field would let anyone rewrite your agent's behaviour on your own site. Use a server SDK for that - see Chat.
Requirements
A voice call needs the page served over HTTPS - browsers only grant microphone access on a secure origin - and the user must grant microphone permission when prompted. Chat has neither requirement.