3.6 KiB
name, description
| name | description |
|---|---|
| dankvoice-silence-triage | Triage silent or late dankvoice auto-speak on the fleet: arming key, /say grammar, endpoint/sink, event granularity, humanizer latency, plus the black-box bats driver. |
Triage "dankvoice is silent" on the fleet
Symptom that recurs: auto-speak only speaks when /say <text> is typed
explicitly. Work the gates in this order; each has an objective check.
- Armed?
cat ~/.omp/cache/dankvoice.json | jq .auto— must betrue(orDANKVOICE_AUTO=1). Arming is read at startup only and/say onnever persists, so a session started before the key was added is silent even though fresh sessions work./say startis not a subcommand: unknown arguments are spoken verbatim (it read out the word "start")./say onis the verb;/say statusmust printauto-speak on. - Endpoint + sink?
/say statusmust show a real endpoint (notNO ENDPOINT) and the saved sink must exist:pw-dump | grep -o 'alsa_output\.[^"]*' | sort -u. - Did it synthesize?
pgrep -a pw-playduring a turn: one process per segment,--target <sink>, wav under/tmp/dankvoice-*/say-<epochms>.wav. One temp directory per utterance chain — count dirs to count utterances, pids to count segments. - Event granularity (the structural cause).
agent_endfires once per prompt when the loop settles and is skipped when the harness maps a non-terminal settle (willContinue) — long runs with background jobs or subagents therefore narrate nothing. Mid-run narration needsturn_end(fires per assistant message + tool results). Verify delivery, don't infer it: skillomp-extension-event-probe. - Latency is not silence. Narration passes through the humanizer
(frank-zealot) before synthesis, so an utterance lands several seconds after
its turn; under endpoint load that stretches to tens of seconds.
/say humanize off= mechanical voice, near-instant. Judge cadence from probe-log timestamps, never from when audio starts.
Design rules the plugin now encodes (dank/dankvoice#2→#3)
- Narrate
turn_endper turn plusagent_endfor the settled answer; dedupe identical text per run (reset onagent_start) so the answer speaks once. - A turn landing while the player is alive is dropped — no queue, no
interrupting; a tool loop would cut every sentence off after a word.
Busy test:
state.child !== undefined && state.child.exitCode === null. - Tool-only turns (no prose, no narration-flagged thinking) stay silent.
print/jsonmodes stay silent, so benches never chatter.- Settings writes must round-trip the file (
{...onDisk, ...owned keys}). Rebuilding from owned keys deleted"auto"on any menu choice and silently un-armed every later session — the classic cause of "it worked yesterday".
Black-box test harness (repo dank/dankvoice)
tests/behavior.bats drives the built artifact through an in-process driver:
const say = DV_EXT(ctx, cfg)[0], handlers via const events = new Map(); const pi = { on: (n,h)=>events.set(n,h) }, then events.get("turn_end")?.({ turnIndex:0, message:{role:"assistant",content:[{type:"text",text:"…"}]}, toolResults:[]}, ctx). Assert on CALL/PLAYS/NOTIFY lines and
SETTINGS <file contents>; stubs are DV_PLAYER_CMD (logs voice+input, honours
DV_HOLD) and DV_REWRITE_URL (404 → falls back to mechanical text). setup()
runs bun run build per test → serialize suites on the shared dist/.
tests/packaging.bats requires dist/ committed (compares to HEAD), so
build → commit → the drift pin goes green.