move initial context to session, not config

This commit is contained in:
Owen Lin
2026-04-09 14:06:20 -07:00
parent 21e7cbb9cd
commit 82dcda2910
12 changed files with 153 additions and 154 deletions
+22 -26
View File
@@ -4,7 +4,7 @@ use codex_features::Feature;
use crate::codex::TurnContext;
use crate::config::Config;
use crate::config::Constrained;
use crate::config::InitialContextInclusions;
use crate::initial_context::InitialContextInclusions;
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
@@ -35,6 +35,27 @@ pub(crate) struct SubAgentPromptSelection {
pub(crate) environment_context: bool,
}
impl SubAgentPromptSelection {
pub(crate) fn initial_context_inclusions(self) -> InitialContextInclusions {
let mut inclusions = InitialContextInclusions::none();
inclusions.model_update = self.model_update;
inclusions.permissions = self.permissions;
inclusions.developer_instructions = self.developer_instructions;
inclusions.separate_developer_instructions = self.separate_developer_instructions;
inclusions.memory = self.memory;
inclusions.collaboration = self.collaboration;
inclusions.realtime = self.realtime;
inclusions.personality = self.personality;
inclusions.apps = self.apps;
inclusions.skills = self.skills;
inclusions.plugins = self.plugins;
inclusions.commit = self.commit;
inclusions.user_instructions = self.user_instructions || self.project_docs;
inclusions.environment_context = self.environment_context;
inclusions
}
}
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)]
pub(crate) enum SubAgentExtensionInheritance {
@@ -124,7 +145,6 @@ impl SubAgentConfigBuilder {
self.config.include_permissions_instructions = false;
self.config.include_apps_instructions = false;
self.config.include_environment_context = false;
self.config.initial_context_inclusions = InitialContextInclusions::none();
}
SubAgentPromptInheritance::Select(selection) => {
self.apply_prompt_selection(selection);
@@ -149,14 +169,6 @@ impl SubAgentConfigBuilder {
Ok(self)
}
pub(crate) fn initial_context_inclusions(
mut self,
inclusions: InitialContextInclusions,
) -> Self {
self.config.initial_context_inclusions = inclusions;
self
}
pub(crate) fn build(self) -> Config {
self.config
}
@@ -182,22 +194,6 @@ impl SubAgentConfigBuilder {
self.config.include_permissions_instructions = selection.permissions;
self.config.include_apps_instructions = selection.apps;
self.config.include_environment_context = selection.environment_context;
self.config.initial_context_inclusions = InitialContextInclusions {
model_update: selection.model_update,
permissions: selection.permissions,
developer_instructions: selection.developer_instructions,
separate_developer_instructions: selection.separate_developer_instructions,
memory: selection.memory,
collaboration: selection.collaboration,
realtime: selection.realtime,
personality: selection.personality,
apps: selection.apps,
skills: selection.skills,
plugins: selection.plugins,
commit: selection.commit,
user_instructions: selection.user_instructions || selection.project_docs,
environment_context: selection.environment_context,
};
}
fn apply_extension_selection(
+19 -2
View File
@@ -268,6 +268,7 @@ use crate::hook_runtime::record_additional_contexts;
use crate::hook_runtime::record_pending_input;
use crate::hook_runtime::run_pending_session_start_hooks;
use crate::hook_runtime::run_user_prompt_submit_hooks;
use crate::initial_context::InitialContextInclusions;
use crate::injection::ToolMentionKind;
use crate::injection::app_id_from_path;
use crate::injection::tool_kind_for_path;
@@ -419,6 +420,7 @@ pub struct CodexSpawnOk {
pub(crate) struct CodexSpawnArgs {
pub(crate) config: Config,
pub(crate) initial_context_inclusions: InitialContextInclusions,
pub(crate) auth_manager: Arc<AuthManager>,
pub(crate) models_manager: Arc<ModelsManager>,
pub(crate) environment_manager: Arc<EnvironmentManager>,
@@ -473,6 +475,7 @@ impl Codex {
async fn spawn_internal(args: CodexSpawnArgs) -> CodexResult<CodexSpawnOk> {
let CodexSpawnArgs {
mut config,
initial_context_inclusions,
auth_manager,
models_manager,
environment_manager,
@@ -640,6 +643,7 @@ impl Codex {
personality: config.personality,
base_instructions,
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions,
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -1120,6 +1124,13 @@ pub(crate) struct SessionConfiguration {
/// Compact prompt override.
compact_prompt: Option<String>,
/// Session-scoped policy for which startup context blocks are model-visible.
///
/// This is chosen at spawn time. It is intentionally separate from the
/// loaded user config so internally spawned subagents can have narrower
/// startup prompts without mutating config.toml-derived settings.
initial_context_inclusions: InitialContextInclusions,
/// When to escalate for approval for execution
approval_policy: Constrained<AskForApproval>,
approvals_reviewer: ApprovalsReviewer,
@@ -3680,16 +3691,22 @@ impl Session {
let mut developer_sections = Vec::<String>::with_capacity(8);
let mut contextual_user_sections = Vec::<String>::with_capacity(2);
let shell = self.user_shell();
let (reference_context_item, previous_turn_settings, collaboration_mode, base_instructions) = {
let (
reference_context_item,
previous_turn_settings,
collaboration_mode,
base_instructions,
initial_context,
) = {
let state = self.state.lock().await;
(
state.reference_context_item(),
state.previous_turn_settings(),
state.session_configuration.collaboration_mode.clone(),
state.session_configuration.base_instructions.clone(),
state.session_configuration.initial_context_inclusions,
)
};
let initial_context = turn_context.config.initial_context_inclusions;
if initial_context.model_update
&& let Some(model_switch_message) =
crate::context_manager::updates::build_model_instructions_update_item(
+4
View File
@@ -41,6 +41,7 @@ use crate::config::Config;
use crate::guardian::GuardianApprovalRequest;
use crate::guardian::review_approval_request_with_cancel;
use crate::guardian::routes_approval_to_guardian;
use crate::initial_context::InitialContextInclusions;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_ACCEPT;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_ACCEPT_FOR_SESSION;
use crate::mcp_tool_call::MCP_TOOL_APPROVAL_DECLINE_SYNTHETIC;
@@ -63,6 +64,7 @@ use crate::codex::completed_session_loop_termination;
#[allow(clippy::too_many_arguments)]
pub(crate) async fn run_codex_thread_interactive(
config: Config,
initial_context_inclusions: InitialContextInclusions,
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
parent_session: Arc<Session>,
@@ -76,6 +78,7 @@ pub(crate) async fn run_codex_thread_interactive(
let CodexSpawnOk { codex, .. } = Codex::spawn(CodexSpawnArgs {
config,
initial_context_inclusions,
auth_manager,
models_manager,
environment_manager: Arc::new(EnvironmentManager::from_environment(
@@ -171,6 +174,7 @@ pub(crate) async fn run_codex_thread_one_shot(
let child_cancel = cancel_token.child_token();
let io = run_codex_thread_interactive(
config,
InitialContextInclusions::full(),
auth_manager,
models_manager,
parent_session,
+6
View File
@@ -1993,6 +1993,7 @@ async fn set_rate_limits_retains_previous_credits() {
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -2095,6 +2096,7 @@ async fn set_rate_limits_updates_plan_type_when_present() {
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -2444,6 +2446,7 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -2707,6 +2710,7 @@ async fn session_new_fails_when_zsh_fork_enabled_without_zsh_path() {
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -2810,6 +2814,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
@@ -3654,6 +3659,7 @@ pub(crate) async fn make_session_and_context_with_dynamic_tools_and_rx(
.clone()
.unwrap_or_else(|| model_info.get_model_instructions(config.personality)),
compact_prompt: config.compact_prompt.clone(),
initial_context_inclusions: InitialContextInclusions::full(),
approval_policy: config.permissions.approval_policy.clone(),
approvals_reviewer: config.approvals_reviewer,
sandbox_policy: config.permissions.sandbox_policy.clone(),
+7 -7
View File
@@ -7,6 +7,7 @@ use crate::exec::ExecCapturePolicy;
use crate::exec::ExecParams;
use crate::exec_policy::ExecPolicyManager;
use crate::guardian::GUARDIAN_REVIEWER_NAME;
use crate::initial_context::InitialContextInclusions;
use crate::sandboxing::SandboxPermissions;
use crate::tools::context::FunctionToolOutput;
use crate::turn_diff_tracker::TurnDiffTracker;
@@ -244,16 +245,14 @@ async fn process_compacted_history_preserves_separate_guardian_developer_message
{
let mut state = session.state.lock().await;
state.session_configuration.session_source = guardian_source.clone();
state.session_configuration.initial_context_inclusions = InitialContextInclusions {
developer_instructions: true,
separate_developer_instructions: true,
..InitialContextInclusions::none()
};
}
turn_context.session_source = guardian_source;
turn_context.developer_instructions = Some(guardian_policy.clone());
let mut config = (*turn_context.config).clone();
config.initial_context_inclusions = crate::config::InitialContextInclusions {
developer_instructions: true,
separate_developer_instructions: true,
..crate::config::InitialContextInclusions::none()
};
turn_context.config = Arc::new(config);
let refreshed = crate::compact_remote::process_compacted_history(
&session,
@@ -441,6 +440,7 @@ async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules() {
let CodexSpawnOk { codex, .. } = Codex::spawn(CodexSpawnArgs {
config,
initial_context_inclusions: InitialContextInclusions::full(),
auth_manager,
models_manager,
environment_manager: Arc::new(EnvironmentManager::new(/*exec_server_url*/ None)),
-4
View File
@@ -4562,7 +4562,6 @@ fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> {
include_permissions_instructions: true,
include_apps_instructions: true,
include_environment_context: true,
initial_context_inclusions: InitialContextInclusions::full(),
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4710,7 +4709,6 @@ fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> {
include_permissions_instructions: true,
include_apps_instructions: true,
include_environment_context: true,
initial_context_inclusions: InitialContextInclusions::full(),
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4856,7 +4854,6 @@ fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> {
include_permissions_instructions: true,
include_apps_instructions: true,
include_environment_context: true,
initial_context_inclusions: InitialContextInclusions::full(),
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
@@ -4988,7 +4985,6 @@ fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> {
include_permissions_instructions: true,
include_apps_instructions: true,
include_environment_context: true,
initial_context_inclusions: InitialContextInclusions::full(),
compact_prompt: None,
commit_attribution: None,
forced_chatgpt_workspace_id: None,
-65
View File
@@ -269,12 +269,6 @@ pub struct Config {
/// Whether to inject the `<environment_context>` user block.
pub include_environment_context: bool,
/// In-memory policy for which startup context blocks are model-visible.
///
/// This is not loaded from config.toml. It is used by internally spawned
/// subagents that need a narrower prompt than the parent session.
pub(crate) initial_context_inclusions: InitialContextInclusions,
/// Compact prompt override.
pub compact_prompt: Option<String>,
@@ -582,64 +576,6 @@ pub struct Config {
pub otel: codex_config::types::OtelConfig,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct InitialContextInclusions {
pub(crate) model_update: bool,
pub(crate) permissions: bool,
pub(crate) developer_instructions: bool,
pub(crate) separate_developer_instructions: bool,
pub(crate) memory: bool,
pub(crate) collaboration: bool,
pub(crate) realtime: bool,
pub(crate) personality: bool,
pub(crate) apps: bool,
pub(crate) skills: bool,
pub(crate) plugins: bool,
pub(crate) commit: bool,
pub(crate) user_instructions: bool,
pub(crate) environment_context: bool,
}
impl InitialContextInclusions {
pub(crate) const fn full() -> Self {
Self {
model_update: true,
permissions: true,
developer_instructions: true,
separate_developer_instructions: false,
memory: true,
collaboration: true,
realtime: true,
personality: true,
apps: true,
skills: true,
plugins: true,
commit: true,
user_instructions: true,
environment_context: true,
}
}
pub(crate) const fn none() -> Self {
Self {
model_update: false,
permissions: false,
developer_instructions: false,
separate_developer_instructions: false,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
user_instructions: false,
environment_context: false,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MultiAgentV2Config {
pub usage_hint_enabled: bool,
@@ -2082,7 +2018,6 @@ impl Config {
include_permissions_instructions,
include_apps_instructions,
include_environment_context,
initial_context_inclusions: InitialContextInclusions::full(),
// The config.toml omits "_mode" because it's a config file. However, "_mode"
// is important in code to differentiate the mode from the store implementation.
cli_auth_credentials_store_mode: cfg.cli_auth_credentials_store.unwrap_or_default(),
+31 -36
View File
@@ -34,9 +34,9 @@ use crate::codex::TurnContext;
use crate::codex_delegate::run_codex_thread_interactive;
use crate::config::Config;
use crate::config::Constrained;
use crate::config::InitialContextInclusions;
use crate::config::NetworkProxySpec;
use crate::config::Permissions;
use crate::initial_context::InitialContextInclusions;
use crate::rollout::recorder::RolloutRecorder;
use codex_model_provider_info::ModelProviderInfo;
@@ -449,6 +449,7 @@ async fn spawn_guardian_review_session(
let has_prior_review = initial_history.is_some();
let codex = run_codex_thread_interactive(
spawn_config,
guardian_review_initial_context_inclusions(),
params.parent_session.services.auth_manager.clone(),
params.parent_session.services.models_manager.clone(),
Arc::clone(&params.parent_session),
@@ -623,42 +624,10 @@ pub(crate) fn build_guardian_review_session_config(
reasoning_effort: Option<codex_protocol::openai_models::ReasoningEffort>,
) -> anyhow::Result<Config> {
let mut guardian_config = SubAgentConfigBuilder::from_parent_config(parent_config)
.prompt_inheritance(SubAgentPromptInheritance::Select(SubAgentPromptSelection {
model_update: false,
base_instructions: false,
user_instructions: false,
project_docs: true,
developer_instructions: true,
separate_developer_instructions: true,
compact_prompt: false,
permissions: false,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
environment_context: true,
}))
.prompt_inheritance(SubAgentPromptInheritance::Select(
guardian_review_prompt_selection(),
))
.extension_inheritance(SubAgentExtensionInheritance::None)?
.initial_context_inclusions(InitialContextInclusions {
model_update: false,
permissions: false,
developer_instructions: true,
separate_developer_instructions: true,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
user_instructions: true,
environment_context: true,
})
.build();
guardian_config.model = Some(active_model.to_string());
guardian_config.model_reasoning_effort = reasoning_effort;
@@ -700,6 +669,32 @@ pub(crate) fn build_guardian_review_session_config(
Ok(guardian_config)
}
pub(crate) fn guardian_review_initial_context_inclusions() -> InitialContextInclusions {
guardian_review_prompt_selection().initial_context_inclusions()
}
const fn guardian_review_prompt_selection() -> SubAgentPromptSelection {
SubAgentPromptSelection {
model_update: false,
base_instructions: false,
user_instructions: false,
project_docs: true,
developer_instructions: true,
separate_developer_instructions: true,
compact_prompt: false,
permissions: false,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
environment_context: true,
}
}
async fn run_before_review_deadline<T>(
deadline: tokio::time::Instant,
external_cancel: Option<&CancellationToken>,
+4 -14
View File
@@ -4,7 +4,6 @@ use crate::codex::TurnContext;
use crate::config::Config;
use crate::config::ConfigOverrides;
use crate::config::Constrained;
use crate::config::InitialContextInclusions;
use crate::config::ManagedFeatures;
use crate::config::NetworkProxySpec;
use crate::config::test_config;
@@ -1210,23 +1209,14 @@ fn guardian_review_session_config_strips_parent_prompt_and_tooling_surface() {
assert!(guardian_config.include_environment_context);
assert_eq!(guardian_config.project_doc_max_bytes, 4096);
assert_eq!(
guardian_config.initial_context_inclusions,
InitialContextInclusions {
model_update: false,
permissions: false,
super::review_session::guardian_review_initial_context_inclusions(),
crate::initial_context::InitialContextInclusions {
developer_instructions: true,
separate_developer_instructions: true,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
user_instructions: true,
environment_context: true,
}
..crate::initial_context::InitialContextInclusions::none()
},
);
assert!(guardian_config.mcp_servers.is_empty());
assert_eq!(guardian_config.js_repl_node_path, None);
+57
View File
@@ -0,0 +1,57 @@
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct InitialContextInclusions {
pub(crate) model_update: bool,
pub(crate) permissions: bool,
pub(crate) developer_instructions: bool,
pub(crate) separate_developer_instructions: bool,
pub(crate) memory: bool,
pub(crate) collaboration: bool,
pub(crate) realtime: bool,
pub(crate) personality: bool,
pub(crate) apps: bool,
pub(crate) skills: bool,
pub(crate) plugins: bool,
pub(crate) commit: bool,
pub(crate) user_instructions: bool,
pub(crate) environment_context: bool,
}
impl InitialContextInclusions {
pub(crate) const fn full() -> Self {
Self {
model_update: true,
permissions: true,
developer_instructions: true,
separate_developer_instructions: false,
memory: true,
collaboration: true,
realtime: true,
personality: true,
apps: true,
skills: true,
plugins: true,
commit: true,
user_instructions: true,
environment_context: true,
}
}
pub(crate) const fn none() -> Self {
Self {
model_update: false,
permissions: false,
developer_instructions: false,
separate_developer_instructions: false,
memory: false,
collaboration: false,
realtime: false,
personality: false,
apps: false,
skills: false,
plugins: false,
commit: false,
user_instructions: false,
environment_context: false,
}
}
}
+1
View File
@@ -38,6 +38,7 @@ mod flags;
mod git_info_tests;
mod guardian;
mod hook_runtime;
mod initial_context;
mod installation_id;
pub(crate) mod instructions;
pub(crate) mod landlock;
+2
View File
@@ -7,6 +7,7 @@ use crate::codex::INITIAL_SUBMIT_ID;
use crate::codex_thread::CodexThread;
use crate::config::Config;
use crate::file_watcher::FileWatcher;
use crate::initial_context::InitialContextInclusions;
use crate::mcp::McpManager;
use crate::plugins::PluginsManager;
use crate::rollout::RolloutRecorder;
@@ -899,6 +900,7 @@ impl ThreadManagerState {
codex, thread_id, ..
} = Codex::spawn(CodexSpawnArgs {
config,
initial_context_inclusions: InitialContextInclusions::full(),
auth_manager,
models_manager: Arc::clone(&self.models_manager),
environment_manager: Arc::clone(&self.environment_manager),