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

110 lines
4.9 KiB
Markdown

---
type: reference
title: dankvoice
description: Voice output ships as the dank/dankvoice package; this page keeps only the fleet integration facts and the cutover procedure.
tags:
- omp
- extension
- tts
- voice
- frank-tts
- dankclaw
verified: 2026-10-19
timestamp: 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](/core/index.md):
**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](/core/index.md) — the live harness configuration.
* [Handy](/tools/handy.md) — offline speech-to-text, the input half of voice.