Skip to content

Configuration Reference

The bridge is configured entirely from environment variables. The package ships a fully commented .env.example. Only two variables are required.

EnvMeaning
WORKER_SHARED_SECRETThe shared secret from StandIn pairing. Must equal what StandIn holds, or the HMAC upgrade is rejected with 401.
OPENAI_API_KEYServer-side OpenAI key. Opens Realtime sessions and calls the TTS endpoint. Never sent to the Teams side.
EnvDefaultMeaning
OPENAI_REALTIME_MODELgpt-realtimeThe Realtime model each per-call session runs.
OPENAI_VOICEunset (model default)Output voice (e.g. marin, cedar, alloy).
OPENAI_INSTRUCTIONSa built-in defaultBase system instructions. The bridge appends per-call caller context (name, tenant, direction) and tool guidance.
OPENAI_FIRST_MESSAGEunsetDeterministic opening line the agent speaks as its first response.
OPENAI_VADserver_vadTurn detection: server_vad (volume-based) or semantic_vad (the model decides when the turn is over). Anything else fails startup.
OPENAI_TRANSCRIPTION_MODELunsetInput-transcription model (e.g. gpt-4o-mini-transcribe). Required for user-side transcript logging.
OPENAI_TTS_VOICEunsetEnables the deterministic governor goodbye (exact text via the standalone TTS endpoint). Without it, the goodbye is delegated to the agent.
OPENAI_TTS_MODELgpt-4o-mini-ttsTTS model for the goodbye line.
OPENAI_HOSTapi.openai.comRestricted to *.openai.com.
OPENAI_HOST_ALLOW_ANYunsetSet to true only to point OPENAI_HOST at a deliberate trusted proxy/test host.
OPENAI_MCP_SERVERSunsetJSON array of remote MCP tool entries ({server_label, server_url, allowed_tools?, authorization?, ...}) the Realtime API executes server-side. server_url must be https; require_approval defaults to "never". See Extending the Agent’s Tools.
EnvDefaultMeaning
MAX_CALL_MINUTES0 (off)Bridge-side hard cap per call, in minutes (fractional allowed). Keep it below 60: the Realtime API caps a session at 60 minutes server-side, and a call reaching that ceiling drops abruptly with agent-disconnected instead of a goodbye. The bridge warns at startup when this governor would not fire first.
GOODBYE_TEXTa default lineThe goodbye the bridge-side governor speaks.
GOODBYE_GRACE_MS8000How long to let the goodbye play out before ending the call when its duration is unknown (agent-said fallback). Always hard-bounded.
EnvDefaultMeaning
VISION_API_URLunsetAn OpenAI-compatible chat-completions endpoint with image input. Set it to enable path-2 vision (describe-then-answer). Validated at startup: must be a well-formed http(s) URL with no embedded credentials; a private/loopback IP is allowed (local Ollama/vLLM) but logged as a warning.
VISION_API_KEYunsetBearer key for the vision endpoint (local endpoints may not need one).
VISION_MODELunsetVision model name (required when VISION_API_URL is set).
EnvDefaultMeaning
PORT8080TCP port the bridge listens on.
BIND0.0.0.0Bind address.
TLS_CERT_PATH / TLS_KEY_PATHunsetPEM cert/key for native TLS (wss://). Without both, the bridge serves plain WS and MUST be fronted by a TLS terminator.
HMAC_FRESHNESS_MS60000Allowed clock skew for the HMAC timestamp.
MAX_CONNECTIONS0 (= 64)Max concurrent connections.
MAX_CONNECTIONS_PER_IP0 (= MAX_CONNECTIONS)Per-IP cap. Defaults to the total cap (effectively off) because StandIn dials from a small set of IPs; set explicitly (with TRUST_PROXY_XFF=true behind a proxy you control) for a real limit.
TRUST_PROXY_XFFfalseKey the per-IP cap on the first X-Forwarded-For hop. Only behind a proxy you control.
PRE_START_TIMEOUT_MS0 (= 10000)Drop a connection that authenticates but never sends session.start.
WORKER_IDLE_TIMEOUT_MS0 (= 90000)Dead-peer window: end the call after this long without any worker message (the worker heartbeats every 30 s). Frees the call id for reconnect and closes the billed Realtime session.
LOG_TRANSCRIPTSfalseLog transcripts (still gated on Teams recording.status == "active"; user turns additionally need OPENAI_TRANSCRIPTION_MODEL).
LOG_LEVELinfodebug | info | warn | error. An invalid value falls back to info.

The bridge also exposes GET /metrics (Prometheus text format, no auth): calls total/active, call seconds, upgrade rejections by cause, frames relayed each way, backpressure drops, and OpenAI connect failures. Like /healthz it is served on the same port - keep the port private to your network or scrape through your ingress.

Audio formats are not configurable: the wire is PCM 16 kHz by contract, and the session is pinned to PCM 24 kHz (the only rate the Realtime API supports); the bridge resamples between them internally.