feat(tui) render request_permissions calls (#14004)

## Summary
Adds support for tui rendering of request_permission calls

<img width="724" height="245" alt="Screenshot 2026-03-08 at 9 04 07 PM"
src="https://github.com/user-attachments/assets/e1997825-a496-4bfb-bbda-43d0006460a5"
/>


## Testing
- [x] Added snapshot test
This commit is contained in:
Dylan Hurd
2026-03-09 04:24:04 +00:00
committed by GitHub
parent 05332b0e96
commit 06f82c123c
8 changed files with 305 additions and 3 deletions
@@ -8,6 +8,7 @@ use codex_protocol::protocol::ExecCommandEndEvent;
use codex_protocol::protocol::McpToolCallBeginEvent;
use codex_protocol::protocol::McpToolCallEndEvent;
use codex_protocol::protocol::PatchApplyEndEvent;
use codex_protocol::request_permissions::RequestPermissionsEvent;
use codex_protocol::request_user_input::RequestUserInputEvent;
use super::ChatWidget;
@@ -17,6 +18,7 @@ pub(crate) enum QueuedInterrupt {
ExecApproval(ExecApprovalRequestEvent),
ApplyPatchApproval(ApplyPatchApprovalRequestEvent),
Elicitation(ElicitationRequestEvent),
RequestPermissions(RequestPermissionsEvent),
RequestUserInput(RequestUserInputEvent),
ExecBegin(ExecCommandBeginEvent),
ExecEnd(ExecCommandEndEvent),
@@ -55,6 +57,11 @@ impl InterruptManager {
self.queue.push_back(QueuedInterrupt::Elicitation(ev));
}
pub(crate) fn push_request_permissions(&mut self, ev: RequestPermissionsEvent) {
self.queue
.push_back(QueuedInterrupt::RequestPermissions(ev));
}
pub(crate) fn push_user_input(&mut self, ev: RequestUserInputEvent) {
self.queue.push_back(QueuedInterrupt::RequestUserInput(ev));
}
@@ -85,6 +92,7 @@ impl InterruptManager {
QueuedInterrupt::ExecApproval(ev) => chat.handle_exec_approval_now(ev),
QueuedInterrupt::ApplyPatchApproval(ev) => chat.handle_apply_patch_approval_now(ev),
QueuedInterrupt::Elicitation(ev) => chat.handle_elicitation_request_now(ev),
QueuedInterrupt::RequestPermissions(ev) => chat.handle_request_permissions_now(ev),
QueuedInterrupt::RequestUserInput(ev) => chat.handle_request_user_input_now(ev),
QueuedInterrupt::ExecBegin(ev) => chat.handle_exec_begin_now(ev),
QueuedInterrupt::ExecEnd(ev) => chat.handle_exec_end_now(ev),
+16
View File
@@ -47,6 +47,7 @@ use codex_protocol::items::PlanItem;
use codex_protocol::items::TurnItem;
use codex_protocol::items::UserMessageItem;
use codex_protocol::models::MessagePhase;
use codex_protocol::models::PermissionProfile;
use codex_protocol::openai_models::ModelPreset;
use codex_protocol::openai_models::ReasoningEffortPreset;
use codex_protocol::openai_models::default_input_modalities;
@@ -98,6 +99,7 @@ use codex_protocol::protocol::UndoCompletedEvent;
use codex_protocol::protocol::UndoStartedEvent;
use codex_protocol::protocol::ViewImageToolCallEvent;
use codex_protocol::protocol::WarningEvent;
use codex_protocol::request_permissions::RequestPermissionsEvent;
use codex_protocol::request_user_input::RequestUserInputEvent;
use codex_protocol::request_user_input::RequestUserInputQuestion;
use codex_protocol::request_user_input::RequestUserInputQuestionOption;
@@ -2746,6 +2748,20 @@ async fn handle_request_user_input_sets_pending_notification() {
);
}
#[tokio::test]
async fn handle_request_permissions_opens_approval_modal() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await;
chat.handle_request_permissions_now(RequestPermissionsEvent {
call_id: "call-1".to_string(),
turn_id: "turn-1".to_string(),
reason: Some("need workspace access".to_string()),
permissions: PermissionProfile::default(),
});
assert!(chat.bottom_pane.has_active_view());
}
#[tokio::test]
async fn plan_reasoning_scope_popup_mentions_selected_reasoning() {
let (mut chat, _rx, _op_rx) = make_chatwidget_manual(Some("gpt-5.1-codex-max")).await;