Skip to content

Commit e0c0c7b

Browse files
author
techartdev
committed
Add configurable agent_id support and update integration options
- Introduced configurable OpenClaw `agent_id` for manual setup and service overrides. - Enhanced API client to support routing messages to specific agents. - Updated integration options to reload automatically upon saving changes. - Added service descriptions and translations for the new `agent_id` field. - Updated version to 0.1.58 in manifest.
1 parent 9bcac79 commit e0c0c7b

9 files changed

Lines changed: 76 additions & 8 deletions

File tree

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,16 @@
22

33
All notable changes to the OpenClaw Home Assistant Integration will be documented in this file.
44

5+
## [0.1.58] - 2026-03-07
6+
7+
### Added
8+
- Added configurable OpenClaw `agent_id` support for manual setup, integration options, and per-call `openclaw.send_message` service overrides.
9+
- Added `x-openclaw-agent-id` routing support in the API client so messages can target non-`main` OpenClaw agents.
10+
11+
### Changed
12+
- Saving OpenClaw integration options now reloads the integration automatically, so updated `agent_id` and other runtime options apply immediately.
13+
- Added service descriptions and translations for the new `agent_id` field in the configuration UI.
14+
515
## [0.1.57] - 2026-02-26
616

717
### Changed

custom_components/openclaw/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
from .api import OpenClawApiClient, OpenClawApiError
3232
from .const import (
33+
ATTR_AGENT_ID,
3334
ATTR_ATTACHMENTS,
3435
ATTR_MESSAGE,
3536
ATTR_MODEL,
@@ -47,6 +48,7 @@
4748
ATTR_ACCOUNT_ID,
4849
ATTR_TIMESTAMP,
4950
CONF_ADDON_CONFIG_PATH,
51+
CONF_AGENT_ID,
5052
CONF_GATEWAY_HOST,
5153
CONF_GATEWAY_PORT,
5254
CONF_GATEWAY_TOKEN,
@@ -63,6 +65,7 @@
6365
CONF_VOICE_PROVIDER,
6466
CONF_THINKING_TIMEOUT,
6567
CONTEXT_STRATEGY_TRUNCATE,
68+
DEFAULT_AGENT_ID,
6669
DEFAULT_CONTEXT_MAX_CHARS,
6770
DEFAULT_CONTEXT_STRATEGY,
6871
DEFAULT_ENABLE_TOOL_CALLS,
@@ -106,6 +109,7 @@
106109
vol.Required(ATTR_MESSAGE): cv.string,
107110
vol.Optional(ATTR_SESSION_ID): cv.string,
108111
vol.Optional(ATTR_ATTACHMENTS): vol.All(cv.ensure_list, [cv.string]),
112+
vol.Optional(ATTR_AGENT_ID): cv.string,
109113
}
110114
)
111115

@@ -136,6 +140,10 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenClawConfigEntry) ->
136140
use_ssl = entry.data.get(CONF_USE_SSL, False)
137141
verify_ssl = entry.data.get(CONF_VERIFY_SSL, True)
138142
session = async_get_clientsession(hass, verify_ssl=verify_ssl)
143+
agent_id: str = entry.options.get(
144+
CONF_AGENT_ID,
145+
entry.data.get(CONF_AGENT_ID, DEFAULT_AGENT_ID),
146+
)
139147

140148
client = OpenClawApiClient(
141149
host=entry.data[CONF_GATEWAY_HOST],
@@ -144,6 +152,7 @@ async def async_setup_entry(hass: HomeAssistant, entry: OpenClawConfigEntry) ->
144152
use_ssl=use_ssl,
145153
verify_ssl=verify_ssl,
146154
session=session,
155+
agent_id=agent_id,
147156
)
148157

149158
coordinator = OpenClawCoordinator(hass, client)
@@ -385,6 +394,7 @@ async def handle_send_message(call: ServiceCall) -> None:
385394
"""Handle the openclaw.send_message service call."""
386395
message: str = call.data[ATTR_MESSAGE]
387396
session_id: str = call.data.get(ATTR_SESSION_ID) or "default"
397+
call_agent_id: str | None = call.data.get(ATTR_AGENT_ID)
388398

