Vai al contenuto principale
Alcune chiamate a tool sono troppo importanti per essere consentite alla cieca e troppo utili per essere bandite del tutto — una scrittura su un database di produzione, un bonifico, un *.delete su dati reali. Per quelle vuoi una persona nel loop: metti in attesa la chiamata, lascia che un umano guardi, poi procedi solo su un sì. È esattamente ciò che fa il verdetto pending_approval. Questa pagina copre il flusso di approvazione degli agent human-in-the-loop da capo a fondo: come emerge una chiamata in attesa, come un revisore la risolve dalla console o da un webhook, e come l’agent ri-invia la chiamata approvata. Per dove il verdetto si colloca nella grammatica delle regole, vedi Regole del Firewall; per il modello di policy che lo circonda, vedi la Panoramica del Firewall.

1. Com’è fatta una chiamata in attesa

Quando una regola si risolve in pending_approval, il motore accoda un record di approvazione e la chiamata non raggiunge il tool. Il relay restituisce HTTP 400 con error.code firewall_approval_pending; l’id di approvazione su cui l’agent farà polling è portato nell’error.message leggibile:
{
  "error": {
    "code": "firewall_approval_pending",
    "message": "tool \"db.write\" held for approval (…) — resolve approval 507f1f77bcf86cd799439011 and retry with header X-OrcaRouter-Firewall-Approval"
  }
}
Gli error.metadata strutturati (quando presenti) portano il dettaglio della motivazione del verdetto — reason_code, factors, risk_score — non l’id di approvazione. Estrai l’id dal messaggio, o ottienilo dall’helper dell’SDK sotto. L’hold è immediato — non c’è alcun long-poll inline che blocca la tua richiesta. L’agent riceve indietro l’id, la chiamata è parcheggiata lato server nello stato pending, e la risoluzione avviene fuori banda.
Una chiamata in attesa è registrata come un evento del firewall con verdetto pending_approval, quindi è filtrabile nel log degli eventi proprio accanto agli eventi deny — puoi sempre vedere cosa è stato messo in attesa e, tramite il record di approvazione, cosa è stato risolto.

2. Un esempio concreto

Scrivi una regola che mette in attesa qualsiasi scrittura su una connessione di produzione per un umano:
{
  "label": "hold prod db writes",
  "tool_name_glob": "db.write",
  "verdict": "pending_approval",
  "args_match_json": "{\"clauses\":[{\"path\":\"$.connection\",\"op\":\"eq\",\"value\":\"prod\"}]}"
}
Ora il ciclo di vita:
1

L'agent chiama il tool

L’agent emette db.write contro prod. La regola corrisponde, il motore mette in attesa la chiamata, e il relay restituisce 400 firewall_approval_pending con un approval_id.
2

Un umano (o il tuo sistema) revisiona

Un revisore risolve l’approvazione — nella console o tramite un webhook callback firmato (vedi §3).
3

L'agent fa polling fino alla risoluzione

L’agent fa polling sull’id di approvazione finché il suo stato non è più pending (vedi §4).
4

L'agent ri-invia con l'header di approvazione

Su approved, l’agent ri-emette esattamente la stessa chiamata una volta, portando un header monouso X-OrcaRouter-Firewall-Approval. Il motore reclama l’approvazione e lascia passare quella sola chiamata.

3. Risolvere un’approvazione

Ci sono due modi per trasformare un’approvazione pending in approved o rejected. Entrambi condividono una garanzia vince-la-prima-decisione — la prima risoluzione che atterra è applicata atomicamente, e qualsiasi risoluzione successiva (o un duplicato) è un no-op idempotente che restituisce 200.
La scheda Approvals elenca gli hold in attesa dal più vecchio, ciascuno con il nome del tool e una riga “Held because…” che nomina la policy e la clausola della regola che è scattata. (Gli argomenti grezzi della chiamata non sono memorizzati sul record di approvazione — solo il nome del tool, la provenienza e un hash degli args — così il revisore decide dal tool più la clausola corrisposta.) Un revisore ne risolve uno con:
PATCH /api/workspace/firewall/approvals/:id
{ "decision": "approved", "reason": "verified change ticket #4821" }
decision deve essere approved o rejected. Questa rotta è UserAuth (la sessione di console del revisore) e gated a Developer+ — l’identità del tuo revisore è l’autorizzazione, quindi non è coinvolto alcun segreto condiviso. Le risoluzioni vengono scritte nel log di audit del workspace.
Per cablare le approvazioni in un sistema esterno (un’approvazione Slack, un workflow di ticketing), configura un segreto del webhook di approvazione per il workspace, poi fai POST della decisione indietro:
POST /api/v1/firewall/approvals/:id/callback
{ "decision": "approved", "reason": "auto-approved by change-control bot" }
Il callback è autenticato tramite HMAC-SHA256: imposta l’header X-Orca-Signature: sha256=<hex> sull’HMAC di <approval_id>\n<raw_body> con chiave il segreto del webhook di approvazione del tuo workspace. L’id fa parte del materiale firmato, quindi una firma catturata non può essere riprodotta contro un’approvazione diversa. Senza un segreto configurato, la risoluzione guidata da callback viene rifiutata — risolvi invece tramite il PATCH della console.
Configurare un percorso di rifiuto del webhook di approvazione è il default sicuro per le esecuzioni non presidiate: se nessun umano risolve un hold, la chiamata resta semplicemente parcheggiata e l’agent continua a fare polling. Una chiamata in attesa non diventa mai silenziosamente un allow.

