From 73bdd06fed88a035aa269fd9c62453d9fbb99fcc Mon Sep 17 00:00:00 2001 From: jif Date: Tue, 27 Oct 2026 16:29:09 +0000 Subject: [PATCH] Extract Guardian planned-action assembly into the reviewer crate (#57509) ## What changed Move planned-action construction from the core Guardian prompt builder into the exported `codex_guardian_reviewer::build_guardian_planned_action` helper. Keep the existing action kinds, MCP tool and connector descriptions, and reason selection unchanged. GitOrigin-RevId: 119323523ed2e199c998c1139fb8e6255bc730d9 --- codex-rs/core/src/context/mod.rs | 1 - codex-rs/core/src/guardian/prompt.rs | 41 ++-------------- codex-rs/ext/guardian-reviewer/src/lib.rs | 2 + .../guardian-reviewer/src/planned_action.rs | 48 +++++++++++++++++++ 4 files changed, 54 insertions(+), 38 deletions(-) create mode 100644 codex-rs/ext/guardian-reviewer/src/planned_action.rs diff --git a/codex-rs/core/src/context/mod.rs b/codex-rs/core/src/context/mod.rs index 59c4a472d7..2969fd2c2f 100644 --- a/codex-rs/core/src/context/mod.rs +++ b/codex-rs/core/src/context/mod.rs @@ -67,7 +67,6 @@ pub(crate) use codex_context_fragments::AdditionalContextToolOutput; pub(crate) use codex_context_fragments::AdditionalContextUserFragment; pub use codex_context_fragments::AnsweredQuestion; pub use codex_context_fragments::ContextualUserFragment; -pub(crate) use codex_guardian_context::GuardianToolDescriptions; pub(crate) use codex_guardian_context::PermissionContext as GuardianPermissionContext; pub(crate) use codex_prompts::MultiAgentRoleInstructions; pub use codex_prompts::PermissionsInstructions; diff --git a/codex-rs/core/src/guardian/prompt.rs b/codex-rs/core/src/guardian/prompt.rs index d0e773bea3..92bcb9b249 100644 --- a/codex-rs/core/src/guardian/prompt.rs +++ b/codex-rs/core/src/guardian/prompt.rs @@ -8,7 +8,6 @@ use codex_guardian_context::ContextProfile; use codex_guardian_context::ConversationTranscriptEntry; use codex_guardian_context::GuardianRootMessage; use codex_guardian_context::PlannedAction; -use codex_guardian_context::PlannedActionKind; use codex_guardian_context::SectionError; use codex_guardian_context::SectionHistory; use codex_guardian_context::SectionInput; @@ -20,7 +19,6 @@ use codex_guardian_reviewer::GuardianPromptItems; use codex_protocol::models::ResponseItem; use crate::context::GuardianPermissionContext; -use crate::context::GuardianToolDescriptions; use crate::context::NodeReplReviewEvidence; use crate::context::NodeReplReviewEvidenceMode; use crate::context::is_guardian_context_message; @@ -33,7 +31,6 @@ use super::GUARDIAN_MAX_NODE_REPL_TOOL_RESULT_TOKENS; use super::GUARDIAN_MAX_TOOL_ENTRY_TOKENS; use super::GuardianApprovalRequest; use super::GuardianReviewContext; -use super::approval_request::format_guardian_action_pretty; // Bound both JSON and permission evidence without restricting manual approvals. const MAX_GUARDIAN_ENVIRONMENT_ID_BYTES: usize = 256; @@ -114,40 +111,10 @@ pub(crate) async fn build_guardian_prompt_items_with_parent_turn( .retained_context() .map(codex_guardian_context::collect_verified_answer_candidates) .unwrap_or_default(); - let planned_action = PlannedAction { - tool_descriptions: if let GuardianApprovalRequest::McpToolCall { - tool_description, - connector_description, - .. - } = &request - { - GuardianToolDescriptions::new( - tool_description.as_deref(), - connector_description.as_deref(), - ) - } else { - None - }, - kind: match &request { - GuardianApprovalRequest::NativeToolCall { call, .. } => { - PlannedActionKind::ToolCall(call.clone()) - } - GuardianApprovalRequest::NetworkAccess { trigger, .. } => PlannedActionKind::Network { - json: format_guardian_action_pretty(&request)?, - has_trigger: trigger.is_some(), - }, - GuardianApprovalRequest::WriteStdin { .. } => PlannedActionKind::TerminalInput { - json: format_guardian_action_pretty(&request)?, - }, - GuardianApprovalRequest::ExecCommand { .. } - | GuardianApprovalRequest::ApplyPatch { .. } - | GuardianApprovalRequest::McpToolCall { .. } - | GuardianApprovalRequest::RequestPermissions { .. } => PlannedActionKind::Command { - json: format_guardian_action_pretty(&request)?, - }, - }, - reason: reasons.retry.or(reasons.approval), - }; + let planned_action = codex_guardian_reviewer::build_guardian_planned_action( + &request, + reasons.retry.or(reasons.approval), + )?; let permissions = parent_context .map(|context| { super::permissions::for_environment(context, request.target_environment_id()) diff --git a/codex-rs/ext/guardian-reviewer/src/lib.rs b/codex-rs/ext/guardian-reviewer/src/lib.rs index 4b9dc40f26..24f6da0adc 100644 --- a/codex-rs/ext/guardian-reviewer/src/lib.rs +++ b/codex-rs/ext/guardian-reviewer/src/lib.rs @@ -19,6 +19,7 @@ mod feedback; mod metrics; mod model; mod outcome; +mod planned_action; mod pool; mod prompt; mod reporting; @@ -51,6 +52,7 @@ pub use model::select_review_model; pub use outcome::GuardianReviewError; pub use outcome::GuardianReviewOutcome; pub use outcome::GuardianReviewSessionOutcome; +pub use planned_action::build_guardian_planned_action; pub use retry::GuardianReviewSessionLimits; pub use retry::run_with_retry; diff --git a/codex-rs/ext/guardian-reviewer/src/planned_action.rs b/codex-rs/ext/guardian-reviewer/src/planned_action.rs new file mode 100644 index 0000000000..b31bad8414 --- /dev/null +++ b/codex-rs/ext/guardian-reviewer/src/planned_action.rs @@ -0,0 +1,48 @@ +//! Assembles the existing planned-action evidence for synchronous Guardian prompts. +//! The host supplies the resolved reason; action kinds and description bounds stay unchanged. + +use crate::GuardianApprovalRequest; +use crate::format_guardian_action_pretty; +use codex_guardian_context::GuardianToolDescriptions; +use codex_guardian_context::PlannedAction; +use codex_guardian_context::PlannedActionKind; + +pub fn build_guardian_planned_action( + request: &GuardianApprovalRequest, + reason: Option, +) -> serde_json::Result { + Ok(PlannedAction { + tool_descriptions: if let GuardianApprovalRequest::McpToolCall { + tool_description, + connector_description, + .. + } = request + { + GuardianToolDescriptions::new( + tool_description.as_deref(), + connector_description.as_deref(), + ) + } else { + None + }, + kind: match request { + GuardianApprovalRequest::NativeToolCall { call, .. } => { + PlannedActionKind::ToolCall(call.clone()) + } + GuardianApprovalRequest::NetworkAccess { trigger, .. } => PlannedActionKind::Network { + json: format_guardian_action_pretty(request)?, + has_trigger: trigger.is_some(), + }, + GuardianApprovalRequest::WriteStdin { .. } => PlannedActionKind::TerminalInput { + json: format_guardian_action_pretty(request)?, + }, + GuardianApprovalRequest::ExecCommand { .. } + | GuardianApprovalRequest::ApplyPatch { .. } + | GuardianApprovalRequest::McpToolCall { .. } + | GuardianApprovalRequest::RequestPermissions { .. } => PlannedActionKind::Command { + json: format_guardian_action_pretty(request)?, + }, + }, + reason, + }) +}