fix(plugins): bound async plugin command await with 30s timeout

Follow-up to #17963. The threaded branch of resolve_plugin_command_result
previously called Event.wait() with no timeout — a hung async plugin
handler would wedge the terminal indefinitely. Cap the wait at 30s and
raise TimeoutError instead. Added a regression test covering the hung
handler path.
This commit is contained in:
teknium1
2026-04-30 19:53:08 -07:00
committed by Teknium
parent ca9a61ae38
commit 447a2bba3a
2 changed files with 29 additions and 2 deletions

View File

@@ -1082,6 +1082,24 @@ class TestPluginCommandResultResolution:
monkeypatch.setattr("hermes_cli.plugins.asyncio.get_running_loop", lambda: _Loop())
assert resolve_plugin_command_result(_handler()) == "threaded-ok"
def test_running_loop_timeout_does_not_hang_forever(self, monkeypatch):
"""Threaded path must abort a hung async handler instead of blocking the caller."""
import asyncio as _asyncio
class _Loop:
pass
async def _slow_handler():
await _asyncio.sleep(10)
return "should-not-reach"
monkeypatch.setattr("hermes_cli.plugins.asyncio.get_running_loop", lambda: _Loop())
monkeypatch.setattr("hermes_cli.plugins._PLUGIN_COMMAND_AWAIT_TIMEOUT_SECS", 0.1)
import pytest
with pytest.raises(TimeoutError):
resolve_plugin_command_result(_slow_handler())
# ── TestPluginDispatchTool ────────────────────────────────────────────────