mirror of
https://github.com/openai/codex.git
synced 2026-05-05 22:01:37 +03:00
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:
committed by
GitHub
parent
ba463a9dc7
commit
6fdeb1d602
@@ -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),
|
||||
|
||||
Reference in New Issue
Block a user