Switchbordswitchbord
v0.15.39

Audio transcription re-landed + outbox hardening

Voice-message transcription is back, with the underlying ESM fix that caused the v0.15.38 rollback. Worker outbox now self-heals from crashed leases and no longer starves operator sends behind webhook backlogs.

Added


  • Audio transcription runtime (re-land): inbound WhatsApp voice messages are transcribed in two passes — Groq Whisper or OpenRouter Whisper for the raw transcript, then a correction LLM (default Gemini Flash via OpenRouter) — and the result replaces the [audio message] placeholder in the inbox. Configuration lives at /settings/integrations/ai/groq; feature is opt-in per workspace.
  • Outbox lease sweeper: a new release_stuck_outbox_jobs function runs every 5 minutes on the worker and returns orphaned running jobs (10+ minutes with no heartbeat) to pending or failed. Messages no longer disappear silently when a worker crashes mid-dispatch.
  • Outbox priority tiers: OPERATOR_DISPATCH is now the same tier as WEBHOOK_INGEST (both priority 10). A backlogged webhook queue can no longer starve operator outbound messages. Template/campaign sends stay at a lower tier so real-time conversations always interleave ahead of bulk blasts.

Fixed


  • Worker boot regression (production outage, 2026-05-05 12:53–13:50 UTC): the Railway worker crashed at boot after v0.15.38 shipped, because a top-level static import of @repo/storage hit Node's ESM loader in a CJS-marked package. packages/storage/package.json now declares "type": "module" like the rest of the workspace. A new subprocess-based boot smoke test exercises the real loader Railway uses, catching this regression class at CI instead of at deploy.

Under the hood


  • @repo/storage is now an explicit workspace dependency of apps/worker and apps/api, so any future top-level import from the database-adapter tree finds the package directly.