Files
hermes-agent/gateway/platforms
Justin Huang 74d2660aeb fix(gateway): await async post-delivery callbacks in chained wrapper
When two features register a post-delivery callback for the same session
(e.g. background-review release + /goal continuation), the second
registration is composed with the first via a `_chained` wrapper. That
wrapper was `def _chained()` — a sync function calling each callback
via `_prev()` / `_new()` and discarding the return value.

For sync callbacks that's fine. For async callbacks (such as the
`_deliver()` coroutine the /goal feature registers to inject the
continuation prompt) the returned coroutine was silently dropped:
RuntimeWarning: coroutine '_deliver' was never awaited.

Outer invoker in `_handle_message` already checks
`inspect.isawaitable(_post_result)` and awaits — but only sees the
wrapper's return value, which was `None`.

Fix: make `_chained` async, iterate over chained callbacks, await any
that return an awaitable. Outer invoker already handles awaitable
wrappers, so no other change is needed.

Tested:
* Added two regression tests in test_post_delivery_callback_chaining.py
  covering an async callback chained behind sync (and vice versa).
* Updated existing chaining tests + test_run_cleanup_progress.py to
  await the popped callback when it's awaitable.
* 62 tests pass across the touched suites.

Live-validated on Discord: /goal continuations now arrive after the
first turn's response is delivered (previously silent).

Refs: NousResearch/hermes-agent#31922
2026-07-01 02:12:25 -07:00
..
2026-04-26 18:50:49 -07:00