feat: enable continue_conversation for Voice PE follow-up dialog

When the assistant's response ends with a question mark or contains
common follow-up patterns (EN/DE), set continue_conversation=True
on the ConversationResult. This tells Voice PE and other HA voice
satellites to automatically re-listen after the response finishes
playing, enabling natural back-and-forth dialog without requiring
the wake word between turns.

Fixes #7
This commit is contained in:
Jarvis (OpenClaw)
2026-03-26 21:27:44 +00:00
parent 95bfe5e214
commit 2fe9e6d6c0
@@ -8,6 +8,7 @@ from __future__ import annotations
from datetime import datetime, timezone from datetime import datetime, timezone
import logging import logging
import re
from typing import Any from typing import Any
from homeassistant.components import conversation from homeassistant.components import conversation
@@ -200,6 +201,7 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
return conversation.ConversationResult( return conversation.ConversationResult(
response=intent_response, response=intent_response,
conversation_id=conversation_id, conversation_id=conversation_id,
continue_conversation=self._should_continue(full_response),
) )
def _resolve_conversation_id(self, user_input: conversation.ConversationInput) -> str: def _resolve_conversation_id(self, user_input: conversation.ConversationInput) -> str:
@@ -314,6 +316,53 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
return None return None
@staticmethod
def _should_continue(response: str) -> bool:
"""Determine if the conversation should continue after this response.
Returns True when the assistant's reply ends with a question or
an explicit prompt for follow-up, so that Voice PE and other
satellites automatically re-listen without requiring a wake word.
The heuristic checks for:
- Trailing question marks (including after closing quotes/parens)
- Common conversational follow-up patterns in English and German
"""
if not response:
return False
text = response.strip()
# Check if the response ends with a question mark
# (allow trailing punctuation like quotes, parens, or emoji)
if re.search(r"\?\s*[\"'""»)\]]*\s*$", text):
return True
# Common follow-up patterns (EN + DE)
lower = text.lower()
follow_up_patterns = (
"what do you think",
"would you like",
"do you want",
"shall i",
"should i",
"can i help",
"anything else",
"let me know",
"was meinst du",
"möchtest du",
"willst du",
"soll ich",
"kann ich",
"noch etwas",
"sonst noch",
)
for pattern in follow_up_patterns:
if pattern in lower:
return True
return False
def _error_result( def _error_result(
self, self,
user_input: conversation.ConversationInput, user_input: conversation.ConversationInput,