Skip to content

[bug] Saying "stop" does nothing — only "stop voice" is a command, and the agent replies "Stopped" anyway #331

Closed

Description

@serge-ivo

What happened

Coder Lead, 2026-08-06 23:51:37. The user said "Stop-stop." — meaning stop.

It was transcribed and sent as a chat message. The agent replied "Got it. Stopped." Nothing
stopped. The mic stayed live, and two phantom turns followed (see #(B), the companion ticket).

Cause: "stop" alone is not an exit phrase

packages/sdk/src/voice/convo.ts:147:

const EXIT_BY_LANG = {
  en: ["exit voice", "exit voice mode", "stop voice", "stop voice mode",
       "leave voice", "text mode", "switch to text", "back to text"],
  …
}

Every English phrase that contains "stop" requires the word "voice" after it. Bare "stop",
"stop stop", "stop listening" match nothing.

There is no vocabulary reason for this: phraseMatchesTranscript already allows a single-word
command when it is the whole utterance — the restriction exists so "don't forget to mute"
stays a message. "Stop-stop." was the whole utterance, so a listed "stop" would have fired
correctly and safely.

Stop-words are not the answer either: they are off unless configured (stripStopWord:394), and a
stop-word ends the turn — it submits the message. It does not stop the session.

The second half: the agent confirmed a stop it cannot perform

"Got it. Stopped."

Voice mode is client state. The agent has no visibility into it and no control over it — it
answered "stop" conversationally, as any assistant would. But the reply reads as confirmation, so
the user reasonably disengaged while the microphone was still open.

That is the same class as #254 and #259: an agent making a confident statement about a capability
it does not have, because nothing told it otherwise. Here the honest reply is "I can't control
the microphone — say 'stop voice' or tap the mode control"
, which requires the prompt to know
voice is active.

Fix

  • Add bare "stop", "stop stop", "stop listening" (and the equivalents in the other nine
    languages already listed) to EXIT_BY_LANG.
  • Consider whether "stop" should mean exit voice or interrupt what is happening — they are
    different. Mid-reply, a user saying "stop" most likely wants the TTS to shut up and the turn
    abandoned, not to leave hands-free entirely. exit may be the wrong verb to bind it to.
  • Teach the agent that voice is active so it stops confirming actions it cannot take. Derived from
    state, not hardcoded prose (Prompt-drift check — three agents in two days told a story about themselves their capabilities contradicted #315).

Verification

  • "Stop." as a whole utterance exits voice; "don't stop now" does not.
  • The agent never claims to have stopped voice.
  • Mid-TTS "stop" silences the reply rather than only unsubscribing from the next one.

Activity

  1. serge-ivo commented on Aug 6, 2026

    @serge-ivo
    ContributorAuthor

    Superseded in part by #333… correction: by #334. The owner has "stop stop" configured as a stop-word, so the real failure was not "stop is not in EXIT_BY_LANG" — it was that normalizeTranscript does not strip hyphens, and Whisper rendered the phrase as "Stop-stop.". See #334 for the measurement.

    What remains valid here: bare "stop" still is not an exit phrase (only "stop voice"), and the agent still replies "Got it. Stopped." about client state it cannot see or control. Both worth fixing — but #334 is the one that explains the intermittency.

  2. serge-ivo commented on Aug 7, 2026

    @serge-ivo
    ContributorAuthor

    Voice half fixed in 3d7e28b; the prompt half is left open below.

    "stop" and "stop stop" are now exit phrases in EXIT_BY_LANG, with equivalents in the other nine languages (停止 / やめて / 그만 / basta / arrête / aufhören / рuko …).

    On whether the bare word is safe: yes, and by construction rather than luck. phraseMatchesTranscript requires a single-word phrase to BE the whole utterance — the rule added when "next agent" fired inside "the next agent in the chain is the builder" — so "don't stop now", "stop the deploy when the tests go green" and "did it stop?" all stay messages. Tests pin those.

    "stop stop" is not redundant with it: it normalises to two words, which the single-word rule can never match, and it is what the reported "Stop-stop." becomes after #334. As a multi-word phrase it can also match inside a longer utterance; a doubled imperative is distinctive enough for that, in the way "next agent" was not.

    "stop listening" deliberately stays a MUTE phrase — it says literally what mute does, exit is checked first and would have stolen it, and silencing the mic is the smaller, recoverable reading.

    On the ticket's second bullet (interrupt vs exit): exit now cancels TTS immediately rather than after awaiting the hands-free teardown, so mid-reply "stop" silences the agent at once instead of talking over the answer to whether anything stopped.

    Left open — the prompt half. "Teach the agent that voice is active so it stops confirming actions it cannot take" belongs in workers/api (#315's lib/prompt-claims.ts is the right machinery: "Got it. Stopped." is a claim that contradicts reality, same class as #254/#259). That was another agent's lane this run, so it is untouched. Suggest tracking it as its own ticket against prompt-claims rather than reopening this one.

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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions