refactor(gateway): migrate Home Assistant adapter to bundled plugin#32500
Closed
kshitijk4poor wants to merge 1 commit into
Closed
refactor(gateway): migrate Home Assistant adapter to bundled plugin#32500kshitijk4poor wants to merge 1 commit into
kshitijk4poor wants to merge 1 commit into
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.
2c45b72 to
4bbdf57
Compare
Contributor
|
Merged via #40709 — your commit was cherry-picked onto current main with your authorship preserved in git log (the original branch was 1211 commits behind). Thanks for the clean migration; it followed the mattermost/discord plugin shape exactly. |
teknium1
pushed a commit
that referenced
this pull request
Jun 6, 2026
`gateway/run.py::_UPDATE_ALLOWED_PLATFORMS` was a hardcoded frozenset listing every messaging platform allowed to invoke the `/update` slash command. Plugin-migrated platforms (currently Discord and Mattermost, soon also Home Assistant via #32500) declare `allow_update_command=True` on their `PlatformEntry`, and `_handle_update_command` already falls back to the registry when a platform isn't in the frozenset. The result was a silent redundancy: those entries said "allowed" twice, and the registry flag was a no-op for them in practice. - Removed `Platform.DISCORD` and `Platform.MATTERMOST` from the frozenset. - Updated the docstring to make the split explicit (built-ins live in the frozenset; plugins use `allow_update_command` on the registry entry). The remaining frozenset entries are all still built-in platforms living under `gateway/platforms/` today. Future plugin migrations should drop their entry from the frozenset as part of the migration PR (or in a sibling chore PR like this one). Added a `TestUpdateCommandPlatformGate` test class that pins down all three branches of the gate so future changes don't silently regress: - Programmatic interfaces (`Platform.WEBHOOK`, `Platform.API_SERVER`) must remain blocked. - Plugin-migrated platforms (Discord, Mattermost) must pass via the registry fallback. - Built-in platforms in the hardcoded frozenset (Telegram) must still pass without needing the registry. The gate previously had zero direct test coverage — its only existing coverage was `test_no_adapter_for_platform` which exercised a different code path.
changman
pushed a commit
to changman/hermes-agent
that referenced
this pull request
Jun 10, 2026
`gateway/run.py::_UPDATE_ALLOWED_PLATFORMS` was a hardcoded frozenset listing every messaging platform allowed to invoke the `/update` slash command. Plugin-migrated platforms (currently Discord and Mattermost, soon also Home Assistant via NousResearch#32500) declare `allow_update_command=True` on their `PlatformEntry`, and `_handle_update_command` already falls back to the registry when a platform isn't in the frozenset. The result was a silent redundancy: those entries said "allowed" twice, and the registry flag was a no-op for them in practice. - Removed `Platform.DISCORD` and `Platform.MATTERMOST` from the frozenset. - Updated the docstring to make the split explicit (built-ins live in the frozenset; plugins use `allow_update_command` on the registry entry). The remaining frozenset entries are all still built-in platforms living under `gateway/platforms/` today. Future plugin migrations should drop their entry from the frozenset as part of the migration PR (or in a sibling chore PR like this one). Added a `TestUpdateCommandPlatformGate` test class that pins down all three branches of the gate so future changes don't silently regress: - Programmatic interfaces (`Platform.WEBHOOK`, `Platform.API_SERVER`) must remain blocked. - Plugin-migrated platforms (Discord, Mattermost) must pass via the registry fallback. - Built-in platforms in the hardcoded frozenset (Telegram) must still pass without needing the registry. The gate previously had zero direct test coverage — its only existing coverage was `test_no_adapter_for_platform` which exercised a different code path.
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
Moves the Home Assistant gateway adapter out of
gateway/platforms/homeassistant.pyand intoplugins/platforms/homeassistant/as a bundled plugin, following the same shape as the recent Mattermost (#31748), Discord, Teams, and other platform-plugin migrations.After this PR, every consumer of the HA adapter goes through
PluginManager.discover_and_load()→platform_registry.get("homeassistant")instead of a hardcodedPlatform.HOMEASSISTANTimport branch.What moves into the plugin
gateway/platforms/homeassistant.py(the whole file)plugins/platforms/homeassistant/adapter.pygit mv, 76% similarity preservedgateway/run.pyHOMEASSISTANTelifinbuild_adapter()tools/send_message_tool.py::_send_homeassistant_standalone_send()in pluginstandalone_sender_fnelifin_send_to_platformchainelsebranchNew files:
plugins/platforms/homeassistant/__init__.py— exposesregisterplugins/platforms/homeassistant/plugin.yaml— manifest declaringHASS_TOKEN(required) andHASS_URL(optional)plugins/platforms/homeassistant/adapter.py— renamed adapter with an appendedregister()blockWhat stays in core (intentionally)
HASS_TOKEN/HASS_URLenv-to-PlatformConfigseeding atgateway/config.py:1392-1401. The bluebubbles, mattermost, and discord migrations all kept their equivalent block ingateway/config.pyrather than moving it into anenv_enablement_fn. Keeping the same pattern here means PR feat(homeassistant): split tool vs platform env vars #29199 (split tool vs platform env vars) collides at most on that small block, not on the renamed file.Platform.HOMEASSISTANTenum literal — used as a dict key throughout the codebase; removing it is a separate refactor with no real benefit (per the established migration playbook).tools/homeassistant_tool.py— the HA REST/WS toolset that lets the agent call HA services from a prompt. It is a separate concern from this messaging adapter and is not affected.What does not need a hook
setup_fn— Home Assistant has no_setup_homeassistantfunction inhermes_cli/setup.pyand is not inhermes_cli/gateway.py::_builtin_setup_fn(). Setup runs through the existing toolset wizard inhermes_cli/tools_config.py, which is unchanged by this PR.apply_yaml_config_fn— nohomeassistant:block currently exists inconfig.yaml; there is nothing to translate.cron_deliver_env_var— Home Assistant has no notion of a "home channel" the way Discord / Slack / Mattermost do. Crondeliver=homeassistantstill works viastandalone_sender_fn; it just always requires an explicitchat_id(the HAnotifytarget, e.g.mobile_app_pixel_8).allowed_users_env/allow_all_env— the HA adapter consumes the WebSocket event bus, not user-to-user messages; auth is per-token, not per-user.Why
_standalone_sendusesnotify.notify, notpersistent_notification.createThe live adapter's
send()callspersistent_notification.create(a notification visible in the HA UI). The legacy_send_homeassistanthelper intools/send_message_tool.pyalways usednotify.notify(which triggers an actual HA notify service, e.g. push to a phone). Out-of-process cron delivery preserves the legacy helper's behavior — phones get pushed, not just an HA dashboard banner. The two surfaces were already different before this PR and this migration does not change that.Verification
Tests
tests/gateway/test_homeassistant.py— 41 tests, import paths updated toplugins.platforms.homeassistant.adapter, allmock.patch(...)strings updated. Passes.tests/integration/test_ha_integration.py— adapter import path updated. Passes.tests/tools/test_send_message_missing_platforms.py— the legacy(token, extra, chat_id, message)-shaped_send_homeassistantis preserved via a smallSimpleNamespaceshim that wraps the plugin's_standalone_send(pconfig, chat_id, message). This mirrors the shim mattermost added when it migrated, so the existing 4 test bodies don't have to be rewritten. Passes.Focused suite: 64 passed.
Broader gateway + cron sweep: 6218 passed, 10 failures — identical set to the same sweep run against unmodified
main(telegram approval/model-picker xdist isolation flakes,wecom_callbackdefusedxml issue,cron/test_cron_script::test_script_timeoutsubprocess-timeout fixture issue). Zero net new failures.Context for in-flight HA PRs
There are several open HA PRs that touch
gateway/platforms/homeassistant.py(#29199, #29388, #31389, #27270, #27272, #24053, #23643). After this migration the file is atplugins/platforms/homeassistant/adapter.py— git rename detection should make rebases largely mechanical, and the env-to-PlatformConfigblock they care about stays ingateway/config.py. Happy to help with any rebase.