fix: generate non-empty approval_id when gateway approval.request omits it (#6008)#6168
fix: generate non-empty approval_id when gateway approval.request omits it (#6008)#6168webtecnica wants to merge 1 commit into
Conversation
|
I traced this against both the WebUI respond path and the agent's approval handler on the read-only agent source, and the fix is correct — the contract claim in your description checks out. A couple of notes to give reviewers confidence, plus one optional robustness idea. The bug is real and this is the right layerThe empty- if _run_id:
if not approval_id:
return bad(handler, "approval_id is required for gateway approvals")So once a Contract verified: the agent resolves by run_id, not approval_idThis is the part worth confirming since it's a cross-repo assumption. The agent's run_id = request.match_info["run_id"]
status = self._run_statuses.get(run_id)
...
approval_session_key = self._run_approval_sessions.get(run_id)
...
resolved = resolve_gateway_approval(approval_session_key, choice, resolve_all=resolve_all)And on the emit side ( Consistency within the streaming path holdsIn the legacy relay path ( Optional: a run-scoped deterministic id would be more robust than uuid4One edge case: because the id is minted fresh on every call to Since there's normally one pending approval per run at a time, deriving the fallback deterministically from |
34e8f54 to
143e742
Compare
🔬 Gate certification — GREEN ✅ (full gate at head
|
…6180) + state-dir test isolation (#6305) (#6332) * fix: catch unhandled exception in POST /api/updates/check (defensive hardening) (#6180) * fix: generate non-empty approval_id when gateway approval.request omits it (#6008) (#6168) * chore: mark update-check try/except as defensive-only guard, drop #6086 linkage Per maintainer review, the try/except wrapper is defense-in-depth only — it does NOT fix #6086 (root cause is signal/process-group reaping). Updated log message and added inline comment to make this explicit. Leave #6086 open. * test: isolate state-dir probes from user state * docs(changelog): stamp #6168 approval_id, #6180 update-check guard, #6305 test isolation --------- Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com> Co-authored-by: webtecnica <webtecnica@users.noreply.github.com> Co-authored-by: pxxD1998 <214340659+pxxD1998@users.noreply.github.com> Co-authored-by: nesquena-hermes <agent@nesquena-hermes>
|
Shipped in exp-v0.52.117 (experimental channel) via release #6332. Thanks @webtecnica! 🎉 The gateway now synthesizes a non-empty Gate: full pytest suite (13443 passed / 0 failed), Codex regression gate |
Closes #6008
Problem
When Hermes Agent emits an
approval.requestSSE event without anapproval_idoridfield,_gateway_runs_approval_event()inapi/gateway_chat.pyproduces an empty string forapproval_id. This causes:approval_id: ""POST /api/approval/respondwith emptyapproval_idif not approval_id: return bad(...)Root cause
The Hermes Agent API server emits
approval.requestevents with onlyrun_id,timestamp,choices— but noapproval_id:The WebUI adapter then does:
Fix
Generate a
uuid.uuid4().hexas the localapproval_idwhen the upstream payload provides neitherapproval_idnorid. This is consistent with howroute_approvals.submit_pendingalready handles the same situation for local approvals:The Hermes Agent resolves approvals by
run_id, notapproval_id, so this ID is purely a WebUI-local correlation key.Verification