Zum Hauptinhalt springen
Manche Tool-Calls sind zu folgenschwer, um sie blind zu erlauben, und zu nützlich, um sie pauschal zu verbieten — ein Produktions-Datenbank-Write, eine Überweisung, ein *.delete auf echten Daten. Für diese wollen Sie einen Menschen in der Schleife: den Aufruf zurückhalten, einen Menschen draufschauen lassen, dann nur bei einem Ja fortfahren. Genau das tut das pending_approval-Verdikt. Diese Seite behandelt den Human-in-the-Loop-Agenten-Freigabe-Flow von Ende zu Ende: wie ein zurückgehaltener Aufruf auftaucht, wie ein Prüfer ihn aus der Konsole oder einem Webhook auflöst, und wie der Agent den genehmigten Aufruf erneut einreicht. Wo das Verdikt in der Regelgrammatik sitzt, siehe Firewall-Regeln; für das Policy-Modell darum herum siehe den Firewall-Überblick.

1. Wie ein zurückgehaltener Aufruf aussieht

Wenn eine Regel auf pending_approval auflöst, reiht die Engine einen Approval-Datensatz ein und der Aufruf erreicht das Tool nicht. Das Relay gibt HTTP 400 mit error.code firewall_approval_pending zurück; die Approval-ID, auf die der Agent pollen wird, ist in der menschenlesbaren error.message enthalten:
{
  "error": {
    "code": "firewall_approval_pending",
    "message": "tool \"db.write\" held for approval (…) — resolve approval 507f1f77bcf86cd799439011 and retry with header X-OrcaRouter-Firewall-Approval"
  }
}
Die strukturierte error.metadata (sofern vorhanden) trägt das Begründungsdetail des Verdikts — reason_code, factors, risk_score — nicht die Approval-ID. Parsen Sie die ID aus der Nachricht, oder holen Sie sie aus dem SDK-Helper unten. Der Hold ist sofortig — es gibt keinen Inline-Long-Poll, der Ihren Request blockiert. Der Agent erhält die ID zurück, der Aufruf wird serverseitig im pending-Zustand geparkt, und die Auflösung geschieht out-of-band.
Ein zurückgehaltener Aufruf wird als Firewall-Event mit Verdikt pending_approval aufgezeichnet, sodass er im Events-Log direkt neben deny-Events filterbar ist — Sie können immer sehen, was zurückgehalten wurde und, über den Approval-Datensatz, was aufgelöst wurde.

2. Ein konkretes Beispiel

Verfassen Sie eine Regel, die jeden Write auf eine Produktionsverbindung für einen Menschen zurückhält:
{
  "label": "hold prod db writes",
  "tool_name_glob": "db.write",
  "verdict": "pending_approval",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.connection\",\"op\":\"eq\",\"value\":\"prod\"}]}"
}
Nun der Lebenszyklus:
1

Agent ruft das Tool auf

Der Agent stellt db.write gegen prod aus. Die Regel matcht, die Engine hält den Aufruf zurück, und das Relay gibt 400 firewall_approval_pending mit einer approval_id zurück.
2

Ein Mensch (oder Ihr System) prüft

Ein Prüfer löst das Approval auf — in der Konsole oder über einen signierten Webhook-Callback (siehe §3).
3

Agent pollt bis aufgelöst

Der Agent pollt die Approval-ID, bis ihr Zustand nicht mehr pending ist (siehe §4).
4

Agent reicht mit dem Approval-Header erneut ein

Bei approved stellt der Agent denselben Aufruf einmal erneut aus, mit einem einmal nutzbaren X-OrcaRouter-Firewall-Approval-Header. Die Engine beansprucht das Approval und lässt diesen einen Aufruf durch.

3. Ein Approval auflösen

Es gibt zwei Wege, ein pending-Approval in approved oder rejected zu verwandeln. Beide teilen eine first-decision-wins-Garantie — die erste Auflösung, die landet, wird atomar angewendet, und jede spätere Auflösung (oder eine Duplikat) ist ein idempotenter No-op, der 200 zurückgibt.
Der Approvals-Tab listet ausstehende Holds ältest-zuerst, jeder mit dem Tool-Namen und einer „Held because…”-Zeile, die die Policy und die Regel-Klausel benennt, die gefeuert hat. (Die rohen Aufruf-Argumente werden nicht auf dem Approval-Datensatz gespeichert — nur der Tool-Name, die Provenienz und ein Args-Hash — sodass der Prüfer aus dem Tool plus der gematchten Klausel entscheidet.) Ein Prüfer löst eines auf mit:
PATCH /api/workspace/firewall/approvals/:id
{ "decision": "approved", "reason": "verified change ticket #4821" }
decision muss approved oder rejected sein. Diese Route ist UserAuth (die Konsolen-Session des Prüfers) und auf Developer+ gegated — die Identität Ihres Prüfers ist die Autorisierung, sodass kein Shared Secret beteiligt ist. Auflösungen werden ins Workspace-Audit-Log geschrieben.
Um Approvals in ein externes System zu verdrahten (eine Slack-Freigabe, einen Ticketing-Workflow), konfigurieren Sie ein Approval-Webhook-Secret für den Workspace und POSTen dann die Entscheidung zurück:
POST /api/v1/firewall/approvals/:id/callback
{ "decision": "approved", "reason": "auto-approved by change-control bot" }
Der Callback wird über HMAC-SHA256 authentifiziert: setzen Sie den X-Orca-Signature: sha256=<hex>-Header auf den HMAC von <approval_id>\n<raw_body>, geschlüsselt mit dem Approval-Webhook-Secret Ihres Workspaces. Die ID ist Teil des signierten Materials, sodass eine abgefangene Signatur nicht gegen ein anderes Approval wiederholt werden kann. Ohne konfiguriertes Secret wird die callback-getriebene Auflösung abgewiesen — lösen Sie stattdessen über das Konsolen-PATCH auf.
Das Konfigurieren eines Approval-Webhook-Ablehnungs-Pfads ist der sichere Default für unbeaufsichtigte Läufe: wenn kein Mensch einen Hold auflöst, bleibt der Aufruf einfach geparkt und der Agent pollt weiter. Ein zurückgehaltener Aufruf wird nie stillschweigend zu einem Allow.

