hermes-agent/plugins/platforms
ygd58 74939d2bfe fix(photon): stop sidecar-crash fatal handler from cancelling its own supervisor task
Fixes #73159.

When the Photon sidecar exits unexpectedly, _supervise_sidecar()
(running as self._sidecar_supervisor_task) correctly detects
SIDECAR_CRASHED and calls self._notify_fatal_error(). The Gateway's
fatal-error handler answers that by calling adapter.disconnect(),
which calls _stop_sidecar() -- from INSIDE the very task that's
currently executing this whole chain.

_stop_sidecar()'s cleanup unconditionally cancelled
self._sidecar_supervisor_task. Cancelling the currently-running task
raises CancelledError at its own next await point (inside
_notify_fatal_error() or _stop_sidecar() itself). Since
asyncio.CancelledError inherits from BaseException (not Exception),
the Gateway's `except Exception` guards around the fatal-error handler
don't catch it -- the handler aborts before ever reaching the
"queue platform for background reconnection" step. Photon then stays
permanently in `retrying` state until the whole process is manually
restarted, even though detection worked correctly and the underlying
transient upstream outage had long since recovered.

Fix: in _stop_sidecar()'s cleanup, check whether
self._sidecar_supervisor_task is asyncio.current_task() before
cancelling it. A task cannot legally cancel itself in any useful way
anyway (the cancellation only takes effect at its own next await,
which is exactly the corruption described above) -- when we're inside
the supervisor's own call stack, it's already in the process of
finishing on its own once _notify_fatal_error() returns, so skip the
cancel and just clear the reference.

This mirrors an existing precedent in the same file: disconnect()
already guards its OTHER task-cancellation (self._sidecar_health_task)
the same way (`if task is not asyncio.current_task()`), just not the
supervisor task in _stop_sidecar().

Per the issue's own note that existing tests mock out
_notify_fatal_error() entirely (so this integration chain was never
exercised), added two tests that drive the REAL chain: one runs
_supervise_sidecar() as an actual asyncio task with a real
_notify_fatal_error() that calls the real disconnect() -> _stop_sidecar(),
confirming the task completes without CancelledError and that the
post-disconnect reconnect-queue step actually executes; a second
confirms the OTHER call path (external cleanup, a different task)
still correctly cancels a running supervisor exactly as before.
Reverting only the adapter.py fix (keeping the new test) reproduces
the exact CancelledError from the bug report, confirming this is a
genuine regression test.

2 new tests pass; 113/113 in the full tests/plugins/platforms/photon/
directory (no regression to sidecar lifecycle, overflow recovery, or
health-monitoring behavior).
2026-07-28 21:45:52 -07:00
..
buzz feat(buzz): WebSocket inbound transport — NIP-42 auth, live DM discovery, poll fallback 2026-07-28 21:45:34 -07:00
dingtalk fix(dingtalk): don't let richText re-derivation clobber VOICE classification 2026-07-28 14:06:56 -07:00
discord refactor(discord): delegate ffmpeg discovery to shared tools.transcription_tools helper 2026-07-28 11:56:37 -07:00
email fix(email): harden adapter against malformed IMAP responses 2026-07-02 03:12:53 -07:00
feishu fix(feishu): classify native voice messages as VOICE for auto-transcription 2026-07-28 14:06:56 -07:00
google_chat fix(gateway): extend the utf-8 file-I/O guard to google_chat + whatsapp 2026-07-24 15:47:12 -07:00
homeassistant fix(gateway): validate multiplex adapter config by platform 2026-07-16 05:39:58 -07:00
irc fix(telegram): preserve Bot API update queue on watcher reconnect 2026-06-25 21:29:57 -07:00
line fix(line): normalize inbound media types and cache routing 2026-07-28 14:06:56 -07:00
matrix fix(tts): improve Opus encoding quality for voice messages 2026-07-28 11:55:48 -07:00
mattermost fix(platforms): clear home channel when setup prompt left blank 2026-07-23 12:01:24 -07:00
ntfy fix(telegram): preserve Bot API update queue on watcher reconnect 2026-06-25 21:29:57 -07:00
photon fix(photon): stop sidecar-crash fatal handler from cancelling its own supervisor task 2026-07-28 21:45:52 -07:00
raft fix(security): widen non-ASCII compare_digest crash fix to all sibling sites 2026-07-16 07:22:24 -07:00
simplex fix(telegram): preserve Bot API update queue on watcher reconnect 2026-06-25 21:29:57 -07:00
slack fix(slack): prefer live send adapter and try multi-workspace tokens individually 2026-07-23 12:01:24 -07:00
sms fix(security): widen non-ASCII compare_digest crash fix to all sibling sites 2026-07-16 07:22:24 -07:00
teams fix(security): pin DNS resolutions for SSRF-safe fetches 2026-07-23 11:44:43 -07:00
telegram fix(telegram): render markdown in voice-message captions 2026-07-28 11:55:48 -07:00
wecom fix(platforms): clear home channel when setup prompt left blank 2026-07-23 12:01:24 -07:00
whatsapp fix(whatsapp): preserve voice notes when STT fails 2026-07-28 14:06:56 -07:00