Overview
OpenHome provides four methods for capturing user input:
user_response() - Wait for next input
wait_for_complete_transcription() - Wait for complete utterance
run_io_loop() - Speak + listen combined
run_confirmation_loop() - Yes/no confirmation
All methods return the transcribed user input as a string.
user_response()
Waits for the user’s next spoken or typed input and returns it as a string.
Signature
await self .capability_worker.user_response() -> str
Returns
The transcribed user input. May be empty if transcription fails.
Examples
Basic Usage
Input Validation
Loop Pattern
Exit Detection
user_input = await self .capability_worker.user_response()
if user_input:
self .worker.editor_logging_handler.info( f "User said: { user_input } " )
Best Practices
Always check for empty strings. Transcription can fail or return empty results.
# ✅ Good
user_input = await self .capability_worker.user_response()
if not user_input:
continue # Skip empty input
# ❌ Bad
user_input = await self .capability_worker.user_response()
process(user_input) # May crash on empty string
wait_for_complete_transcription()
Waits until the user has completely finished speaking before returning. Use when you need the full utterance without premature cutoff.
Signature
await self .capability_worker.wait_for_complete_transcription() -> str
Returns
The complete transcribed input after the user finishes speaking
When to Use
Use Case Example Long-form input Dictation, descriptions, stories Addresses Street addresses with multiple parts Lists ”Add apples, oranges, and bananas” Numbers Phone numbers, credit cards
Examples
Dictation
Voice Note Recording
Story Collection
await self .capability_worker.speak(
"Tell me your full address. I'll wait until you finish."
)
address = await self .capability_worker.wait_for_complete_transcription()
self .worker.editor_logging_handler.info( f "Address: { address } " )
Comparison with user_response()
Method Timing Use Case user_response()Returns on short pause Quick back-and-forth, single words/phrases wait_for_complete_transcription()Returns after full utterance Long input, addresses, dictation
run_io_loop()
Speaks the text, then waits for a response. A convenience wrapper around speak() + user_response().
Signature
await self .capability_worker.run_io_loop(text: str ) -> str
The text to speak before listening
Returns
The user’s reply after the prompt
Examples
Simple Question
Data Collection
Sequential Flow
Error Recovery
name = await self .capability_worker.run_io_loop( "What's your name?" )
await self .capability_worker.speak( f "Nice to meet you, { name } !" )
When to Use
✅ Quick question-answer pairs
✅ Data collection forms
✅ Simple prompts needing immediate response
✅ When you always speak before listening
Use run_io_loop() instead of manually calling speak() then user_response() - it’s cleaner and less error-prone.
run_confirmation_loop()
Asks a yes/no question and loops until the user clearly says yes or no. Returns a boolean.
Signature
await self .capability_worker.run_confirmation_loop(text: str ) -> bool
The yes/no question to ask. The system automatically appends “Please respond with ‘yes’ or ‘no’.”
Returns
True if user confirms, False if user declines
Examples
Basic Confirmation
Multiple Confirmations
Destructive Action Guard
Onboarding
confirmed = await self .capability_worker.run_confirmation_loop(
"Should I send this email?"
)
if confirmed:
send_email()
await self .capability_worker.speak( "Email sent!" )
else :
await self .capability_worker.speak( "Okay, I won't send it." )
Behavior
Automatically loops until it gets a clear yes/no
Accepts variations: “yeah”, “yep”, “nope”, “nah”, etc.
Handles ambiguous responses by re-asking
The method automatically appends “Please respond with ‘yes’ or ‘no’” to your prompt, so you don’t need to include that in your text.
Common Patterns
Loop with Exit Detection
EXIT_WORDS = { "stop" , "exit" , "quit" , "done" , "cancel" }
await self .capability_worker.speak( "Ask me anything. Say stop when done." )
while True :
user_input = await self .capability_worker.user_response()
if not user_input:
continue
if any (word in user_input.lower() for word in EXIT_WORDS ):
await self .capability_worker.speak( "Goodbye!" )
break
# Process input
response = self .capability_worker.text_to_text_response(user_input)
await self .capability_worker.speak(response)
self .capability_worker.resume_normal_flow()
async def collect_user_info ( self ):
"""Collect user information step by step."""
name = await self .capability_worker.run_io_loop(
"What's your full name?"
)
email = await self .capability_worker.run_io_loop(
"What's your email?"
)
phone = await self .capability_worker.run_io_loop(
"What's your phone number?"
)
# Confirm all data
summary = f "Name: { name } , Email: { email } , Phone: { phone } "
confirmed = await self .capability_worker.run_confirmation_loop(
f "I have { summary } . Is this correct?"
)
if confirmed:
return { "name" : name, "email" : email, "phone" : phone}
else :
await self .capability_worker.speak( "Let's start over." )
return await self .collect_user_info() # Recursive retry
Retry on Empty
async def get_valid_input ( self , prompt : str , max_retries : int = 3 ) -> str :
"""Get user input with retries on empty response."""
for attempt in range (max_retries):
user_input = await self .capability_worker.run_io_loop(prompt)
if user_input and len (user_input) > 0 :
return user_input
if attempt < max_retries - 1 :
await self .capability_worker.speak(
"Sorry, I didn't catch that. Let's try again."
)
await self .capability_worker.speak(
"I'm having trouble hearing you. Let's try again later."
)
return None
Best Practices
# ✅ Good
user_input = await self .capability_worker.user_response()
if not user_input:
continue
# ❌ Bad
user_input = await self .capability_worker.user_response()
result = process(user_input) # May crash
Use run_io_loop() for Simple Prompts
# ✅ Good
name = await self .capability_worker.run_io_loop( "What's your name?" )
# ❌ Verbose
await self .capability_worker.speak( "What's your name?" )
name = await self .capability_worker.user_response()
Provide Exit Keywords
# ✅ Good
await self .capability_worker.speak(
"Let's chat. Say 'stop' when you're done."
)
# ❌ Bad - user doesn't know how to exit
await self .capability_worker.speak( "Let's chat." )
Speaking Combine with speak() for two-way conversation
LLM Process user input with text_to_text_response()
Flow Control Use resume_normal_flow() after input loops