Release OpenClaw HA integration 0.1.66

This commit is contained in:
2026-05-06 13:08:57 +02:00
parent 8221098ebc
commit 2a02c18b86
6 changed files with 301 additions and 136 deletions
+31 -11
View File
@@ -41,7 +41,12 @@ from .const import (
from .coordinator import OpenClawCoordinator
from .exposure import apply_context_policy, build_exposed_entities_context
from .helpers import extract_text_recursive
from .routing import normalize_ha_user_id, resolve_agent_id, resolve_model_override
from .routing import (
build_scoped_session_id,
normalize_ha_user_id,
resolve_agent_id,
resolve_model_override,
)
_LOGGER = logging.getLogger(__name__)
@@ -126,7 +131,11 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
ha_user_id = normalize_ha_user_id(getattr(context, "user_id", None))
options = self.entry.options
resolved_agent_id = resolve_agent_id(ha_user_id)
conversation_id = self._resolve_conversation_id(user_input, resolved_agent_id)
conversation_id = self._resolve_conversation_id(
user_input,
ha_user_id,
resolved_agent_id,
)
active_model = resolve_model_override(options.get("active_model"))
include_context = options.get(
CONF_INCLUDE_EXPOSED_CONTEXT,
@@ -218,9 +227,10 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
def _resolve_conversation_id(
self,
user_input: conversation.ConversationInput,
ha_user_id: str | None,
agent_id: str | None,
) -> str:
"""Return conversation id from HA with conservative agent namespacing."""
"""Return an OpenClaw agent-scoped session key for HA Assist."""
configured_session_id = self._normalize_optional_text(
self.entry.options.get(
CONF_ASSIST_SESSION_ID,
@@ -228,27 +238,37 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
)
)
if configured_session_id:
return configured_session_id
if configured_session_id.lower().startswith("agent:"):
return configured_session_id
return build_scoped_session_id(configured_session_id, ha_user_id, agent_id)
agent_suffix = self._normalize_optional_text(agent_id)
if user_input.conversation_id:
if agent_suffix:
return f"{user_input.conversation_id}:{agent_suffix}"
return user_input.conversation_id
if user_input.conversation_id.lower().startswith("agent:"):
return user_input.conversation_id
raw_session = (
f"{user_input.conversation_id}:{agent_suffix}"
if agent_suffix
else user_input.conversation_id
)
return build_scoped_session_id(raw_session, ha_user_id, agent_id)
context = getattr(user_input, "context", None)
user_id = getattr(context, "user_id", None)
if user_id:
base_id = f"assist_user_{user_id}"
return f"{base_id}:{agent_suffix}" if agent_suffix else base_id
raw_session = f"{base_id}:{agent_suffix}" if agent_suffix else base_id
return build_scoped_session_id(raw_session, ha_user_id, agent_id)
device_id = getattr(user_input, "device_id", None)
if device_id:
base_id = f"assist_device_{device_id}"
return f"{base_id}:{agent_suffix}" if agent_suffix else base_id
raw_session = f"{base_id}:{agent_suffix}" if agent_suffix else base_id
return build_scoped_session_id(raw_session, ha_user_id, agent_id)
return f"assist_default:{agent_suffix}" if agent_suffix else "assist_default"
raw_session = f"assist_default:{agent_suffix}" if agent_suffix else "assist_default"
return build_scoped_session_id(raw_session, ha_user_id, agent_id)
def _normalize_optional_text(self, value: Any) -> str | None:
"""Return a stripped string or None for blank values."""
@@ -310,7 +330,7 @@ class OpenClawConversationAgent(conversation.AbstractConversationAgent):
# Check if the response ends with a question mark
# (allow trailing punctuation like quotes, parens, or emoji)
if re.search(r"\?\s*[\"'""»)\]]*\s*$", text):
if re.search("\\?\\s*[\"'»)\\]]*\\s*$", text):
return True
# Common follow-up patterns (EN + DE)