mirror of
https://github.com/openai/codex.git
synced 2026-10-19 16:17:49 +00:00
## Why Client permission definitions and constraints can differ from those on the connected app server. Accepted permission changes also need to survive task transitions before their settings notifications arrive. ## What changed - Discover permission profiles and availability from the connected server and apply selections through `thread/settings/update`, including custom profiles. - Adopt the server's effective permission settings instead of reapplying local definitions or constraints. - Retain accepted selections and effective approval settings across new tasks, forks, side conversations, directory changes, reconnects, and safety retries without blocking navigation on a settings notification. - Recognize the current built-in permission preset when the server supplies an unnamed profile. ## Testing Add regression coverage for conflicting client/server profile definitions, rejected and unchanged selections, consecutive requests with omitted approval settings, and permission carryover before confirmation. Extend discovery and menu tests to verify server-provided availability and unnamed-profile highlighting. GitOrigin-RevId: bcd767b58dc92dc4f945189078e51e6e5fce6d24
78 lines
3.0 KiB
Rust
78 lines
3.0 KiB
Rust
//! Keep named-profile discovery responsive and discard replies after closing or changing scope.
|
|
|
|
use super::*;
|
|
use crate::permission_discovery::PermissionDiscovery;
|
|
|
|
pub(super) const VIEW_ID: &str = "permission-profiles";
|
|
|
|
impl ChatWidget {
|
|
pub(crate) fn retain_input_after_failed_permission_selection(&mut self) {
|
|
self.input_queue.recovered_queue |= self.input_queue.has_queued_follow_up_messages()
|
|
|| !self.input_queue.pending_steers.is_empty();
|
|
if let Some(message) = self.initial_user_message.take() {
|
|
self.restore_user_message_to_composer(message);
|
|
}
|
|
}
|
|
pub(crate) fn request_permission_profiles(&mut self) {
|
|
self.invalidate_permission_discovery();
|
|
let request_id = uuid::Uuid::new_v4();
|
|
self.permission_popup_request_id = Some(request_id);
|
|
self.bottom_pane.show_selection_view(SelectionViewParams {
|
|
view_id: Some(VIEW_ID),
|
|
title: Some("Update Model Permissions".into()),
|
|
items: vec![SelectionItem {
|
|
name: "Loading permission profiles…".to_string(),
|
|
is_disabled: true,
|
|
..Default::default()
|
|
}],
|
|
..SelectionViewParams::picker()
|
|
});
|
|
self.app_event_tx.send(AppEvent::FetchPermissionProfiles {
|
|
request_id,
|
|
thread_cwd: self.thread_id.and(self.current_cwd.clone()),
|
|
});
|
|
}
|
|
|
|
pub(super) fn invalidate_permission_discovery(&mut self) {
|
|
self.permission_popup_request_id = None;
|
|
self.bottom_pane.dismiss_view_by_id(VIEW_ID);
|
|
}
|
|
|
|
pub(crate) fn permission_popup_request_is_current(&self, request_id: uuid::Uuid) -> bool {
|
|
self.permission_popup_request_id == Some(request_id)
|
|
}
|
|
|
|
pub(crate) fn on_permission_profiles_loaded(
|
|
&mut self,
|
|
request_id: uuid::Uuid,
|
|
result: Result<PermissionDiscovery, String>,
|
|
) {
|
|
if !self.permission_popup_request_is_current(request_id) {
|
|
return;
|
|
}
|
|
self.permission_popup_request_id = None;
|
|
if !self.bottom_pane.dismiss_active_view_if_id(VIEW_ID) {
|
|
self.bottom_pane.dismiss_view_by_id(VIEW_ID);
|
|
return;
|
|
}
|
|
match result {
|
|
Ok(discovery) => {
|
|
self.permission_profiles_menu_opened = true;
|
|
self.open_permission_profiles_popup(discovery);
|
|
}
|
|
Err(message) => self.bottom_pane.show_selection_view(SelectionViewParams {
|
|
view_id: Some(VIEW_ID),
|
|
title: Some("Update Model Permissions".to_string()),
|
|
subtitle: Some(message),
|
|
items: vec![SelectionItem {
|
|
name: "Retry".to_string(),
|
|
actions: vec![Box::new(|tx| tx.send(AppEvent::OpenPermissionsPopup))],
|
|
dismiss_on_select: true,
|
|
..Default::default()
|
|
}],
|
|
..SelectionViewParams::picker()
|
|
}),
|
|
}
|
|
}
|
|
}
|