mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
fix(gateway): session.active_list reads waiting while a viewer request holds the turn
Greptile on #148880 (Some waiting sessions stay silent): the status came from shared controls only, so a turn blocked on a clarify batch, sudo, secret or vault prompt (session_server_requests) read working, and the TUI never announced a background session waiting on one.
This commit is contained in:
1 parent
3349029085
commit
787954a49f
2 files changed
+60
-2
No files matched your search
@@ -14,8 +14,12 @@ from hermes_state_runtime import RuntimeStoreError
|
||||
|
||||
def _status(live, handle, pending) -> str:
|
||||
if handle.execution_state == 'running':
|
||||
prompts = live.controls.snapshot(handle.ref.session_id, handle.execution_generation)
|
||||
return 'waiting' if prompts else 'working'
|
||||
from gateway.session_server_requests import open_requests
|
||||
sid = handle.ref.session_id
|
||||
# A question holds the turn: a shared control (approval) or a viewer request (clarify batch,
|
||||
# sudo, secret, vault) still open on the stream.
|
||||
asked = live.controls.snapshot(sid, handle.execution_generation) or open_requests(live.event_stream, sid)
|
||||
return 'waiting' if asked else 'working'
|
||||
# Admitted, not yet claimed by the drain: the turn exists, its agent has not started.
|
||||
return 'starting' if any(row['status'] == 'queued' for row in pending) else 'idle'
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
"""``session.active_list`` reads ``waiting`` while a viewer request holds the turn.
|
||||
|
||||
A TUI kept a session working in the background (``/new`` mid-turn) and polls this verb to tell the
|
||||
user when that session needs an answer. Clarify batches, sudo, secret and vault prompts are viewer
|
||||
requests (``gateway.session_server_requests``), not shared controls, so a status read from the
|
||||
controls alone said ``working`` while the turn sat blocked on the question.
|
||||
"""
|
||||
import asyncio
|
||||
import threading
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.gateway.test_authority_active_list import owner as listing_owner
|
||||
|
||||
listing = listing_owner # the active-list fixture, under a name the gateway conftest's `owner` does not shadow
|
||||
|
||||
|
||||
class _Peer:
|
||||
def __init__(self):
|
||||
self.frames = []
|
||||
|
||||
def write(self, frame, **_):
|
||||
self.frames.append(frame)
|
||||
return True
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_a_turn_blocked_on_a_viewer_request_reads_waiting(listing):
|
||||
from gateway.session_server_requests import ask_viewer, withdraw
|
||||
|
||||
await listing.submit('hi')
|
||||
events = listing.authority.sessions['chat'].event_stream
|
||||
peer = _Peer()
|
||||
events.fanout.attach(peer)
|
||||
assert (await listing.active())['chat']['status'] == 'working'
|
||||
|
||||
asked = threading.Thread(target=ask_viewer, args=(events, 'chat', 'sudo', {'command': 'id'}),
|
||||
kwargs={'timeout': 10}, daemon=True)
|
||||
asked.start()
|
||||
for _ in range(200):
|
||||
if peer.frames:
|
||||
break
|
||||
await asyncio.sleep(0.01)
|
||||
assert peer.frames, 'the sudo request never reached the viewer'
|
||||
|
||||
try:
|
||||
assert (await listing.active())['chat']['status'] == 'waiting'
|
||||
finally:
|
||||
withdraw(events, 'chat', 'sudo')
|
||||
asked.join(5)
|
||||
assert (await listing.active())['chat']['status'] == 'working'
|
||||
Reference in new issue
Block a user