Version
hermes-agent 0.18.0 @ 30e947e · Python gateway running as a systemd user unit
Summary
AsyncSessionDB.__getattr__ (hermes_state.py:5818-5826) returns a coroutine
function for every attribute access on a callable:
def __getattr__(self, name):
attr = getattr(self._db, name)
if not callable(attr):
return attr
async def _offloaded(*args, **kwargs):
return await asyncio.to_thread(attr, *args, **kwargs)
return _offloaded
Any call site that treats an AsyncSessionDB method as synchronous produces a
coroutine that is never awaited: the DB operation never runs and Python emits a
RuntimeWarning. Because it's a generic forwarder, these bugs are invisible to
static analysis — there's no named async def to grep for a missing await.
Observed
On every gateway /model switch:
gateway/slash_commands.py:1773: RuntimeWarning: coroutine
'AsyncSessionDB.__getattr__.<locals>._offloaded' was never awaited
Reproduced on two independent gateways (default + a profile gateway) whenever a
/model command runs. The switch appears to succeed, but a session-DB write
issued during the switch is silently discarded.
Impact
Silent data loss on session state written during the affected paths. Suspected to
be the root cause of the null-system_prompt persistence bug (filed separately),
where the next turn finds no stored system prompt and rebuilds from scratch.
Suggested fixes
- Make the dropped call site
await the method (fix the immediate /model path
around slash_commands.py:1764-1773 / _finish_switch).
- Defensively, have
AsyncSessionDB guard against sync misuse — e.g. wrap
_offloaded so a garbage-collected un-awaited coroutine logs the offending
method name, not just an anonymous _offloaded.
Version
hermes-agent 0.18.0 @ 30e947e · Python gateway running as a systemd user unit
Summary
AsyncSessionDB.__getattr__(hermes_state.py:5818-5826) returns a coroutinefunction for every attribute access on a callable:
Any call site that treats an
AsyncSessionDBmethod as synchronous produces acoroutine that is never awaited: the DB operation never runs and Python emits a
RuntimeWarning. Because it's a generic forwarder, these bugs are invisible tostatic analysis — there's no named
async defto grep for a missingawait.Observed
On every gateway
/modelswitch:Reproduced on two independent gateways (default + a profile gateway) whenever a
/modelcommand runs. The switch appears to succeed, but a session-DB writeissued during the switch is silently discarded.
Impact
Silent data loss on session state written during the affected paths. Suspected to
be the root cause of the null-
system_promptpersistence bug (filed separately),where the next turn finds no stored system prompt and rebuilds from scratch.
Suggested fixes
awaitthe method (fix the immediate/modelpatharound
slash_commands.py:1764-1773/_finish_switch).AsyncSessionDBguard against sync misuse — e.g. wrap_offloadedso a garbage-collected un-awaited coroutine logs the offendingmethod name, not just an anonymous
_offloaded.