Problem
I wanted to experiment with the LiveKit SDKs and experience writing my own voice agent, and on-call work is a good test: ask “is anything broken?” and have the agent check the real servers instead of reciting a status from memory, then page me only when I confirmed it out loud.
What I built
An on-call voice agent built on the LiveKit Node.js Agents SDK. You talk to it in the browser over WebRTC, and the hosted LiveKit Meet client is the frontend, so there is no custom web app. A browser joins with a token that dispatches the on-call worker.
checkServersprobes every target inHEALTH_TARGETSin parallel with a 3-second timeout and answers with real counts, e.g. “2 of 3 healthy. Problems: database responded 503.”sendAlertwrites the alert, reads it back with its level, and only posts to Shion after a spoken yes. A failed page is reported as a failure, never as “probably sent”.- Self-hosted with Docker Compose on a DigitalOcean droplet, AICGEN00, that only makes outbound connections.
- The image runs on the same droplet as Shion, with a memory cap and
restart: unless-stopped. - LiveKit simulation scenarios run in CI on merges to
mainand on demand.
Results
- Cut idle memory from about 805 MiB to about 515 MiB, based on measured usage.
- Picked models for cost, at roughly $0.006 per minute, against $2.50 of inference credit.
- Finished four scope items end to end, and cut a SIP phone number and a demo recording.
Stack
TypeScript, Node.js, the LiveKit Agents SDK, LiveKit Cloud with Deepgram Nova-3 for speech-to-text, GPT-4.1 mini for the LLM and Rime Mist v3 for text-to-speech, Docker Compose and DigitalOcean.