Conversation
- hermes peer run starts a canonical Bot Chat turn through POST /v1/runs and returns a run_id immediately; hermes peer status polls it without holding the HTTP connection. - POST /v1/runs admits an Idempotency-Key: a replay resolves before the concurrency cap so a retry after a lost 202 returns the original run instead of a 429, and the session transcript is reloaded after admission. - Serialize run admission under a per-adapter asyncio.Lock so two concurrent same-key requests resolve to one run instead of two (fixes the check/register TOCTOU race across the session-history reload). - Tests: peer run/status against a fake peer; runs endpoint replay, conflict, session-history load, and the concurrent same-key path.
Solid design overall: resolving a replay before the concurrency gate (
Tests covering the contended-wait race via |
What
Adds peer async dispatch (Hermes peer run/status) with idempotent admission to the API server's
/v1/runsendpoint.gateway/platforms/api_server.py: idempotent admission for/v1/runs— a lock serializes concurrent POSTs so the same idempotency key cannot create duplicate runs. The idempotency key is registered before the history read, closing the race where two same-key requests both pass the check and both create a run.hermes_cli/subcommands/peer.py:peer run/peer statussubcommands.tests/gateway/test_api_server_runs.py+ new concurrent same-key race test;tests/hermes_cli/test_peer_cmd.py.Why
Previously, the peer async work lived as an uncommitted diff. This promotes it to a reviewable change, and fixes a real race (idempotency key registered after the await, so concurrent same-key POSTs could double-create runs).
Test
tests/gateway/test_api_server_runs.py+tests/hermes_cli/test_peer_cmd.py: 39 passed (incl. new race test)tests/gateway/test_api_server.py+test_api_server_active_work_drain.py: 129 passed