389399
entry_data = _get_first_entry_data(hass)
390400
if not entry_data:
@@ -420,6 +430,7 @@ async def handle_send_message(call: ServiceCall) -> None:
420430
message=message,
421431
session_id=session_id,
422432
system_prompt=system_prompt,
433+
agent_id=call_agent_id,
423434
)
424435

425436
if options.get(CONF_ENABLE_TOOL_CALLS, DEFAULT_ENABLE_TOOL_CALLS):
@@ -433,6 +444,7 @@ async def handle_send_message(call: ServiceCall) -> None:
433444
),
434445
session_id=session_id,
435446
system_prompt=system_prompt,
447+
agent_id=call_agent_id,
436448
)
437449

438450
assistant_message = _extract_assistant_message(response)

custom_components/openclaw/api.py

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ def __init__(
5151
use_ssl: bool = False,
5252
verify_ssl: bool = True,
5353
session: aiohttp.ClientSession | None = None,
54+
agent_id: str = "main",
5455
) -> None:
5556
"""Initialize the API client.
5657
@@ -61,13 +62,15 @@ def __init__(
6162
use_ssl: Use HTTPS instead of HTTP.
6263
verify_ssl: Verify SSL certificates (set False for self-signed certs).
6364
session: Optional aiohttp session (reused from HA).
65+
agent_id: Target OpenClaw agent ID (default: "main").
6466
"""
6567
self._host = host
6668
self._port = port
6769
self._token = token
6870
self._use_ssl = use_ssl
6971
self._verify_ssl = verify_ssl
7072
self._session = session
73+
self._agent_id = agent_id
7174
self._base_url = f"{'https' if use_ssl else 'http'}://{host}:{port}"
7275
# ssl=False disables cert verification for self-signed certs;
7376
# ssl=None uses default verification.
@@ -82,11 +85,13 @@ def update_token(self, token: str) -> None:
8285
"""Update the authentication token (e.g., after addon restart)."""
8386
self._token = token
8487

85-
def _headers(self) -> dict[str, str]:
86-
"""Build request headers with auth token."""
88+
def _headers(self, agent_id: str | None = None) -> dict[str, str]:
89+
"""Build request headers with auth token and agent ID."""
90+
effective_agent = agent_id or self._agent_id or "main"
8791
return {
8892
"Authorization": f"Bearer {self._token}",
8993
"Content-Type": "application/json",
94+
"x-openclaw-agent-id": effective_agent,
9095
}
9196

