Add experimental Guardian review for injected thread commands (#58119)

## What changed

Expose `thread/guardianReview` to review an idle thread's final injected `exec_command` without executing it. Return the call ID and Guardian assessment, or `null` for the assessment when exec policy skips approval.

Subscribe the requesting connection to the thread, enforce input and model-provider restrictions, and cancel an in-flight review when the connection disconnects so the thread is released promptly.

## Testing

Add integration coverage for assessment responses, policy-skipped reviews, model-provider enforcement, and WebSocket disconnect cancellation.

GitOrigin-RevId: e8ad5598e8f101a937447ebe26136310bb76c8d1
This commit is contained in:
swastik-oai
2026-10-29 16:30:06 +00:00
committed by copyberry
parent 02ca1e0d99
commit 6174d05a6a
10 changed files with 262 additions and 0 deletions
@@ -181,6 +181,7 @@ pub(crate) struct MessageProcessor {
#[derive(Debug)]
pub(crate) struct ConnectionSessionState {
disconnect: CancellationToken,
pub(crate) rpc_gate: Arc<ConnectionRpcGate>,
pub(crate) origin: crate::transport::ConnectionOrigin,
pub(crate) mcp_event_streams: McpEventStreams,
@@ -201,6 +202,7 @@ impl ConnectionSessionState {
pub(crate) fn new(origin: crate::transport::ConnectionOrigin) -> Self {
Self {
origin,
disconnect: CancellationToken::new(),
rpc_gate: Arc::new(ConnectionRpcGate::new()),
mcp_event_streams: McpEventStreams::default(),
initialized: OnceLock::new(),
@@ -904,6 +906,7 @@ impl MessageProcessor {
connection_id: ConnectionId,
session_state: &ConnectionSessionState,
) {
session_state.disconnect.cancel();
session_state.rpc_gate.close().await;
self.account_processor
.gateway_connection_closed(connection_id);
@@ -1032,6 +1035,7 @@ impl MessageProcessor {
| ClientRequest::ThreadDelete { .. }
| ClientRequest::ThreadArchive { .. } => (Some(self.turn_admission.admit()?), false),
ClientRequest::ThreadSample { .. }
| ClientRequest::ThreadGuardianReview { .. }
| ClientRequest::TurnStart { .. }
| ClientRequest::TurnSteer { .. }
| ClientRequest::ReviewStart { .. }
@@ -1704,6 +1708,20 @@ impl MessageProcessor {
)
.await
}
ClientRequest::ThreadGuardianReview { params, .. } => {
let cancellation = &request_context.cancellation;
let review =
self.turn_processor
.thread_guardian_review(&request_id, params, cancellation);
tokio::pin!(review);
tokio::select! {
result = &mut review => result,
_ = session.disconnect.cancelled() => {
cancellation.cancel();
review.await
}
}
}
ClientRequest::ThreadInjectItems { params, .. } => {
self.turn_processor
.thread_inject_items(&request_id, params)