Deploy on Cloudflare Workers
Cloudflare Workers is a first-party runtime for Syrinx, not an afterthought — the same engine that runs on Node runs on the edge via @kuralle-syrinx/cf-agents’ withVoice(Agent). Each conversation is one hibernatable Durable Object; provider sockets dial out through the Workers fetch-upgrade path.
Add withVoice to an Agent
Section titled “Add withVoice to an Agent”import { Agent, routeAgentRequest } from 'agents';import { withVoice } from '@kuralle-syrinx/cf-agents';import { DeepgramSTTPlugin } from '@kuralle-syrinx/deepgram';import { CartesiaTTSPlugin } from '@kuralle-syrinx/cartesia';import { createWorkersSocket } from '@kuralle-syrinx/ws/workers';
export class VoiceConversation extends withVoice<Env, typeof Agent<Env>>(Agent<Env>, { pipeline: { kind: 'cascaded', stt: (env) => ({ plugin: new DeepgramSTTPlugin(createWorkersSocket), config: { api_key: env.DEEPGRAM_API_KEY, model: 'nova-3', sample_rate: 16000 }, }), tts: (env) => ({ plugin: new CartesiaTTSPlugin(createWorkersSocket), config: { api_key: env.CARTESIA_API_KEY, voice_id: env.CARTESIA_VOICE_ID }, }), }, reasoner: (env) => yourReasoner(env),}) {}
export default { fetch: (request: Request, env: Env) => routeAgentRequest(request, env).then((r) => r ?? new Response('Not found', { status: 404 })),};agents is a peer dependency — install it alongside @kuralle-syrinx/cf-agents. withVoice also accepts a realtime pipeline (kind: "realtime"); see Realtime providers.
Deploy
Section titled “Deploy”npx wrangler deploy
npx wrangler secret put DEEPGRAM_API_KEYnpx wrangler secret put OPENAI_API_KEYnpx wrangler secret put CARTESIA_API_KEYOne Durable Object per transport
Section titled “One Durable Object per transport”The reference Worker (packages/server-workers/src/worker.ts) binds one withVoice(Agent, {...}) Durable Object per transport:
| Route | Durable Object | Transport |
|---|---|---|
wss://<worker>/ws | VoiceConversation | Browser / edge client, Syrinx’s JSON+envelope protocol |
/twilio | TwilioVoiceConversation | Twilio Media Streams, μ-law 8 kHz |
/telnyx | TelnyxVoiceConversation | Telnyx Media Streaming — see the [Preview] callout below |
Wire up telephony webhooks
Section titled “Wire up telephony webhooks”- Twilio — point the phone number’s “A call comes in” webhook at
POST /incoming-call. It returns<Connect><Stream>TwiML pointed at/twilio. - Telnyx — point a Call Control application at
/telnyx-stream-start. It builds the TeXML<Stream>(or Call Controlstreaming_start) payload for/telnyx.
See Twilio and Telnyx for the full setup.
Other endpoints
Section titled “Other endpoints”GET /health— liveness check.GET /recordings?sessionId=<id>— fetch a per-call stereoconversation.wavwhen aRECORDINGSR2 bucket is bound.
Durable conversation history
Section titled “Durable conversation history”By default, conversation history (and a realtime provider’s resume handle) persists in the Agent’s own SQLite storage and survives Durable Object eviction — a call that gets hibernated mid-conversation picks back up with full context. Set durableHistory: false on withVoice to opt out.