refactor(gateway): migrate Home Assistant adapter to bundled plugin#40709
Merged
Conversation
Move gateway/platforms/homeassistant.py into plugins/platforms/homeassistant/
following the same shape as the Mattermost and Discord migrations.
- Adapter file is renamed via git mv (history is preserved).
- register() exposes the platform via the plugin system instead of the
hardcoded Platform.HOMEASSISTANT elif in gateway/run.py::build_adapter().
- _standalone_send() replaces the legacy _send_homeassistant() helper in
tools/send_message_tool.py. Out-of-process cron delivery
(deliver=homeassistant from a cron process not co-located with the
gateway) now flows through the registry's standalone_sender_fn path
instead of the hardcoded elif.
- _is_connected() probes HASS_TOKEN via hermes_cli.gateway.get_env_value
so existing connected-platform checks behave identically.
The HASS_TOKEN / HASS_URL env-to-PlatformConfig seeding in
gateway/config.py stays in core — same pattern bluebubbles, mattermost,
and discord migrations followed. No setup_fn or apply_yaml_config_fn is
registered because Home Assistant has no _setup_homeassistant wizard in
hermes_cli/setup.py and no homeassistant: YAML block in config.yaml today;
setup runs through the existing hermes_cli/tools_config.py toolset wizard.
Test imports were rewritten across tests/gateway/test_homeassistant.py,
tests/integration/test_ha_integration.py, and
tests/tools/test_send_message_missing_platforms.py; the legacy
(token, extra, chat_id, message)-shaped _send_homeassistant call site is
preserved via a small SimpleNamespace shim in
test_send_message_missing_platforms.py (same approach used when
mattermost moved).
- Focused HA suites (64 tests across the three rewritten files) pass.
- Broader gateway/cron sweep produces 10 failures identical to main
baseline (telegram approval/model-picker xdist isolation flakes,
wecom_callback defusedxml issue, cron script_timeout fixture issue).
Zero net new failures.
Contributor
🔎 Lint report:
|
| Rule | Count |
|---|---|
unresolved-attribute |
4 |
unresolved-import |
1 |
First entries
plugins/platforms/homeassistant/adapter.py:70: [unresolved-attribute] unresolved-attribute: Attribute `ClientWebSocketResponse` is not defined on `None` in union `Unknown | None`
plugins/platforms/homeassistant/adapter.py:259: [unresolved-attribute] unresolved-attribute: Attribute `WSMsgType` is not defined on `None` in union `Unknown | None`
plugins/platforms/homeassistant/adapter.py:506: [unresolved-attribute] unresolved-attribute: Attribute `ClientSession` is not defined on `None` in union `Unknown | None`
plugins/platforms/homeassistant/adapter.py:507: [unresolved-attribute] unresolved-attribute: Attribute `ClientTimeout` is not defined on `None` in union `Unknown | None`
plugins/platforms/homeassistant/adapter.py:25: [unresolved-import] unresolved-import: Cannot resolve imported module `aiohttp`
✅ Fixed issues (5):
| Rule | Count |
|---|---|
unresolved-attribute |
4 |
unresolved-import |
1 |
First entries
gateway/platforms/homeassistant.py:70: [unresolved-attribute] unresolved-attribute: Attribute `ClientWebSocketResponse` is not defined on `None` in union `Unknown | None`
gateway/platforms/homeassistant.py:422: [unresolved-attribute] unresolved-attribute: Attribute `ClientSession` is not defined on `None` in union `Unknown | None`
gateway/platforms/homeassistant.py:427: [unresolved-attribute] unresolved-attribute: Attribute `ClientTimeout` is not defined on `None` in union `Unknown | None`
gateway/platforms/homeassistant.py:25: [unresolved-import] unresolved-import: Cannot resolve imported module `aiohttp`
gateway/platforms/homeassistant.py:259: [unresolved-attribute] unresolved-attribute: Attribute `WSMsgType` is not defined on `None` in union `Unknown | None`
Unchanged: 5162 pre-existing issues carried over.
Diagnostics are surfaced as warnings — this check never fails the build.
teknium1
added a commit
that referenced
this pull request
Jun 7, 2026
Home Assistant is a bundled plugin now (#40709) and declares allow_update_command=True on its PlatformEntry. The registry fallback in _handle_update_command already covers it, so the frozenset entry is a redundant double-allow — same cleanup #40711 did for Discord and Mattermost. Adds a registry-fallback test mirroring the existing discord/mattermost cases.
28 tasks
teknium1
added a commit
that referenced
this pull request
Jun 7, 2026
Move gateway/platforms/slack.py into plugins/platforms/slack/ following the Discord (#24356) and Home Assistant (#40709) migrations. Advances #41112 / hardcoded Platform.SLACK touchpoints in core. - Adapter file renamed via git mv (history preserved). - register() exposes the platform via ctx.register_platform() instead of the Platform.SLACK elif in gateway/run.py::_create_adapter(). - _standalone_send() replaces the legacy _send_slack() helper in tools/send_message_tool.py; out-of-process cron delivery (deliver=slack) now flows through the registry's standalone_sender_fn. mrkdwn formatting moved into the plugin (was applied in _send_to_platform before chunking). - _apply_yaml_config() owns the config.yaml slack: -> SLACK_* env bridge (require_mention, strict_mention, allow_bots, free_response_channels, reactions, allowed_channels), replacing the hardcoded block in gateway/config.py. - interactive_setup() replaces hermes_cli/setup.py::_setup_slack + _write_slack_manifest_and_instruct and the static _PLATFORMS["slack"] dict in hermes_cli/gateway.py; setup metadata is discovered dynamically. - is_connected() probes SLACK_BOT_TOKEN via hermes_cli.gateway.get_env_value. - max_message_length=39000 on the PlatformEntry; the registry fallback in send_message_tool covers it (dropped the _MAX_LENGTHS entry). The SLACK_BOT_TOKEN/SLACK_HOME_CHANNEL env->PlatformConfig seeding and the _is_user_authorized allowlist maps stay in core (same as Discord/HA/Mattermost). Bug fixed during migration: the registry-driven plugin-enable pass in _apply_env_overrides re-enabled any plugin platform whose is_connected() passed, ignoring an explicit enabled: false. Slack is the first plugin with an enabled-false-wins test, so it exposed this latent bug (Discord had no such test). Added an explicit-disable guard (_enabled_explicit + enabled=False -> skip) and changed the slack env-block to read the flag instead of popping it so the guard can see it; the flag is still cleared in the final per-platform cleanup. Restores test_explicit_{top_level,platforms}_slack_enabled_false_wins. Test imports rewritten across 11 files (gateway.platforms.slack -> plugins.platforms.slack.adapter). The _setup_slack home-channel tests moved to tests/gateway/test_slack_plugin_setup.py exercising interactive_setup. The test_send_message_tool slack-formatting tests now patch the registry standalone_sender_fn (via _patch_slack_standalone_sender) and assert the mrkdwn-formatted text reaches the wire. Validation: 706 targeted tests pass (slack/config/setup/registry/send/media suites); 18/18 live E2E checks pass (real plugin discovery + registry resolves SlackAdapter, env-only enable, standalone sender wired, YAML bridge, dynamic setup discovery).
teknium1
added a commit
that referenced
this pull request
Jun 7, 2026
Move gateway/platforms/slack.py into plugins/platforms/slack/ following the Discord (#24356) and Home Assistant (#40709) migrations. Advances #41112 / hardcoded Platform.SLACK touchpoints in core. - Adapter file renamed via git mv (history preserved). - register() exposes the platform via ctx.register_platform() instead of the Platform.SLACK elif in gateway/run.py::_create_adapter(). - _standalone_send() replaces the legacy _send_slack() helper in tools/send_message_tool.py; out-of-process cron delivery (deliver=slack) now flows through the registry's standalone_sender_fn. mrkdwn formatting moved into the plugin (was applied in _send_to_platform before chunking). - _apply_yaml_config() owns the config.yaml slack: -> SLACK_* env bridge (require_mention, strict_mention, allow_bots, free_response_channels, reactions, allowed_channels), replacing the hardcoded block in gateway/config.py. - interactive_setup() replaces hermes_cli/setup.py::_setup_slack + _write_slack_manifest_and_instruct and the static _PLATFORMS["slack"] dict in hermes_cli/gateway.py; setup metadata is discovered dynamically. - is_connected() probes SLACK_BOT_TOKEN via hermes_cli.gateway.get_env_value. - max_message_length=39000 on the PlatformEntry; the registry fallback in send_message_tool covers it (dropped the _MAX_LENGTHS entry). The SLACK_BOT_TOKEN/SLACK_HOME_CHANNEL env->PlatformConfig seeding and the _is_user_authorized allowlist maps stay in core (same as Discord/HA/Mattermost). Bug fixed during migration: the registry-driven plugin-enable pass in _apply_env_overrides re-enabled any plugin platform whose is_connected() passed, ignoring an explicit enabled: false. Slack is the first plugin with an enabled-false-wins test, so it exposed this latent bug (Discord had no such test). Added an explicit-disable guard (_enabled_explicit + enabled=False -> skip) and changed the slack env-block to read the flag instead of popping it so the guard can see it; the flag is still cleared in the final per-platform cleanup. Restores test_explicit_{top_level,platforms}_slack_enabled_false_wins. Test imports rewritten across 11 files (gateway.platforms.slack -> plugins.platforms.slack.adapter). The _setup_slack home-channel tests moved to tests/gateway/test_slack_plugin_setup.py exercising interactive_setup. The test_send_message_tool slack-formatting tests now patch the registry standalone_sender_fn (via _patch_slack_standalone_sender) and assert the mrkdwn-formatted text reaches the wire. Validation: 706 targeted tests pass (slack/config/setup/registry/send/media suites); 18/18 live E2E checks pass (real plugin discovery + registry resolves SlackAdapter, env-only enable, standalone sender wired, YAML bridge, dynamic setup discovery).
changman
pushed a commit
to changman/hermes-agent
that referenced
this pull request
Jun 10, 2026
…ch#40736) Home Assistant is a bundled plugin now (NousResearch#40709) and declares allow_update_command=True on its PlatformEntry. The registry fallback in _handle_update_command already covers it, so the frozenset entry is a redundant double-allow — same cleanup NousResearch#40711 did for Discord and Mattermost. Adds a registry-fallback test mirroring the existing discord/mattermost cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Migrates the Home Assistant gateway adapter out of
gateway/platforms/homeassistant.pyintoplugins/platforms/homeassistant/as a bundled plugin, matching the Mattermost (#31748), Discord, and Teams plugin migrations. Every HA consumer now resolves viaPluginManager.discover_and_load()→platform_registry.get("homeassistant")instead of a hardcodedPlatform.HOMEASSISTANTimport branch.Salvage of #32500 by @kshitijk4poor onto current
main(original branch was 1211 commits behind). Cherry-pick preserved authorship; cleanly re-verified.Changes
gateway/platforms/homeassistant.py→plugins/platforms/homeassistant/adapter.py(git mv, 76% similarity) + appendedregister()plugins/platforms/homeassistant/__init__.py(exposesregister) andplugin.yaml(declaresHASS_TOKENrequired,HASS_URLoptional)gateway/run.py: removed HOMEASSISTANTeliffrombuild_adapter();_send_to_platformfalls through to the registryelsebranchtools/send_message_tool.py:_send_homeassistant→_standalone_send()in the plugin, reachable from cron viastandalone_sender_fnHASS_TOKEN/HASS_URLenv→PlatformConfigseeding stays ingateway/config.py(same as bluebubbles/mattermost/discord)Validation
homeassistantresolves assource: plugin,standalone_sender_fnset,required_env=['HASS_TOKEN'], emoji 🏠Original PR: #32500
Infographic