9297
async def _get_session(self) -> aiohttp.ClientSession:
@@ -182,6 +187,7 @@ async def async_send_message(
182187
model: str | None = None,
183188
system_prompt: str | None = None,
184189
stream: bool = False,
190+
agent_id: str | None = None,
185191
) -> dict[str, Any]:
186192
"""Send a chat message (non-streaming).
187193
@@ -190,6 +196,7 @@ async def async_send_message(
190196
session_id: Optional session/conversation ID.
191197
model: Optional model override.
192198
stream: If True, raises ValueError (use async_stream_message).
199+
agent_id: Optional per-call agent ID override.
193200
194201
Returns:
195202
Complete chat completion response.
@@ -213,7 +220,7 @@ async def async_send_message(
213220
payload["model"] = model
214221

215222
# Pass session_id as a custom header or param if supported by gateway
216-
headers = self._headers()
223+
headers = self._headers(agent_id=agent_id)
217224
if session_id:
218225
headers["X-Session-Id"] = session_id
219226
headers["x-openclaw-session-key"] = session_id
@@ -247,6 +254,7 @@ async def async_stream_message(
247254
session_id: str | None = None,
248255
model: str | None = None,
249256
system_prompt: str | None = None,
257+
agent_id: str | None = None,
250258
) -> AsyncIterator[str]:
251259
"""Send a chat message and stream the response via SSE.
252260
@@ -256,6 +264,7 @@ async def async_stream_message(
256264
message: The user message text.
257265
session_id: Optional session/conversation ID.
258266
model: Optional model override.
267+
agent_id: Optional per-call agent ID override.
259268
260269
Yields:
261270
Content delta strings from the streaming response.
@@ -275,7 +284,7 @@ async def async_stream_message(
275284
if model:
276285
payload["model"] = model
277286

278-
headers = self._headers()
287+
headers = self._headers(agent_id=agent_id)
279288
if session_id:
280289
headers["X-Session-Id"] = session_id
281290
headers["x-openclaw-session-key"] = session_id

custom_components/openclaw/config_flow.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,13 @@
2020
ConfigFlow,
2121
ConfigFlowResult,
2222
OptionsFlow,
23+
OptionsFlowWithReload,
2324
)
2425
except ImportError:
2526
from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow
2627

2728
ConfigFlowResult = dict[str, Any]
29+
OptionsFlowWithReload = OptionsFlow
2830
from homeassistant.core import HomeAssistant
2931
from homeassistant.helpers.aiohttp_client import async_get_clientsession
3032

@@ -34,6 +36,7 @@
3436
ADDON_SLUG,
3537
ADDON_SLUG_FRAGMENTS,
3638
CONF_ADDON_CONFIG_PATH,
39+
CONF_AGENT_ID,
3740
CONF_GATEWAY_HOST,
3841
CONF_GATEWAY_PORT,
3942
CONF_GATEWAY_TOKEN,
@@ -52,6 +55,7 @@
5255
BROWSER_VOICE_LANGUAGES,
5356
CONTEXT_STRATEGY_CLEAR,
5457
CONTEXT_STRATEGY_TRUNCATE,
58+
DEFAULT_AGENT_ID,
5559
DEFAULT_GATEWAY_HOST,
5660
DEFAULT_GATEWAY_PORT,
5761
DEFAULT_CONTEXT_MAX_CHARS,
@@ -411,6 +415,7 @@ async def async_step_manual(
411415
CONF_GATEWAY_TOKEN: token,
412416
CONF_USE_SSL: use_ssl,
413417
CONF_VERIFY_SSL: verify_ssl,
418+
CONF_AGENT_ID: user_input.get(CONF_AGENT_ID, DEFAULT_AGENT_ID),
414419
},
415420
)
416421
if "base" not in errors:
@@ -429,13 +434,14 @@ async def async_step_manual(
429434
vol.Required(CONF_GATEWAY_TOKEN): str,
430435
vol.Optional(CONF_USE_SSL, default=False): bool,
431436
vol.Optional(CONF_VERIFY_SSL, default=True): bool,
437+
vol.Optional(CONF_AGENT_ID, default=DEFAULT_AGENT_ID): str,
432438
}
433439
),
434440
errors=errors,
435441
)
436442

437443

438-
class OpenClawOptionsFlow(OptionsFlow):
444+
class OpenClawOptionsFlow(OptionsFlowWithReload):
439445
"""Handle OpenClaw options."""
440446

