Skip to content

feat(api-server): expose run approval events - #20311

Closed
hanzckernel wants to merge 1 commit into
NousResearch:mainfrom
hanzckernel:fix/api-server-run-approvals
Closed

feat(api-server): expose run approval events#20311
hanzckernel wants to merge 1 commit into
NousResearch:mainfrom
hanzckernel:fix/api-server-run-approvals

Conversation

@hanzckernel

Copy link
Copy Markdown
Contributor

Summary

Adds first-class approval support to the API Server /v1/runs control plane so Web UI clients can surface and resolve dangerous-command approval gates without scraping assistant text or sending /approve as a normal chat message.

Changes:

  • Emits structured approval.request events on GET /v1/runs/{run_id}/events
  • Adds POST /v1/runs/{run_id}/approval for once | session | always | deny
  • Emits approval.responded after successful resolution
  • Advertises approval support in /v1/capabilities
  • Binds API runs into the existing approval/session context using contextvars rather than process-global env mutation
  • Cleans up approval callbacks/session mappings on completion, stop/cancel, and orphan sweep
  • Adds regression tests for request event + response unblocking and no-pending response handling

Why

Downstream WUI issue: EKKOLearnAI/hermes-studio#368

The Web UI path uses:

  • POST /v1/runs
  • GET /v1/runs/{run_id}/events

Without an API-level approval event/response path, WUI cannot reliably know that an approval is pending or unblock the in-flight run. DOM-scanning or sending /approve as chat text is brittle and targets the wrong control plane.

Fixes #15802

API shape

Approval request event:

{
  "event": "approval.request",
  "run_id": "run_...",
  "timestamp": 1234567890.0,
  "command": "...",
  "pattern_key": "...",
  "pattern_keys": ["..."],
  "description": "...",
  "choices": ["once", "session", "always", "deny"]
}

Approval response:

POST /v1/runs/{run_id}/approval
{
  "choice": "once",
  "all": false
}

Successful response:

{
  "object": "hermes.run.approval_response",
  "run_id": "run_...",
  "choice": "once",
  "resolved": 1
}

Tests

Targeted suite:

scripts/run_tests.sh tests/gateway/test_api_server.py tests/gateway/test_api_server_runs.py tests/gateway/test_api_server_toolset.py tests/gateway/test_api_server_jobs.py tests/gateway/test_api_server_bind_guard.py tests/gateway/test_api_server_multimodal.py tests/gateway/test_api_server_normalize.py tests/tools/test_approval.py tests/tools/test_approval_heartbeat.py tests/acp/test_approval_isolation.py -o 'addopts=' -q

Result:

403 passed, 151 warnings

@alt-glitch alt-glitch added type/feature New feature or request comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists labels May 5, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Related: #6059 (open PR) addresses the same issue (#15802) with a similar approach. This PR appears to supersede #6059 with a more complete implementation (contextvar-based binding, cleanup on stop/cancel, capabilities endpoint).

@teknium1

teknium1 commented May 8, 2026

Copy link
Copy Markdown
Contributor

Salvaged onto current main via PR #21899 (#21899), merged as commit 839cdd1. Your commit was cherry-picked with authorship preserved via rebase-merge — git log shows you as the author of feat(api-server): expose run approval events.

Added one follow-up commit on top: the new _is_gateway_approval_context() widened the gateway classification to any call with HERMES_SESSION_PLATFORM bound via contextvars, but cron/scheduler.py binds that same contextvar for delivery routing on cron jobs that originate from a gateway platform. That would route cron-from-telegram/discord/etc. through submit_pending with no listener, hanging the job instead of honoring approvals.cron_mode. Short-circuited on HERMES_CRON_SESSION before the gateway check and added regression coverage in TestCronWithGatewayOrigin.

Thanks for this — clean mirror of the run.py / telegram / discord pattern, and the contextvar-based approach was exactly right for concurrent API runs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/gateway Gateway runner, session dispatch, delivery P2 Medium — degraded but workaround exists type/feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: API Server/WebUI path cannot surface dangerous command approval prompts

3 participants