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
This commit is contained in:
jif
2026-10-27 16:37:01 +00:00
committed by copyberry
parent 2d1984b9f7
commit 73bdd06fed
4 changed files with 54 additions and 38 deletions
-1
View File
@@ -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;
+4 -37
View File
@@ -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())
@@ -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;
@@ -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<String>,
) -> serde_json::Result<PlannedAction> {
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,
})
}