fix(agent): make spoken narration strictly opt-in#3500
Conversation
Spoken narration defaulted on for all cloud runs via resolveSpokenNarration falling back to isCloudRun(meta). That loaded the `speak` tool and its prompt instructions — and prompted the agent to call it — on headless runs (Slack threads, Signals scouts) where nothing can play audio, costing tokens with no listener and regardless of the feature flag, user setting, or ElevenLabs key. Make narration strictly opt-in: resolveSpokenNarration now returns true only when a caller explicitly sets spokenNarration. The desktop is the only client that can play audio and knows the flag/setting/key, so it computes that boolean and passes it; everything else stays silent and never loads the tool. Also require an ElevenLabs key alongside the setting on the desktop start/reconnect paths, and refresh the now-stale comments. Generated-By: PostHog Code Task-Id: 7a65b8a4-b69d-472f-9753-67d59715e332
|
😎 Merged successfully - details. |
|
React Doctor found no issues in the changed files. 🎉 Reviewed by React Doctor for commit |
Generated-By: PostHog Code Task-Id: ac30fada-8c29-4973-a253-08d70be31be6
|
Reviews (1): Last reviewed commit: "fix(agent): allow system voice narration..." | Re-trigger Greptile |
pauldambra
left a comment
There was a problem hiding this comment.
Note
🤖 Automated comment by QA Swarm — not written by a human
QA Swarm review complete. See inline comments.
|
Note 🤖 Automated comment by QA Swarm — not written by a human Multi-perspective review: paul-reviewer, xp-reviewer, security-audit (qa-team unavailable) Verdict:
|
| Reviewer | Assessment |
|---|---|
| 👤 paul | Cloud narration propagation and tests need fixes. |
| 📐 xp | Design is simple, but the existing focused test suite breaks. |
| 🛡 security-audit | No exploitable vulnerabilities found. |
Automated by QA Swarm — not a human review
Generated-By: PostHog Code Task-Id: ac30fada-8c29-4973-a253-08d70be31be6
|
Note 🤖 Automated comment by QA Swarm — not written by a human Round 2 verdict:
|
Generated-By: PostHog Code Task-Id: ac30fada-8c29-4973-a253-08d70be31be6
| meta: SpokenNarrationSource | undefined, | ||
| ): boolean { | ||
| return meta?.spokenNarration ?? isCloudRun(meta); | ||
| return meta?.spokenNarration === true; |
There was a problem hiding this comment.
Note
🤖 Automated comment by QA Swarm — not written by a human
[convergent: paul-reviewer + xp-reviewer] 🟠 HIGH
Strict opt-in currently makes narration local-only because interactive cloud runs have no backend-supported way to carry the desktop flag + user opt-in decision. Supporting cloud narration requires a coordinated server contract or another explicit transport; otherwise this PR intentionally leaves cloud runs silent.
|
Note 🤖 Automated comment by QA Swarm — not written by a human Round 3 verdict: 💬 APPROVE WITH A DEFERRED PRODUCT DECISIONThe local implementation and tests are clean. Interactive cloud narration remains disabled because the current backend has no supported field for the explicit desktop opt-in; enabling it requires coordinated backend work. Automated by QA Swarm — not a human review |
There was a problem hiding this comment.
Clean behavioral fix making spoken narration strictly opt-in. The logic is consistent end-to-end: resolver simplified, settings wiring renamed correctly, feature-flag gate added in the host layer, and tests updated. The unresolved bot comment at current head describes the intentional design decision (cloud runs stay silent) rather than a blocking concern.
|
/trunk merge |
|
Could not verify team-posthog-code membership (GitHub API error). Auto-release is limited to Team PostHog Code members, so this will ship with the next scheduled release instead. |
Problem
The
speak(spoken narration) tool was running on headless cloud runs — Slack threads and Signals scouts — where nothing can play audio, quietly costing tokens with no listener.Raised in #team-max-ai. The gating that was believed to protect this (feature flag + user setting + ElevenLabs key) only governs playback on the desktop client. On the agent side,
resolveSpokenNarrationfell back toisCloudRun(meta), so every cloud run defaulted narration on when no explicit setting was passed. That loaded thespeaktool schema and appended its prompt instructions (which tell the agent to "never end a turn silently"), so the model actively emittedspeakcalls on runs no one was listening to — independent of the flag, setting, or key.Changes
Make narration strictly opt-in:
resolveSpokenNarrationnow returns true only when a caller explicitly setsspokenNarration. The cloud/sandbox default-on is gone, so headless runs never load the tool or its instructions and never pay the token cost.Why: narration should only run where someone can actually hear it and has explicitly turned it on; it should never silently burn tokens on automated runs.
Note: requiring an ElevenLabs key means the macOS
sayfallback no longer triggers narration on its own — intentional per the requested gating, but flagging in case we want the fallback to count.How did you test this?
pnpm --filter @posthog/agent exec vitest runonsession-meta.test.ts(rewritten for opt-in semantics),speak.test.ts, andinstructions.test.ts— all pass.pnpm --filter @posthog/{agent,core,workspace-server} typecheck— clean.biome linton all touched files — clean.Automatic notifications
Created with PostHog from a Slack thread