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.
110 lines
4.9 KiB
Markdown
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.
|