4. Pollen, dann erneut einreichen

Die Agentenseite ist eine Poll-Schleife gefolgt von einem Re-submit. Pollen Sie den Approval-Zustand mit einem firewall-gateway-scoped Token:
GET /api/v1/firewall/approvals/:id
Diese Route erfordert ein Token mit dem Firewall-Gateway-Scope (derselbe dedizierte Gateway-Key, der für /evaluate und das MCP-Gateway genutzt wird); ein regulärer Relay-Key bekommt 403. Sie gibt das Approval-Dokument zurück — warten Sie, bis state approved oder rejected ist, statt pending. Eine cross-Workspace- oder unbekannte ID gibt 404 zurück und offenbart einem anderen Tenant nie, dass sie existiert. Erneut einreichen, sobald der Zustand approved ist: stellen Sie denselben Tool-Call erneut aus, mit der Approval-ID in einem einmal nutzbaren Header:
X-OrcaRouter-Firewall-Approval: 507f1f77bcf86cd799439011
Die Engine beansprucht atomar das Approval — einmal nutzbar. Der erste Re-submit, der es trägt, wird dieses eine Mal durchgelassen; ein Replay desselben Headers findet das Approval bereits verbraucht und wird erneut zurückgehalten, nicht erlaubt. Ein rejected-Approval ist nie beanspruchbar, sodass der Agent eine Ablehnung als terminales deny behandeln und einen anderen Weg wählen sollte.
Der HITL-Helper des OrcaRouter-MCP-SDK führt diese Pollen-dann-erneut-einreichen-Schleife für Sie aus: wenn evaluate pending_approval zurückgibt, pollt er GET /api/v1/firewall/approvals/:id und reicht bei Genehmigung mit dem Approval-Header erneut ein — Sie verfassen nur die Regel und besetzen den Prüfer.

5. Zustände und Rollen auf einen Blick

ZustandBedeutungAgent-Aktion
pendingZurückgehalten, wartet auf eine EntscheidungWeiter pollen
approvedPrüfer sagte jaEinmal mit dem Header erneut einreichen
rejectedPrüfer sagte neinAls deny behandeln
AktionRouteAuth · Rolle
Die Queue auflistenGET /api/workspace/firewall/approvalsUserAuth · Developer+
AuflösenPATCH /api/workspace/firewall/approvals/:idUserAuth · Developer+
Webhook-CallbackPOST /api/v1/firewall/approvals/:id/callbackHMAC-signiert
Zustand pollenGET /api/v1/firewall/approvals/:idGateway-Token

6. Wo Approvals hineinpassen

Ein pending_approval-Verdikt ist eines der Firewall-Verdikte — es komponiert sich mit allem anderen in einer Policy. Zwei Interaktionen, die zu kennen sich lohnt:
  • Skill-Quarantäne eskaliert zu einem Hold. Wenn ein zurückgehaltener Tool-Call einem quarantänierten Skill gehört, wird alles unterhalb eines Denys automatisch zu pending_approval eskaliert — Quarantäne und Approvals sind dasselbe Review-Gate aus zwei Richtungen.
  • Shadow-Mode flacht es ab. Im Shadow-Mode wird ein pending_approval-Verdikt auf audit herabgestuft und als [shadow] would … geloggt, sodass Sie messen können, wie oft ein Hold feuern würde, bevor er beginnt, echten Traffic zu gaten.
Dies ist die richtige Kontrolle für gefährliche Tool-Calls und übermäßige Handlungsmacht — die Fälle, in denen ein Verdikt von „frage einen Menschen” sowohl allow als auch deny schlägt.

Wohin als Nächstes

Verdikte

Alle sechs Firewall-Verdikte und das Default-Verdikt.

Gateway-Keys

Prägen Sie das Firewall-Gateway-Token, das zum Pollen von Approvals genutzt wird.

Shadow-Mode

Messen Sie einen Hold, bevor er echten Traffic gatet.

Regel-Referenz

Verfassen Sie die Regel, die ein pending_approval-Verdikt erzeugt.