Files
command-center/omp-docs/core/dankvoice.md
T
Frank fd6a07bb58 docs: auto-speak narrates every turn, not only the final answer (Refs #36)
The Limits bullet still described the pre-fix behaviour ("thinking and the
final message only"), which dank/dankvoice#3 just retired: narration rides
`turn_end`, so the assistant's prose and thinking are spoken while the agent
works. Records the two rules an operator needs when audio seems missing —
arming is read at startup only, and a turn landing during playback is dropped
rather than queued — plus where the design rationale lives.

kb-lint 0 violations, index-coverage 0 issues.
2026-10-19 13:31:01 -07:00

4.9 KiB

type, title, description, tags, verified, timestamp
type title description tags verified timestamp
reference dankvoice Voice output ships as the dank/dankvoice package; this page keeps only the fleet integration facts and the cutover procedure.
omp
extension
tts
voice
frank-tts
dankclaw
2026-10-19 2026-10-19

dankvoice

Voice output lives in the dank/dankvoice package: pi install git:http://192.168.0.143:3000/dank/dankvoice.git. This page owns only fleet integration and the cutover. The package README (http://192.168.0.143:3000/dank/dankvoice) owns the /say command reference, the settings/env knob list, the segmentation state machine, the enhancer port, and mood control — never duplicate those facts here.

Fleet wiring

  • TTS endpoint — resolved from the provider block whose model row carries api: openai-speech in agent/models.yml: frank-tts on Dankclaw :7772. LAN-only — no Caddy vhost fronts it.
  • Narration humanizer — the harness @tiny role (modelRoles.tiny in agent/config.yml), on this fleet frank-zealot (Dankclaw :7771).
  • Hybrid-endpoint trap (load-bearing) — a raw fetch to a thinking-by-default model spends the token budget on reasoning_content and answers content: "". The package pins chat_template_kwargs: { enable_thinking: false } on the rewrite call; do not remove it. On a hybrid endpoint, empty content beside non-empty reasoning_content means the flag was ignored — that is a failed rewrite (fall back to the mechanical text), never the legitimate "nothing to say".
  • Voice contract — omitting voice is legal: frank-tts fills its DEFAULT_VOICE (2026-10-18 voice-pack work). GET {base}/v1/audio/voices answers a bare JSON array; an unknown voice answers 400 with available_voices, which the package uses as roster fallback. On this shim GET /v1/voices and GET /v1/models are 404.

Cutover (Refs #34)

The agent/extensions/dankvoice.ts drop-in and its 26-test bats suite are retired here (the package suite is a strict superset; test names ported 1:1). Per box:

  1. pi install git:http://192.168.0.143:3000/dank/dankvoice.git
  2. /say status, then "Speak a test phrase" from the /say menu — the audible proof a silent session needs.
  3. Pull main (the drop-in disappears with it) and restart the session.

Menu choices survive the cutover: both transports persist to the same gitignored settings file, ~/.omp/cache/dankvoice.json (DANKVOICE_CONFIG relocates it).

Why not the built-in vocalizer

The harness speak-aloud path (speech.enabled / speech.voice, omp say) synthesizes with bundled Kokoro ONNX against a compile-time voice enum — cloned voices can never reach it, and no setting routes it to frank-tts. dankvoice is a second transport beside it, not a patch: Kokoro stays for quick local speech, the package carries cloned-voice narration. The tts tool / xd://tts device reach frank-tts too, but produce files, not audio playback.

Arming auto-speak

Arming is session-scoped by design: /say on arms the running session and is deliberately never persisted. A session that starts silent is a config state, not a fault — set "auto": true in ~/.omp/cache/dankvoice.json (this fleet does) or export DANKVOICE_AUTO=1 to start armed. Editing the settings file mid-session does nothing; the plugin reads it at startup.

Two checks prove the chain, in order: /say status must report auto-speak on with a real endpoint (not NO ENDPOINT), and pgrep -a pw-play during a turn must show one player per spoken segment, --target set to the saved sink. Thinking narration rides the same arming (thinking: true).

Limits

  • Auto-speak narrates each turn — the assistant's prose and thinking while the agent is still working — plus the settled final answer, spoken once. A turn that lands while audio is still playing is dropped, not queued or interrupting; tool-only turns stay silent; print/json modes never speak, so benches stay quiet. Narration goes through the humanizer, so it lags its turn by a rewrite round trip; /say humanize off removes the lag.
  • Arming is read at startup only — see Arming auto-speak above. A session that never speaks is unarmed, not broken; /say on before debugging.
  • frank-tts deployment, voice packs and the registry are owned by the serverAppConfigs repo (serverAppConfigs-docs/Dankclaw/Frank TTS.md).

Citations

  • Package repo dank/dankvoice (README, docs/decisions/) — behaviour and knob truth. docs/decisions/2026-10-19-turn-narration.md records why narration rides turn_end and not only agent_end.
  • Gitea issues #21, #23, #27, #32 (drop-in history) and #34 (this cutover) on dank/command-center.
  • Live endpoint probes 2026-10-18/19 documented in those issues.

See Also

  • Core Documentation — the live harness configuration.
  • Handy — offline speech-to-text, the input half of voice.