Reuse guardian session across approvals (#14668)

## Summary
- reuse a guardian subagent session across approvals so reviews keep a
stable prompt cache key and avoid one-shot startup overhead
- clear the guardian child history before each review so prior guardian
decisions do not leak into later approvals
- include the `smart_approvals` -> `guardian_approval` feature flag
rename in the same PR to minimize release latency on a very tight
timeline
- add regression coverage for prompt-cache-key reuse without
prior-review prompt bleed

## Request
- Bug/enhancement request: internal guardian prompt-cache and latency
improvement request

---------

Co-authored-by: Codex <noreply@openai.com>
This commit is contained in:
Charley Cunningham
2026-03-15 22:56:18 -07:00
committed by GitHub
parent ba463a9dc7
commit 6fdeb1d602
26 changed files with 3132 additions and 1504 deletions

View File

@@ -2370,6 +2370,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
pending_mcp_server_refresh_config: Mutex::new(None),
conversation: Arc::new(RealtimeConversationManager::new()),
active_turn: Mutex::new(None),
guardian_review_session: crate::guardian::GuardianReviewSessionManager::default(),
services,
js_repl,
next_internal_sub_id: AtomicU64::new(0),
@@ -2873,6 +2874,120 @@ async fn shutdown_and_wait_waits_when_shutdown_is_already_in_progress() {
.expect("shutdown waiter");
}
#[tokio::test]
async fn shutdown_and_wait_shuts_down_cached_guardian_subagent() {
let (parent_session, parent_turn_context) = make_session_and_context().await;
let parent_session = Arc::new(parent_session);
let parent_config = Arc::clone(&parent_turn_context.config);
let (parent_tx_sub, parent_rx_sub) = async_channel::bounded(4);
let (_parent_tx_event, parent_rx_event) = async_channel::unbounded();
let (_parent_status_tx, parent_agent_status) = watch::channel(AgentStatus::PendingInit);
let parent_session_for_loop = Arc::clone(&parent_session);
let parent_session_loop_handle = tokio::spawn(async move {
submission_loop(parent_session_for_loop, parent_config, parent_rx_sub).await;
});
let parent_codex = Codex {
tx_sub: parent_tx_sub,
rx_event: parent_rx_event,
agent_status: parent_agent_status,
session: Arc::clone(&parent_session),
session_loop_termination: session_loop_termination_from_handle(parent_session_loop_handle),
};
let (child_session, _child_turn_context) = make_session_and_context().await;
let (child_tx_sub, child_rx_sub) = async_channel::bounded(4);
let (_child_tx_event, child_rx_event) = async_channel::unbounded();
let (_child_status_tx, child_agent_status) = watch::channel(AgentStatus::PendingInit);
let (child_shutdown_tx, child_shutdown_rx) = tokio::sync::oneshot::channel();
let child_session_loop_handle = tokio::spawn(async move {
let shutdown: Submission = child_rx_sub
.recv()
.await
.expect("child shutdown submission");
assert_eq!(shutdown.op, Op::Shutdown);
child_shutdown_tx
.send(())
.expect("child shutdown signal should be delivered");
});
let child_codex = Codex {
tx_sub: child_tx_sub,
rx_event: child_rx_event,
agent_status: child_agent_status,
session: Arc::new(child_session),
session_loop_termination: session_loop_termination_from_handle(child_session_loop_handle),
};
parent_session
.guardian_review_session
.cache_for_test(child_codex)
.await;
parent_codex
.shutdown_and_wait()
.await
.expect("parent shutdown should succeed");
child_shutdown_rx
.await
.expect("guardian subagent should receive a shutdown op");
}
#[tokio::test]
async fn shutdown_and_wait_shuts_down_tracked_ephemeral_guardian_review() {
let (parent_session, parent_turn_context) = make_session_and_context().await;
let parent_session = Arc::new(parent_session);
let parent_config = Arc::clone(&parent_turn_context.config);
let (parent_tx_sub, parent_rx_sub) = async_channel::bounded(4);
let (_parent_tx_event, parent_rx_event) = async_channel::unbounded();
let (_parent_status_tx, parent_agent_status) = watch::channel(AgentStatus::PendingInit);
let parent_session_for_loop = Arc::clone(&parent_session);
let parent_session_loop_handle = tokio::spawn(async move {
submission_loop(parent_session_for_loop, parent_config, parent_rx_sub).await;
});
let parent_codex = Codex {
tx_sub: parent_tx_sub,
rx_event: parent_rx_event,
agent_status: parent_agent_status,
session: Arc::clone(&parent_session),
session_loop_termination: session_loop_termination_from_handle(parent_session_loop_handle),
};
let (child_session, _child_turn_context) = make_session_and_context().await;
let (child_tx_sub, child_rx_sub) = async_channel::bounded(4);
let (_child_tx_event, child_rx_event) = async_channel::unbounded();
let (_child_status_tx, child_agent_status) = watch::channel(AgentStatus::PendingInit);
let (child_shutdown_tx, child_shutdown_rx) = tokio::sync::oneshot::channel();
let child_session_loop_handle = tokio::spawn(async move {
let shutdown: Submission = child_rx_sub
.recv()
.await
.expect("child shutdown submission");
assert_eq!(shutdown.op, Op::Shutdown);
child_shutdown_tx
.send(())
.expect("child shutdown signal should be delivered");
});
let child_codex = Codex {
tx_sub: child_tx_sub,
rx_event: child_rx_event,
agent_status: child_agent_status,
session: Arc::new(child_session),
session_loop_termination: session_loop_termination_from_handle(child_session_loop_handle),
};
parent_session
.guardian_review_session
.register_ephemeral_for_test(child_codex)
.await;
parent_codex
.shutdown_and_wait()
.await
.expect("parent shutdown should succeed");
child_shutdown_rx
.await
.expect("ephemeral guardian review should receive a shutdown op");
}
pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
dynamic_tools: Vec<DynamicToolSpec>,
) -> (
@@ -3045,6 +3160,7 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
pending_mcp_server_refresh_config: Mutex::new(None),
conversation: Arc::new(RealtimeConversationManager::new()),
active_turn: Mutex::new(None),
guardian_review_session: crate::guardian::GuardianReviewSessionManager::default(),
services,
js_repl,
next_internal_sub_id: AtomicU64::new(0),