mirror of
https://github.com/openai/codex.git
synced 2026-11-08 20:40:33 +00:00
## What changed - Add `ResolvedModelMessages` to resolve catalog text and bundled defaults while preserving explicit empty overrides and their source. - Move base-instruction rendering, Guardian prompt composition, multi-agent role rendering, and `update_plan` guidance filtering into `codex-prompts`; migrate consumers to the shared APIs. - Separate permission-profile resolution from prompt composition, and annotate Guardian policy and classifier instructions with content kinds. ## Testing Add and update coverage for missing versus empty templates, literal overrides, multi-agent role composition, Guardian policy substitution and truncation, and preservation of permission path spellings and order. GitOrigin-RevId: 52335bb7acec0f432d5c57acb2accd5f0276056e
209 lines
7.9 KiB
Rust
209 lines
7.9 KiB
Rust
//! Hosts approval decisions and the isolated synchronous reviewer.
|
|
//! The extension chooses policy and evidence; core enforces permissions and mandatory
|
|
//! review requirements. Each approval retains its issuing context and cancellation.
|
|
|
|
mod approval_request;
|
|
mod coverage;
|
|
mod decision;
|
|
mod feedback;
|
|
mod input_budget;
|
|
mod prompt;
|
|
pub(crate) use input_budget::PendingReviewContext;
|
|
pub(crate) use input_budget::check_pending as check_pending_guardian_input;
|
|
pub(crate) use input_budget::finalize as finalize_guardian_input;
|
|
mod request_budget;
|
|
pub(crate) use request_budget::ExhaustedReviewBudget;
|
|
pub(crate) use request_budget::check_prompt as check_guardian_prompt_budget;
|
|
pub(crate) use request_budget::observe as observe_guardian_request;
|
|
mod review;
|
|
mod review_session;
|
|
mod reviewer_config;
|
|
pub(crate) use reviewer_config::resolve_review_model;
|
|
mod runtime;
|
|
#[cfg(test)]
|
|
pub(crate) mod test_host;
|
|
|
|
use codex_protocol::items::ModelInvocationContext;
|
|
use std::sync::Arc;
|
|
|
|
use codex_protocol::config_types::ApprovalsReviewer;
|
|
use codex_protocol::config_types::Personality;
|
|
use codex_protocol::config_types::ReasoningSummary;
|
|
use codex_protocol::openai_models::ModelInfo;
|
|
use codex_protocol::openai_models::ReasoningEffort;
|
|
use codex_protocol::protocol::AskForApproval;
|
|
use codex_protocol::protocol::GuardianAssessmentOutcome;
|
|
|
|
use crate::environment_selection::TurnEnvironmentSnapshot;
|
|
use crate::session::step_context::StepContext;
|
|
use crate::session::step_settings::ResolvedStepSettings;
|
|
use crate::session::turn_context::TurnContext;
|
|
use crate::tools::sandboxing::ApprovalRequestReasons;
|
|
|
|
pub(crate) use approval_request::GuardianApprovalRequest;
|
|
pub(crate) use approval_request::GuardianMcpAnnotations;
|
|
pub(crate) use approval_request::GuardianNetworkAccessTrigger;
|
|
#[cfg(test)]
|
|
pub(crate) use approval_request::guardian_approval_request_to_json;
|
|
pub(crate) use decision::decide_approval;
|
|
pub(crate) use decision::spawn_approval_decision;
|
|
pub(crate) use prompt::guardian_truncate_text;
|
|
pub(crate) use review::GuardianReviewOptions;
|
|
pub(crate) use review::is_basic_session_source;
|
|
pub(crate) use review::new_guardian_review_id;
|
|
pub(crate) use review::routes_approval_policy_to_guardian;
|
|
pub use review_session::GuardianReviewSession;
|
|
pub(crate) use review_session::GuardianReviewSessionManager;
|
|
pub use review_session::GuardianReviewState;
|
|
pub use review_session::PreparedGuardianContext;
|
|
pub use review_session::prepare_review_prewarm;
|
|
|
|
pub(crate) use review_session::prompt_cache_key_override_for_review_session;
|
|
pub(crate) use runtime::ReviewAction;
|
|
|
|
pub(crate) use codex_guardian_reviewer::REVIEW_TIMEOUT as GUARDIAN_REVIEW_TIMEOUT;
|
|
pub(crate) const GUARDIAN_REVIEWER_NAME: &str = "guardian";
|
|
pub(crate) const AUTO_REVIEW_DENIED_ACTION_APPROVAL_DEVELOPER_PREFIX: &str =
|
|
codex_guardian_context::MANUAL_APPROVAL_DEVELOPER_PREFIX;
|
|
const GUARDIAN_MAX_TOOL_ENTRY_TOKENS: usize = codex_guardian_context::ContextProfile::synchronous()
|
|
.transcript
|
|
.entry_limits
|
|
.tool_tokens;
|
|
pub(crate) const GUARDIAN_MAX_ROOT_MESSAGE_TOKENS: usize = 900;
|
|
pub(crate) const GUARDIAN_MAX_NODE_REPL_TOOL_RESULT_TOKENS: usize = 6_000;
|
|
|
|
/// Captures review inputs from the issuing step without retaining its MCP bindings or tool router.
|
|
/// Background network approvals and Unix interception use the active task's resolved settings.
|
|
/// Startup reviewer prewarming intentionally uses turn-only inputs because it has no issuing step.
|
|
///
|
|
/// MCP elicitation reviews continue to use turn-only inputs.
|
|
#[derive(Clone)]
|
|
pub(crate) struct GuardianReviewContext {
|
|
/// The latest response ID received in this turn when review was requested.
|
|
pub(crate) parent_response_id: Option<String>,
|
|
turn: Arc<TurnContext>,
|
|
environments: TurnEnvironmentSnapshot,
|
|
// Model and reasoning inputs are carried for the follow-up Guardian and V2 migrations.
|
|
pub(crate) model_info: Arc<ModelInfo>,
|
|
pub(crate) reasoning_effort: Option<ReasoningEffort>,
|
|
pub(crate) reasoning_summary: ReasoningSummary,
|
|
pub(crate) personality: Option<Personality>,
|
|
pub(crate) approval_policy: AskForApproval,
|
|
pub(crate) approvals_reviewer: ApprovalsReviewer,
|
|
}
|
|
|
|
impl GuardianReviewContext {
|
|
pub(crate) fn model_context(&self) -> ModelInvocationContext {
|
|
ModelInvocationContext {
|
|
model_slug: self.model_info.slug.clone(),
|
|
reasoning_effort: self
|
|
.reasoning_effort
|
|
.as_ref()
|
|
.or(self.model_info.default_reasoning_level.as_ref())
|
|
.map(ToString::to_string),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn from_resolved_settings(
|
|
turn: Arc<TurnContext>,
|
|
settings: &ResolvedStepSettings,
|
|
environments: &TurnEnvironmentSnapshot,
|
|
) -> Self {
|
|
Self {
|
|
parent_response_id: turn
|
|
.extension_data
|
|
.get::<codex_api::ResponseId>()
|
|
.map(|id| id.0.clone()),
|
|
environments: environments.clone(),
|
|
model_info: Arc::clone(&settings.model_info),
|
|
reasoning_effort: settings.reasoning_effort().cloned(),
|
|
reasoning_summary: settings.reasoning_summary,
|
|
personality: settings.personality(),
|
|
approval_policy: settings.approval_policy(),
|
|
approvals_reviewer: settings.approvals_reviewer(),
|
|
turn,
|
|
}
|
|
}
|
|
|
|
pub(crate) fn turn(&self) -> &Arc<TurnContext> {
|
|
&self.turn
|
|
}
|
|
|
|
pub(crate) fn environments(&self) -> &TurnEnvironmentSnapshot {
|
|
&self.environments
|
|
}
|
|
}
|
|
|
|
impl From<&Arc<StepContext>> for GuardianReviewContext {
|
|
fn from(step: &Arc<StepContext>) -> Self {
|
|
Self {
|
|
parent_response_id: step
|
|
.turn
|
|
.extension_data
|
|
.get::<codex_api::ResponseId>()
|
|
.map(|id| id.0.clone()),
|
|
turn: Arc::clone(&step.turn),
|
|
environments: step.environments.clone(),
|
|
model_info: Arc::clone(&step.settings.model_info),
|
|
reasoning_effort: step.settings.reasoning_effort().cloned(),
|
|
reasoning_summary: step.settings.reasoning_summary,
|
|
personality: step.settings.personality(),
|
|
approval_policy: step.settings.approval_policy(),
|
|
approvals_reviewer: step.settings.approvals_reviewer(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<Arc<TurnContext>> for GuardianReviewContext {
|
|
fn from(turn: Arc<TurnContext>) -> Self {
|
|
Self {
|
|
parent_response_id: turn
|
|
.extension_data
|
|
.get::<codex_api::ResponseId>()
|
|
.map(|id| id.0.clone()),
|
|
environments: turn.environments.clone(),
|
|
model_info: Arc::clone(turn.model_info()),
|
|
reasoning_effort: turn.reasoning_effort().cloned(),
|
|
reasoning_summary: turn.reasoning_summary(),
|
|
personality: turn.personality(),
|
|
approval_policy: turn.approval_policy(),
|
|
approvals_reviewer: turn.config.approvals_reviewer,
|
|
turn,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl From<&Arc<TurnContext>> for GuardianReviewContext {
|
|
fn from(turn: &Arc<TurnContext>) -> Self {
|
|
Self::from(Arc::clone(turn))
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
use codex_guardian_reviewer::guardian_output_schema;
|
|
|
|
pub(crate) use approval_request::format_guardian_action_pretty;
|
|
#[cfg(test)]
|
|
use approval_request::guardian_assessment_action;
|
|
#[cfg(test)]
|
|
use approval_request::guardian_request_turn_id;
|
|
#[cfg(test)]
|
|
use codex_guardian_reviewer::GuardianReviewOutcome;
|
|
#[cfg(test)]
|
|
use prompt::GuardianPromptMode;
|
|
#[cfg(test)]
|
|
use prompt::GuardianTranscriptCursor;
|
|
#[cfg(test)]
|
|
use prompt::build_guardian_prompt_items;
|
|
#[cfg(test)]
|
|
use prompt::build_guardian_prompt_items_with_parent_turn;
|
|
#[cfg(test)]
|
|
use prompt::render_guardian_transcript_entries;
|
|
#[cfg(test)]
|
|
use review::run_guardian_review_session_with_retry as run_guardian_review_session_for_test;
|
|
#[cfg(test)]
|
|
use review_session::build_guardian_review_session_config as build_guardian_review_session_config_for_test;
|
|
|
|
#[cfg(test)]
|
|
mod tests;
|