mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
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:
@@ -39,6 +39,8 @@ pub(super) struct PendingInteractiveReplayState {
|
||||
patch_approval_call_ids: HashSet<String>,
|
||||
patch_approval_call_ids_by_turn_id: HashMap<String, Vec<String>>,
|
||||
elicitation_requests: HashSet<ElicitationRequestKey>,
|
||||
request_permissions_call_ids: HashSet<String>,
|
||||
request_permissions_call_ids_by_turn_id: HashMap<String, Vec<String>>,
|
||||
request_user_input_call_ids: HashSet<String>,
|
||||
request_user_input_call_ids_by_turn_id: HashMap<String, Vec<String>>,
|
||||
}
|
||||
@@ -50,6 +52,7 @@ impl PendingInteractiveReplayState {
|
||||
EventMsg::ExecApprovalRequest(_)
|
||||
| EventMsg::ApplyPatchApprovalRequest(_)
|
||||
| EventMsg::ElicitationRequest(_)
|
||||
| EventMsg::RequestPermissions(_)
|
||||
| EventMsg::ExecCommandBegin(_)
|
||||
| EventMsg::PatchApplyBegin(_)
|
||||
| EventMsg::TurnComplete(_)
|
||||
@@ -64,6 +67,7 @@ impl PendingInteractiveReplayState {
|
||||
Op::ExecApproval { .. }
|
||||
| Op::PatchApproval { .. }
|
||||
| Op::ResolveElicitation { .. }
|
||||
| Op::RequestPermissionsResponse { .. }
|
||||
| Op::UserInputAnswer { .. }
|
||||
| Op::Shutdown
|
||||
)
|
||||
@@ -99,6 +103,13 @@ impl PendingInteractiveReplayState {
|
||||
request_id.clone(),
|
||||
));
|
||||
}
|
||||
Op::RequestPermissionsResponse { id, .. } => {
|
||||
self.request_permissions_call_ids.remove(id);
|
||||
Self::remove_call_id_from_turn_map(
|
||||
&mut self.request_permissions_call_ids_by_turn_id,
|
||||
id,
|
||||
);
|
||||
}
|
||||
// `Op::UserInputAnswer` identifies the turn, not the prompt call_id. The UI
|
||||
// answers queued prompts for the same turn in FIFO order, so remove the oldest
|
||||
// queued call_id for that turn.
|
||||
@@ -166,17 +177,26 @@ impl PendingInteractiveReplayState {
|
||||
.or_default()
|
||||
.push(ev.call_id.clone());
|
||||
}
|
||||
EventMsg::RequestPermissions(ev) => {
|
||||
self.request_permissions_call_ids.insert(ev.call_id.clone());
|
||||
self.request_permissions_call_ids_by_turn_id
|
||||
.entry(ev.turn_id.clone())
|
||||
.or_default()
|
||||
.push(ev.call_id.clone());
|
||||
}
|
||||
// A turn ending (normally or aborted/replaced) invalidates any unresolved
|
||||
// turn-scoped approvals and request_user_input prompts from that turn.
|
||||
// turn-scoped approvals, permission prompts, and request_user_input prompts.
|
||||
EventMsg::TurnComplete(ev) => {
|
||||
self.clear_exec_approval_turn(&ev.turn_id);
|
||||
self.clear_patch_approval_turn(&ev.turn_id);
|
||||
self.clear_request_permissions_turn(&ev.turn_id);
|
||||
self.clear_request_user_input_turn(&ev.turn_id);
|
||||
}
|
||||
EventMsg::TurnAborted(ev) => {
|
||||
if let Some(turn_id) = &ev.turn_id {
|
||||
self.clear_exec_approval_turn(turn_id);
|
||||
self.clear_patch_approval_turn(turn_id);
|
||||
self.clear_request_permissions_turn(turn_id);
|
||||
self.clear_request_user_input_turn(turn_id);
|
||||
}
|
||||
}
|
||||
@@ -228,6 +248,23 @@ impl PendingInteractiveReplayState {
|
||||
.remove(&ev.turn_id);
|
||||
}
|
||||
}
|
||||
EventMsg::RequestPermissions(ev) => {
|
||||
self.request_permissions_call_ids.remove(&ev.call_id);
|
||||
let mut remove_turn_entry = false;
|
||||
if let Some(call_ids) = self
|
||||
.request_permissions_call_ids_by_turn_id
|
||||
.get_mut(&ev.turn_id)
|
||||
{
|
||||
call_ids.retain(|call_id| call_id != &ev.call_id);
|
||||
if call_ids.is_empty() {
|
||||
remove_turn_entry = true;
|
||||
}
|
||||
}
|
||||
if remove_turn_entry {
|
||||
self.request_permissions_call_ids_by_turn_id
|
||||
.remove(&ev.turn_id);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
@@ -250,6 +287,9 @@ impl PendingInteractiveReplayState {
|
||||
EventMsg::RequestUserInput(ev) => {
|
||||
self.request_user_input_call_ids.contains(&ev.call_id)
|
||||
}
|
||||
EventMsg::RequestPermissions(ev) => {
|
||||
self.request_permissions_call_ids.contains(&ev.call_id)
|
||||
}
|
||||
_ => true,
|
||||
}
|
||||
}
|
||||
@@ -258,6 +298,7 @@ impl PendingInteractiveReplayState {
|
||||
!self.exec_approval_call_ids.is_empty()
|
||||
|| !self.patch_approval_call_ids.is_empty()
|
||||
|| !self.elicitation_requests.is_empty()
|
||||
|| !self.request_permissions_call_ids.is_empty()
|
||||
}
|
||||
|
||||
fn clear_request_user_input_turn(&mut self, turn_id: &str) {
|
||||
@@ -268,6 +309,14 @@ impl PendingInteractiveReplayState {
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_request_permissions_turn(&mut self, turn_id: &str) {
|
||||
if let Some(call_ids) = self.request_permissions_call_ids_by_turn_id.remove(turn_id) {
|
||||
for call_id in call_ids {
|
||||
self.request_permissions_call_ids.remove(&call_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_exec_approval_turn(&mut self, turn_id: &str) {
|
||||
if let Some(call_ids) = self.exec_approval_call_ids_by_turn_id.remove(turn_id) {
|
||||
for call_id in call_ids {
|
||||
@@ -317,6 +366,8 @@ impl PendingInteractiveReplayState {
|
||||
self.patch_approval_call_ids.clear();
|
||||
self.patch_approval_call_ids_by_turn_id.clear();
|
||||
self.elicitation_requests.clear();
|
||||
self.request_permissions_call_ids.clear();
|
||||
self.request_permissions_call_ids_by_turn_id.clear();
|
||||
self.request_user_input_call_ids.clear();
|
||||
self.request_user_input_call_ids_by_turn_id.clear();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user