@@ -713,6 +713,13 @@ export interface ChatCallbacks {
713713 onDone : ( sessionId ?: string ) => void ;
714714 onError : ( error : string ) => void ;
715715 onToolProgress ?: ( tool : string ) => void ;
716+ /** Called when a tool call in the SSE stream requires human approval
717+ * (per the tool policy rules). The callback receives the tool name
718+ * and the command/parameters. The caller should create an approval
719+ * entry in the ApprovalInbox and wait for the user's decision before
720+ * allowing the tool to proceed. If the callback is not provided,
721+ * tool calls proceed without approval (backward compatibility). */
722+ onToolApprovalRequired ?: ( toolName : string , command : string ) => void ;
716723 onUsage ?: ( usage : {
717724 promptTokens : number ;
718725 completionTokens : number ;
@@ -1242,12 +1249,25 @@ function sendMessageViaApi(
12421249
12431250 /** Handle a custom SSE event (non-data lines with `event:` prefix). */
12441251 function processCustomEvent ( eventType : string , data : string ) : void {
1245- if ( eventType === "hermes.tool.progress" && cb . onToolProgress ) {
1252+ if ( eventType === "hermes.tool.progress" ) {
12461253 try {
12471254 const payload = JSON . parse ( data ) ;
12481255 const label = payload . label || payload . tool || "" ;
12491256 const emoji = payload . emoji || "" ;
1250- cb . onToolProgress ( emoji ? `${ emoji } ${ label } ` : label ) ;
1257+ if ( cb . onToolProgress ) {
1258+ cb . onToolProgress ( emoji ? `${ emoji } ${ label } ` : label ) ;
1259+ }
1260+ // Fire approval callback if the tool requires it.
1261+ // The Hermes gateway can include `requires_approval: true` in
1262+ // the tool progress event when the tool matches an approval rule.
1263+ // The desktop creates an ApprovalInbox entry and waits for the
1264+ // user's decision. The gateway itself doesn't block — it's the
1265+ // desktop's responsibility to intercept and pause if needed.
1266+ if ( payload . requires_approval && cb . onToolApprovalRequired ) {
1267+ const toolName = payload . tool || label || "unknown" ;
1268+ const command = payload . command || payload . args || "" ;
1269+ cb . onToolApprovalRequired ( toolName , command ) ;
1270+ }
12511271 } catch {
12521272 /* malformed — skip */
12531273 }
0 commit comments