Skip to main content

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

response
string
The transcribed user input. May be empty if transcription fails.

Examples

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

response
string
The complete transcribed input after the user finishes speaking

When to Use

Use CaseExample
Long-form inputDictation, descriptions, stories
AddressesStreet addresses with multiple parts
Lists”Add apples, oranges, and bananas”
NumbersPhone numbers, credit cards

Examples

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()

MethodTimingUse Case
user_response()Returns on short pauseQuick back-and-forth, single words/phrases
wait_for_complete_transcription()Returns after full utteranceLong 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
text
string
required
The text to speak before listening

Returns

response
string
The user’s reply after the prompt

Examples

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
text
string
required
The yes/no question to ask. The system automatically appends “Please respond with ‘yes’ or ‘no’.”

Returns

confirmed
boolean
True if user confirms, False if user declines

Examples

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()

Multi-Step Form

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

Always Check for Empty Input

# ✅ 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

Build docs developers (and LLMs) love