4. Fai polling, poi ri-invia

Il lato agent è un loop di polling seguito da un solo ri-invio. Fai polling sullo stato di approvazione con un token con scope firewall-gateway:
GET /api/v1/firewall/approvals/:id
Questa rotta richiede un token con lo scope firewall-gateway (la stessa chiave del gateway dedicata usata per /evaluate e il gateway MCP); una normale chiave di relay riceve 403. Restituisce il documento di approvazione — aspetta finché state non è approved o rejected anziché pending. Un id cross-workspace o sconosciuto restituisce 404, senza mai rivelare che esiste a un altro tenant. Ri-invia una volta che lo stato è approved: ri-emetti la stessa chiamata a tool, portando l’id di approvazione in un header monouso:
X-OrcaRouter-Firewall-Approval: 507f1f77bcf86cd799439011
Il motore reclama atomicamente l’approvazione — monouso. Il primo ri-invio che la porta viene fatto passare quell’unica volta; una riproduzione dello stesso header trova l’approvazione già consumata ed è messa di nuovo in attesa, non consentita. Un’approvazione rejected non è mai reclamabile, quindi l’agent dovrebbe trattare il rifiuto come un deny terminale e scegliere un altro percorso.
L’helper HITL dell’SDK MCP di OrcaRouter esegue questo loop di polling-poi-ri-invio per te: quando evaluate restituisce pending_approval, fa polling su GET /api/v1/firewall/approvals/:id e ri-invia con l’header di approvazione all’approvazione — devi solo scrivere la regola e assegnare il revisore.

5. Stati e ruoli in breve

StatoSignificatoAzione dell’agent
pendingIn attesa, in attesa di una decisioneContinua a fare polling
approvedIl revisore ha detto sìRi-invia una volta con l’header
rejectedIl revisore ha detto noTrattalo come un deny
AzioneRottaAuth · ruolo
Elencare la codaGET /api/workspace/firewall/approvalsUserAuth · Developer+
RisolverePATCH /api/workspace/firewall/approvals/:idUserAuth · Developer+
Webhook callbackPOST /api/v1/firewall/approvals/:id/callbackFirmato con HMAC
Fare polling sullo statoGET /api/v1/firewall/approvals/:idToken del gateway

6. Dove si inseriscono le approvazioni

Un verdetto pending_approval è uno dei verdetti del firewall — si compone con tutto il resto in una policy. Due interazioni da conoscere:
  • La quarantine di una skill escala a un hold. Se una chiamata a tool messa in attesa è di proprietà di una skill in quarantine, qualsiasi cosa al di sotto di un deny viene escalata automaticamente a pending_approval — la quarantine e le approvazioni sono lo stesso cancello di revisione da due direzioni.
  • La shadow mode la appiattisce. In shadow mode un verdetto pending_approval viene declassato a audit e loggato come [shadow] would …, così puoi misurare quanto spesso un hold scatterebbe prima che inizi a governare il traffico reale.
Questo è il controllo giusto per le chiamate a tool pericolose e l’agenzia eccessiva — i casi in cui un verdetto di “chiedi a un umano” batte sia allow sia deny.

Dove andare dopo

Verdetti

Tutti e sei i verdetti del firewall e il verdetto di default.

Chiavi del gateway

Conia il token firewall-gateway usato per fare polling sulle approvazioni.

Shadow mode

Misura un hold prima che governi il traffico reale.

Riferimento delle regole

Scrivi la regola che produce un verdetto pending_approval.