CedarCopilot wants to merge 2 commits into staging from feat/slack-voice-notes
Live on prod, no production signal yet
Libra has verdicts on 0 of 7 tracked behaviors on prod; 7 are still being checked. Libra checks hourly for 3 days after each deploy.
handleSlackBotInteraction) derived its query from event.text alone, so a voice note (empty text, audio in files) was silently dropped -- no reply, no log. Verified against a real voice note sent during this investigation.files to SlackMessageEvent, and downloads + transcribes the audio (Groq whisper-large-v3-turbo, same model already live in the mail composer's voice-to-draft feature) when text is empty, echoing the transcript before the agent runs.fetchSlackFileBytes (out of slack-files.ts's existing image-download path) and transcribeAudioBuffer (out of the mail composer's tRPC route). Both are now used by two callers instead of one each.files:read scope or a download/transcription failure gets a plain-language reply ("reconnect Slack..." / "mind trying again...") instead of silence.Thermo-review found a real ordering bug before merge: the new branch posted to Slack (the echo, or a failure reply) before the requireExistingBotThread gate ran. A voice note dropped as a reply into any thread Cedar had never spoken in -- not just DMs -- would have gotten an unsolicited Cedar reply, bypassing the exact guard that gate exists to enforce. Fixed by moving the branch to after the gate. Full review in apps/server/docs/slack-voice-notes.md.
pnpm --filter @zero/server run types -- cleanpnpm deps:check -- no violationsfetchSlackFileBytes/transcribeAudioBuffer extractionsfindVoiceNoteFile / transcribeSlackVoiceNote (happy path, missing scope, download failure, missing API key, Groq error, empty transcript)transcribeSlackVoiceNote, then ran the full handleSlackBotInteraction against a synthetic event pointed at the real Cedar Mail DM -- Cedar posted the transcript echo and a live agent reply in Slack. Also incidentally verified the failure path posts a graceful message rather than crashing (surfaced by a misconfigured first test run).apps/server/docs/slack-voice-notes.md -- current state, investigation findings against the real message, proposed changes, phased plan, and post-review implementation notes.
š¤ Generated with Claude Code
https://claude.ai/code/session_01VwETaLnBZrY3bYYTEWMFR3
The PR adds Slack voice-note support by downloading audio attachments, transcribing them through a shared Groq helper, echoing the transcript, and passing it into the existing chat agent. It also extracts shared Slack-file download and transcription code and adds focused tests.
The PR should not merge until oversized downloads are bounded before buffering and credential or download rejections reliably produce the intended Slack failure reply.
The new interaction path can allocate an entire oversized attachment in the shared API process and can silently lose voice-note interactions when credential resolution or Slack downloading rejects outside the transcription catch.
Files Needing Attention: apps/server/src/services/integrations/slack/slack-files.ts, apps/server/src/mastra/routeHandlers/slack/slack-bot-chat.ts, apps/server/src/mastra/routeHandlers/slack/tests/slack-voice-note.test.ts
Libra has not measured any production surfaces for this change yet.