feat(auto-review) Handle request_permissions calls (#18393)

## Summary
When auto-review is enabled, it should handle request_permissions tool.
We'll need to clean up the UX but I'm planning to do that in a separate
pass

## Testing
- [x] Ran locally
<img width="893" height="396" alt="Screenshot 2026-04-17 at 1 16 13 PM"
src="https://github.com/user-attachments/assets/4c045c5f-1138-4c6c-ac6e-2cb6be4514d8"
/>

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Dylan Hurd
2026-04-20 21:48:57 -07:00
committed by GitHub
co-authored by Codex
parent 543a08dac9
commit 86535c9901
31 changed files with 2232 additions and 370 deletions
+6 -36
View File
@@ -26,15 +26,14 @@ use codex_protocol::user_input::UserInput;
use serde_json::Value;
use std::time::Duration;
use tokio::sync::Mutex;
use tokio::sync::oneshot;
use tokio::time::timeout;
use tokio_util::sync::CancellationToken;
use crate::config::Config;
use crate::guardian::GuardianApprovalRequest;
use crate::guardian::new_guardian_review_id;
use crate::guardian::review_approval_request_with_cancel;
use crate::guardian::routes_approval_to_guardian;
use crate::guardian::spawn_approval_request_review;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_ACCEPT;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_ACCEPT_FOR_SESSION;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_DECLINE_SYNTHETIC;
@@ -457,7 +456,7 @@ async fn handle_exec_approval(
} = event;
let decision = if routes_approval_to_guardian(parent_ctx) {
let review_cancel = cancel_token.child_token();
let review_rx = spawn_guardian_review(
let review_rx = spawn_approval_request_review(
Arc::clone(parent_session),
Arc::clone(parent_ctx),
new_guardian_review_id(),
@@ -565,7 +564,7 @@ async fn handle_patch_approval(
})
.collect::<Vec<_>>()
.join("\n");
let review_rx = spawn_guardian_review(
let review_rx = spawn_approval_request_review(
Arc::clone(parent_session),
Arc::clone(parent_ctx),
new_guardian_review_id(),
@@ -686,7 +685,7 @@ async fn maybe_auto_review_mcp_request_user_input(
)
.await;
let review_cancel = cancel_token.child_token();
let review_rx = spawn_guardian_review(
let review_rx = spawn_approval_request_review(
Arc::clone(parent_session),
Arc::clone(parent_ctx),
new_guardian_review_id(),
@@ -730,36 +729,6 @@ async fn maybe_auto_review_mcp_request_user_input(
})
}
fn spawn_guardian_review(
session: Arc<Session>,
turn: Arc<TurnContext>,
review_id: String,
request: GuardianApprovalRequest,
retry_reason: Option<String>,
cancel_token: CancellationToken,
) -> oneshot::Receiver<ReviewDecision> {
let (tx, rx) = oneshot::channel();
std::thread::spawn(move || {
let Ok(runtime) = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()
else {
let _ = tx.send(ReviewDecision::Denied);
return;
};
let decision = runtime.block_on(review_approval_request_with_cancel(
&session,
&turn,
review_id,
request,
retry_reason,
cancel_token,
));
let _ = tx.send(decision);
});
rx
}
async fn handle_request_permissions(
codex: &Codex,
parent_session: &Arc<Session>,
@@ -772,7 +741,8 @@ async fn handle_request_permissions(
reason: event.reason,
permissions: event.permissions,
};
let response_fut = parent_session.request_permissions(parent_ctx, call_id.clone(), args);
let response_fut =
parent_session.request_permissions(parent_ctx, call_id.clone(), args, cancel_token.clone());
let response =
await_request_permissions_with_cancel(response_fut, parent_session, &call_id, cancel_token)
.await;