feat(core) Persist request_permission data across turns (#14009)

## Summary
request_permissions flows should support persisting results for the
session.

Open Question: Still deciding if we need within-turn approvals - this
adds complexity but I could see it being useful

## Testing
- [x] Updated unit tests

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Dylan Hurd
2026-03-09 14:36:38 -07:00
committed by GitHub
Unverified
parent 831ee51c86
commit d241dc598c
21 changed files with 638 additions and 8 deletions
+19 -1
View File
@@ -103,6 +103,7 @@ use codex_protocol::protocol::TurnAbortReason;
use codex_protocol::protocol::TurnContextItem;
use codex_protocol::protocol::TurnContextNetworkItem;
use codex_protocol::protocol::TurnStartedEvent;
use codex_protocol::request_permissions::PermissionGrantScope;
use codex_protocol::request_permissions::RequestPermissionsArgs;
use codex_protocol::request_permissions::RequestPermissionsEvent;
use codex_protocol::request_permissions::RequestPermissionsResponse;
@@ -2996,6 +2997,7 @@ impl Session {
call_id: &str,
response: RequestPermissionsResponse,
) {
let mut granted_for_session = None;
let entry = {
let mut active = self.active_turn.lock().await;
match active.as_mut() {
@@ -3003,13 +3005,24 @@ impl Session {
let mut ts = at.turn_state.lock().await;
let entry = ts.remove_pending_request_permissions(call_id);
if entry.is_some() && !response.permissions.is_empty() {
ts.record_granted_permissions(response.permissions.clone());
match response.scope {
PermissionGrantScope::Turn => {
ts.record_granted_permissions(response.permissions.clone());
}
PermissionGrantScope::Session => {
granted_for_session = Some(response.permissions.clone());
}
}
}
entry
}
None => None,
}
};
if let Some(permissions) = granted_for_session {
let mut state = self.state.lock().await;
state.record_granted_permissions(permissions);
}
match entry {
Some(tx_response) => {
tx_response.send(response).ok();
@@ -3027,6 +3040,11 @@ impl Session {
ts.granted_permissions()
}
pub(crate) async fn granted_session_permissions(&self) -> Option<PermissionProfile> {
let state = self.state.lock().await;
state.granted_permissions()
}
pub async fn notify_dynamic_tool_response(&self, call_id: &str, response: DynamicToolResponse) {
let entry = {
let mut active = self.active_turn.lock().await;