Skip to content

Feed the transcription prompt the proper nouns the platform already knows — tmux targets, repo names, subordinates #372

Closed

Description

@serge-ivo

The platform already knows the words it is mishearing

buildTranscribePrompt(surfaces, extra) (packages/sdk/src/voice/prompt.ts:27) takes an extra
array specifically for "any extra proper nouns, e.g. attached repo names". The one call site
(InstanceDetail.tsx:237) passes:

buildTranscribePrompt(surfaces, instance?.name ? [instance.name] : [])

One string. The parameter's own doc-comment names repo names as the use case and repo names are
not passed.

Meanwhile the proper nouns the user actually says out loud are all sitting in the instance, already
fetched by the page:

source already available as words it would supply
tmux / terminal targets terminal_list_targets — the Tmux tab lists them tmux-operator-runner, platform, session + window names
attached coding repos coding_repos, injected into chat context by agent-think.ts heartfull, platform, owner/repo
indexed repos (Repo Chat) repoMember: keys repo + owner names
subordinate instances the supervision graph the names of agents the user says aloud to delegate
collections list_instance_collections collection names used in commands

Every one is a proper noun, which is exactly the category generic ASR mangles and exactly what a
bias prompt is for.

Why this should land before the user-facing list (#373)

It costs no UI, no settings, no migration, and no user effort — and it fixes the reported case. In
#371 the user said tmux and the browser returned Timo; tmux and every session name were
knowable from a call the agent had already made three times in that same conversation.

Asking a user to type tmux into a settings box to fix a word the platform can already enumerate is
the wrong first move. The manual list (#373) should exist for what cannot be derived — a person's
own name, a product, an initialism — not as the primary mechanism.

Notes for implementation

  • This is the same one-line class of bug as [bug] "Do it" is transcribed "Duet" and "go, send" becomes "context:" — a tmux agent gets no vocabulary bias, and the divergence guard is off below four words #371's root cause. There, CODING_TERMS was skipped
    because the gate asks about surfaces and a tmux agent has surfaces: ["tmux"]. Here, extra is
    under-fed. Both are cases of the prompt builder being given less than the caller already holds.
  • Bound it. The prompt field is finite and dilution degrades bias — cap the derived list (~30
    terms), prefer the most recently used targets/repos, and dedupe against the static term lists so
    platform is not sent twice.
  • Refresh it when it changes. Attaching a repo or creating a tmux target should change the next
    turn's prompt; a value captured once at page load goes stale exactly when the user starts saying
    the new name.
  • Split identifiers. tmux-operator-runner said aloud is three words. Send both the raw token
    and its split form, or the bias helps the written form and not the spoken one.

Related

#371 (the report), #373 (the user-editable list this precedes).

Activity

  1. serge-ivo commented on Aug 7, 2026

    @serge-ivo
    ContributorAuthor

    Fixed in bfbfd29.

    workers/api/src/lib/voice-vocabulary.ts derives, per instance: the display name, the agent's name, attached coding_repos (name + owner/repo + the repo half of it) newest-first, and subordinate instance names from the supervision graph. Capped at 20, deduped, ordered most-relevant-first so the cap truncates the tail.

    Delivered on the voice-settings response, not assembled in the console. That response is already re-fetched on every mic start (getVoiceConfig, background revalidate), so attaching a repo changes the next turn's bias — which is the refresh requirement in the ticket, and better than a value captured at page load. derivedVocabulary is read-only and is dropped by the sanitizer if echoed back through PUT.

    Split identifiers: spokenForm sends both spellings — tmux-operator-runner + tmux operator runner, ProAgentStore/platform + Pro Agent Store platform (camel/Pascal boundaries too). Deduped against the static term lists, so platform and console are not sent twice.

    The entry rule, and what was left out. A term qualifies only if it is both likely to be said aloud and likely to be mis-heard. So excluded, though every one is a column away: clone URLs, workdir paths, branch names, session ids (enumerable, never spoken in that form); collection and file names (said sometimes, but ordinary words far more often — "notes", "leads", "resume" — and biasing an ordinary word bends real speech toward it).

    Not done: tmux/terminal targets, which the ticket lists first. They live on the runner, not in D1, so enumerating them means a relay round trip on the voice-config path — the one path #284 spent effort taking round trips out of. The static TMUX_TERMS list (#371) covers the vocabulary that was actually failing that agent's turns; live target names can follow if they turn out to be the residual failure.

    #332 interaction: every term added here is a proper noun, the exact class that echoes back off a near-silent clip. isTranscribeBiasEcho still catches multi-word echoes only (single words stay unfiltered, or a real "commit" gets swallowed). What makes the trade acceptable is that each multi-token identifier ships its multi-word spoken form beside it, so an echo of either is caught — and that the caps are hard, because a longer list biases worse. A one-word repo or agent name echoed alone remains uncaught; that is the standing price of the bias existing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestvoiceVoice / STT / TTS

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions