feat: add configurable agent ID support

Allow users to configure which OpenClaw agent the integration communicates
with, instead of always defaulting to the implicit 'main' agent.

Changes:
- const.py: add CONF_AGENT_ID, DEFAULT_AGENT_ID='main', ATTR_AGENT_ID
- api.py: accept agent_id in constructor; _headers() now includes the
  x-openclaw-agent-id header on every request; async_send_message and
  async_stream_message accept an optional per-call agent_id override
- config_flow.py: expose agent_id as a text field in both the manual
  setup step and the options flow (Settings → Integrations → Configure)
- __init__.py: read agent_id from options/data and pass it to the API
  client; add optional agent_id field to the send_message service schema
  so automations can address a specific agent per-call
- services.yaml: document the new agent_id field on send_message
- strings.json / translations/en.json: add UI labels for the new option

The gateway routing header x-openclaw-agent-id is always sent; when
agent_id is 'main' (the default) the gateway behaviour is unchanged.
A per-call override on send_message takes precedence over the config.

Implemented with assistance from an AI coding agent (BMO) with human
review. Bot-assisted contribution reviewed by a human before submission.
This commit is contained in:
BMO (OpenClaw)
2026-02-26 13:50:07 -06:00
parent 9bcac79241
commit fa0af8da60
7 changed files with 71 additions and 6 deletions
+20 -4
View File
@@ -51,6 +51,7 @@ class OpenClawApiClient:
use_ssl: bool = False,
verify_ssl: bool = True,
session: aiohttp.ClientSession | None = None,
agent_id: str = "main",
) -> None:
"""Initialize the API client.
@@ -61,6 +62,7 @@ class OpenClawApiClient:
use_ssl: Use HTTPS instead of HTTP.
verify_ssl: Verify SSL certificates (set False for self-signed certs).
session: Optional aiohttp session (reused from HA).
agent_id: Target OpenClaw agent ID (default: "main").
"""
self._host = host
self._port = port
@@ -68,6 +70,7 @@ class OpenClawApiClient:
self._use_ssl = use_ssl
self._verify_ssl = verify_ssl
self._session = session
self._agent_id = agent_id
self._base_url = f"{'https' if use_ssl else 'http'}://{host}:{port}"
# ssl=False disables cert verification for self-signed certs;
# ssl=None uses default verification.
@@ -82,11 +85,18 @@ class OpenClawApiClient:
"""Update the authentication token (e.g., after addon restart)."""
self._token = token
def _headers(self) -> dict[str, str]:
"""Build request headers with auth token."""
def _headers(self, agent_id: str | None = None) -> dict[str, str]:
"""Build request headers with auth token and agent ID.
Args:
agent_id: Per-call agent ID override. Falls back to the
client-level ``agent_id`` set in the constructor.
"""
effective_agent = agent_id or self._agent_id or "main"
return {
"Authorization": f"Bearer {self._token}",
"Content-Type": "application/json",
"x-openclaw-agent-id": effective_agent,
}
async def _get_session(self) -> aiohttp.ClientSession:
@@ -182,6 +192,7 @@ class OpenClawApiClient:
model: str | None = None,
system_prompt: str | None = None,
stream: bool = False,
agent_id: str | None = None,
) -> dict[str, Any]:
"""Send a chat message (non-streaming).
@@ -190,6 +201,8 @@ class OpenClawApiClient:
session_id: Optional session/conversation ID.
model: Optional model override.
stream: If True, raises ValueError (use async_stream_message).
agent_id: Optional per-call agent ID override (overrides the
client-level default set in the constructor).
Returns:
Complete chat completion response.
@@ -213,7 +226,7 @@ class OpenClawApiClient:
payload["model"] = model
# Pass session_id as a custom header or param if supported by gateway
headers = self._headers()
headers = self._headers(agent_id=agent_id)
if session_id:
headers["X-Session-Id"] = session_id
headers["x-openclaw-session-key"] = session_id
@@ -247,6 +260,7 @@ class OpenClawApiClient:
session_id: str | None = None,
model: str | None = None,
system_prompt: str | None = None,
agent_id: str | None = None,
) -> AsyncIterator[str]:
"""Send a chat message and stream the response via SSE.
@@ -256,6 +270,8 @@ class OpenClawApiClient:
message: The user message text.
session_id: Optional session/conversation ID.
model: Optional model override.
agent_id: Optional per-call agent ID override (overrides the
client-level default set in the constructor).
Yields:
Content delta strings from the streaming response.
@@ -275,7 +291,7 @@ class OpenClawApiClient:
if model:
payload["model"] = model
headers = self._headers()
headers = self._headers(agent_id=agent_id)
if session_id:
headers["X-Session-Id"] = session_id
headers["x-openclaw-session-key"] = session_id