Integrate voice input into the TUI and add turn cancellation#236
Merged
Conversation
- TUI: pure-black canvas (all surface fills #0b0e16 -> #000000). - Stream the agent turn-by-step (stream_mode="values") so tool calls, results, and reply text render live instead of all at the end; the approval/interrupt flow is preserved and request_cancel() can break the loop between steps. - Escape interrupts a running turn; Ctrl-C interrupts a running turn or, when idle, quits only on a confirmed double-press (mirrors deepagents-code's action_interrupt / action_quit_or_interrupt). - Voice now drives the TUI: a spoken turn is transcribed, entered into the prompt, and submitted; TTS reads back a code-stripped summary (spoken_summary) instead of the full reply. --no-tui keeps the voice REPL. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FUL1Y7QWgAUDTRdQtK2qCJ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR integrates voice input/output into the code agent TUI, allowing users to speak their requests and hear summaries of replies read back. It also adds turn cancellation (Escape) and a safer quit mechanism (Ctrl-C double-press confirmation).
Key Changes
Voice Integration in TUI
_VoiceIOprotocol to abstract voice session interface (listen/speak)voiceparameter and routes spoken turns into the prompt_capture_voice_turn()to listen for spoken input on a background thread_voice_followup()to read back a spoken summary after each reply_voice_typedflag)Turn Cancellation & Safer Quit
action_interrupt()(Escape key) to cancel a running agent turn without quittingaction_quit_or_interrupt()(Ctrl-C) that interrupts running turns or requires double-press to quit when idle_turn_running()to check if prompt is disabled (turn in flight)_cancel_turn()to set the session's cancel flag cooperatively_quit_pendingflag and_arm_quit_pending()to show "Press Ctrl-C again to quit" hintSession Streaming & Cancellation
_SupportsStreamprotocol to detect agents that support incremental streamingCodeSession.send()to call new_run()method that streams events incrementally_run()checks_cancelflag between steps, allowing cooperative turn interruption_resolve_interrupts()also respects the cancel flag to stop approval loops earlyrequest_cancel()method to set the cancel flag from another threadVoice Readback Improvements
spoken_summary()function to strip code (fenced and inline) from replies before TTSspoken_summary()instead of reading full textUI Polish
#0b0e16to pure black (#000000) for cleaner appearanceTesting
test_code_tui_voice.pycovering voice integration scenariostest_code_tui.pytest_code_agent.pyto verify incremental event emissionspoken_summary()tests intest_code_voice.pyImplementation Details
call_from_thread()is used to safely update UI state from voice worker threadsthreading.Eventchecked at step boundaries, enabling cooperative cancellation without killing threadsinvoke()emit once at the end_quit_pendingflag after 3 secondshttps://claude.ai/code/session_01FUL1Y7QWgAUDTRdQtK2qCJ