@@ -28,6 +28,8 @@ pub(crate) struct AdapterOutcome {
2828 pub ( crate ) events : Vec < NormalizedEvent > ,
2929 /// Hook response body returned to the invoking agent process.
3030 pub ( crate ) response : Value ,
31+ /// Final permission request evaluated separately so its observable hook event stays unchanged.
32+ pub ( crate ) permission : Option < Result < ToolEvent , String > > ,
3133}
3234
3335pub ( super ) struct ClassificationRules < ' a > {
@@ -221,6 +223,57 @@ pub(crate) struct ToolPathSet {
221223 status : & ' static [ & ' static [ & ' static str ] ] ,
222224}
223225
226+ pub ( super ) fn permission_request (
227+ payload : & Value ,
228+ headers : & HeaderMap ,
229+ kind : AgentKind ,
230+ extractor : & dyn AgentPayloadExtractor ,
231+ ) -> Option < Result < ToolEvent , String > > {
232+ let event_name = extractor. event_name ( payload) ?;
233+ if normalize_name ( & event_name) != "permissionrequest" {
234+ return None ;
235+ }
236+ let session_id = match extractor. session_id ( payload, headers) {
237+ Some ( value) if !value. trim ( ) . is_empty ( ) => value,
238+ _ => {
239+ return Some ( Err (
240+ "permission request is missing a session identifier" . into ( )
241+ ) ) ;
242+ }
243+ } ;
244+ let tool = extractor. tool_call ( payload, headers, & event_name) ;
245+ let tool_call_id = match tool. tool_call_id {
246+ Some ( value) if !value. trim ( ) . is_empty ( ) => value,
247+ None if kind == AgentKind :: ClaudeCode => String :: new ( ) ,
248+ _ => {
249+ return Some ( Err (
250+ "permission request is missing a tool-call identifier" . into ( )
251+ ) ) ;
252+ }
253+ } ;
254+ let tool_name = match tool. tool_name {
255+ Some ( value) if !value. trim ( ) . is_empty ( ) => value,
256+ _ => return Some ( Err ( "permission request is missing a tool name" . into ( ) ) ) ,
257+ } ;
258+ let arguments = match tool. arguments {
259+ Some ( value) => value,
260+ None => return Some ( Err ( "permission request is missing tool arguments" . into ( ) ) ) ,
261+ } ;
262+ Some ( Ok ( ToolEvent {
263+ session_id,
264+ agent_kind : kind,
265+ event_name : event_name. clone ( ) ,
266+ tool_call_id,
267+ tool_name,
268+ subagent_id : tool. subagent_id ,
269+ arguments,
270+ result : Value :: Null ,
271+ status : tool. status ,
272+ payload : payload. clone ( ) ,
273+ metadata : extractor. metadata ( payload, headers, kind, & event_name) ,
274+ } ) )
275+ }
276+
224277/// Whether an extractor accepts the Claude installed-mode session header.
225278#[ derive( Clone , Copy ) ]
226279pub ( crate ) enum SessionHeaderPolicy {
0 commit comments