Summary
check_system_health (tools.py:748-762) calls asyncio.run(registry.run_all(...)). This works today only because sync tools run in a thread pool via run_in_executor. But unlike recall_memory and recall_conversation (which use run_coroutine_threadsafe with fallback), this will crash with RuntimeError: asyncio.run() cannot be called from a running event loop if the tool ever runs in an async context.
Fix
Use the same pattern as recall_memory (lines 399-415):
try:
loop = asyncio.get_running_loop()
except RuntimeError:
loop = None
if loop is not None:
report = asyncio.run_coroutine_threadsafe(
registry.run_all(user_id=ctx.user_id), loop
).result(timeout=30)
else:
report = asyncio.run(registry.run_all(user_id=ctx.user_id))
Files
apps/server/src/anima_server/services/agent/tools.py:748-762
Severity
High — crash if call path changes (tool becomes async, executor dispatches differently).
Summary
check_system_health(tools.py:748-762) callsasyncio.run(registry.run_all(...)). This works today only because sync tools run in a thread pool viarun_in_executor. But unlikerecall_memoryandrecall_conversation(which userun_coroutine_threadsafewith fallback), this will crash withRuntimeError: asyncio.run() cannot be called from a running event loopif the tool ever runs in an async context.Fix
Use the same pattern as
recall_memory(lines 399-415):Files
apps/server/src/anima_server/services/agent/tools.py:748-762Severity
High — crash if call path changes (tool becomes async, executor dispatches differently).