441447
def __init__(self, config_entry: ConfigEntry) -> None:
@@ -453,6 +459,13 @@ async def async_step_init(
453459
selected_provider = options.get(CONF_VOICE_PROVIDER, DEFAULT_VOICE_PROVIDER)
454460

455461
schema: dict[Any, Any] = {
462+
vol.Optional(
463+
CONF_AGENT_ID,
464+
default=options.get(
465+
CONF_AGENT_ID,
466+
self._config_entry.data.get(CONF_AGENT_ID, DEFAULT_AGENT_ID),
467+
),
468+
): str,
456469
vol.Optional(
457470
CONF_INCLUDE_EXPOSED_CONTEXT,
458471
default=options.get(

custom_components/openclaw/const.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
CONF_USE_SSL = "use_ssl"
2424
CONF_VERIFY_SSL = "verify_ssl"
2525
CONF_ADDON_CONFIG_PATH = "addon_config_path"
26+
CONF_AGENT_ID = "agent_id"
2627

2728
# Options
2829
CONF_INCLUDE_EXPOSED_CONTEXT = "include_exposed_context"
@@ -36,6 +37,7 @@
3637
CONF_BROWSER_VOICE_LANGUAGE = "browser_voice_language"
3738
CONF_THINKING_TIMEOUT = "thinking_timeout"
3839

40+
DEFAULT_AGENT_ID = "main"
3941
DEFAULT_INCLUDE_EXPOSED_CONTEXT = True
4042
DEFAULT_CONTEXT_MAX_CHARS = 13000
4143
DEFAULT_CONTEXT_STRATEGY = "truncate"
@@ -130,6 +132,7 @@
130132
ATTR_DRY_RUN = "dry_run"
131133
ATTR_MESSAGE_CHANNEL = "message_channel"
132134
ATTR_ACCOUNT_ID = "account_id"
135+
ATTR_AGENT_ID = "agent_id"
133136
ATTR_OK = "ok"
134137
ATTR_RESULT = "result"
135138
ATTR_ERROR = "error"

custom_components/openclaw/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"iot_class": "local_polling",
99
"issue_tracker": "https://github.com/techartdev/OpenClawHomeAssistant/issues",
1010
"requirements": [],
11-
"version": "0.1.57",
11+
"version": "0.1.58",
1212
"dependencies": ["conversation"],
1313
"after_dependencies": ["hassio", "lovelace"]
1414
}

custom_components/openclaw/services.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,15 @@ send_message:
2424
selector:
2525
text:
2626
multiline: true
27+
agent_id:
28+
name: Agent ID
29+
description: >
30+
Optional OpenClaw agent ID to route this message to. Overrides the
31+
agent ID configured in the integration options. Defaults to "main".
32+
required: false
33+
example: "main"
34+
selector:
35+
text:
2736

2837
clear_history:
2938
name: Clear History

custom_components/openclaw/strings.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"gateway_port": "Gateway Port",
1919
"gateway_token": "Gateway Token",
2020
"use_ssl": "Use SSL (HTTPS)",
21-
"verify_ssl": "Verify SSL certificate"
21+
"verify_ssl": "Verify SSL certificate",
22+
"agent_id": "Agent ID"
2223
}
2324
}
2425
},
@@ -37,6 +38,7 @@
3738
"title": "OpenClaw Options",
3839
"description": "Configure context and tool-calling behavior.",
3940
"data": {
41+
"agent_id": "Agent ID (e.g. main)",
4042
"include_exposed_context": "Include exposed entities context",
4143
"context_max_chars": "Max context characters",
4244
"context_strategy": "When context exceeds max",
@@ -124,6 +126,10 @@
124126
"attachments": {
125127
"name": "Attachments",
126128
"description": "Optional file attachments."
129+
},
130+
"agent_id": {
131+
"name": "Agent ID",
132+
"description": "Optional OpenClaw agent ID to route this message to. Overrides the configured default. Defaults to \"main\"."
127133
}
128134
}
129135
},

custom_components/openclaw/translations/en.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
"gateway_port": "Gateway Port",
1919
"gateway_token": "Gateway Token",
2020
"use_ssl": "Use SSL (HTTPS)",
21-
"verify_ssl": "Verify SSL certificate"
21+
"verify_ssl": "Verify SSL certificate",
22+
"agent_id": "Agent ID"
2223
}
2324
}
2425
},
@@ -39,6 +40,7 @@
3940
"title": "OpenClaw Options",
4041
"description": "Configure context and tool-calling behavior.",
4142
"data": {
43+
"agent_id": "Agent ID (e.g. main)",
4244
"include_exposed_context": "Include exposed entities context",
4345
"context_max_chars": "Max context characters",
4446
"context_strategy": "When context exceeds max",
@@ -126,6 +128,10 @@
126128
"attachments": {
127129
"name": "Attachments",
128130
"description": "Optional file attachments."
131+
},
132+
"agent_id": {
133+
"name": "Agent ID",
134+
"description": "Optional OpenClaw agent ID to route this message to. Overrides the configured default. Defaults to \"main\"."
129135
}
130136
}
131137
},

0 commit comments

Comments
 (0)