mirror of
https://github.com/openai/codex.git
synced 2026-10-18 17:18:52 +00:00
Pair thread environment settings (#26687)
## Why Thread cwd and environment selections are a single logical setting in core: updating one without the other can silently desynchronize the next-turn execution context. This change makes that relationship explicit in the internal thread settings flow while preserving the existing app-server public API shape. ## What changed - Moved the cwd/environment pair through internal `ThreadSettingsOverrides.environment_settings` instead of a top-level internal `cwd` field. - Kept `thread/settings/update` public params unchanged, with app-server translating top-level `cwd` into the paired internal settings shape. - Moved `Op::UserInput` environment overrides into thread settings so user turns and settings updates use the same core path. - Updated core, app-server, MCP, memories, sample, and test callsites to construct the paired settings shape. ## Verification - `git diff --check` - Local test run starting after PR creation.
This commit is contained in:
@@ -76,7 +76,7 @@ pub struct TurnStartParams {
|
||||
#[experimental("turn/start.additionalContext")]
|
||||
#[ts(optional = nullable)]
|
||||
pub additional_context: Option<HashMap<String, AdditionalContextEntry>>,
|
||||
/// Optional turn-scoped environments.
|
||||
/// Optional environments for this turn and subsequent turns.
|
||||
///
|
||||
/// Omitted uses the thread sticky environments. Empty disables
|
||||
/// environment access for this turn. Non-empty selects the first
|
||||
|
||||
@@ -767,7 +767,7 @@ pub(crate) async fn apply_bespoke_event_handling(
|
||||
let requested_permissions = request.permissions.clone();
|
||||
let request_cwd = match request.cwd.clone() {
|
||||
Some(cwd) => cwd,
|
||||
None => conversation.config_snapshot().await.cwd,
|
||||
None => conversation.config_snapshot().await.cwd().clone(),
|
||||
};
|
||||
let params = PermissionsRequestApprovalParams {
|
||||
thread_id: conversation_id.to_string(),
|
||||
@@ -1161,7 +1161,7 @@ pub(crate) async fn apply_bespoke_event_handling(
|
||||
return;
|
||||
}
|
||||
};
|
||||
let fallback_cwd = conversation.config_snapshot().await.cwd;
|
||||
let fallback_cwd = conversation.config_snapshot().await.cwd().clone();
|
||||
let stored_thread = match conversation
|
||||
.read_thread(
|
||||
/*include_archived*/ true, /*include_history*/ true,
|
||||
|
||||
@@ -330,6 +330,7 @@ use codex_core_plugins::remote::RemotePluginShareContext as RemoteCatalogPluginS
|
||||
use codex_core_plugins::remote::RemotePluginShareSummary as RemoteCatalogPluginShareSummary;
|
||||
use codex_core_plugins::remote::RemotePluginSummary as RemoteCatalogPluginSummary;
|
||||
use codex_exec_server::EnvironmentManager;
|
||||
use codex_exec_server::LOCAL_ENVIRONMENT_ID;
|
||||
use codex_exec_server::LOCAL_FS;
|
||||
use codex_features::FEATURES;
|
||||
use codex_features::Feature;
|
||||
@@ -400,6 +401,7 @@ use codex_protocol::protocol::SessionConfiguredEvent;
|
||||
#[cfg(test)]
|
||||
use codex_protocol::protocol::SessionMetaLine;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::protocol::USER_MESSAGE_BEGIN;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_protocol::user_input::MAX_USER_INPUT_TEXT_CHARS;
|
||||
|
||||
@@ -53,7 +53,7 @@ impl AppsRequestProcessor {
|
||||
None
|
||||
};
|
||||
let fallback_cwd = match thread.as_ref() {
|
||||
Some(thread) => Some(thread.config_snapshot().await.cwd.to_path_buf()),
|
||||
Some(thread) => Some(thread.config_snapshot().await.cwd().to_path_buf()),
|
||||
None => None,
|
||||
};
|
||||
let mut config = self.load_latest_config(fallback_cwd).await?;
|
||||
|
||||
@@ -627,6 +627,8 @@ pub(super) async fn handle_pending_thread_resume_request(
|
||||
}
|
||||
}
|
||||
|
||||
let config_snapshot = pending.config_snapshot;
|
||||
let cwd = config_snapshot.cwd().clone();
|
||||
let ThreadConfigSnapshot {
|
||||
model,
|
||||
model_provider_id,
|
||||
@@ -635,11 +637,10 @@ pub(super) async fn handle_pending_thread_resume_request(
|
||||
approvals_reviewer,
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
cwd,
|
||||
workspace_roots,
|
||||
reasoning_effort,
|
||||
..
|
||||
} = pending.config_snapshot;
|
||||
} = config_snapshot;
|
||||
let instruction_sources = pending.instruction_sources;
|
||||
let sandbox = thread_response_sandbox_policy(&permission_profile, cwd.as_path());
|
||||
let active_permission_profile =
|
||||
|
||||
@@ -47,11 +47,11 @@ fn collect_resume_override_mismatches(
|
||||
}
|
||||
if let Some(requested_cwd) = request.cwd.as_deref() {
|
||||
let requested_cwd_path = std::path::PathBuf::from(requested_cwd);
|
||||
if requested_cwd_path != config_snapshot.cwd.as_path() {
|
||||
if requested_cwd_path != config_snapshot.cwd().as_path() {
|
||||
mismatch_details.push(format!(
|
||||
"cwd requested={} active={}",
|
||||
requested_cwd_path.display(),
|
||||
config_snapshot.cwd.display()
|
||||
config_snapshot.cwd().display()
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -1154,8 +1154,9 @@ impl ThreadRequestProcessor {
|
||||
|
||||
let sandbox = thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
config_snapshot.cwd().as_path(),
|
||||
);
|
||||
let cwd = config_snapshot.cwd().clone();
|
||||
let active_permission_profile =
|
||||
thread_response_active_permission_profile(config_snapshot.active_permission_profile);
|
||||
|
||||
@@ -1164,7 +1165,7 @@ impl ThreadRequestProcessor {
|
||||
model: config_snapshot.model,
|
||||
model_provider: config_snapshot.model_provider_id,
|
||||
service_tier: config_snapshot.service_tier,
|
||||
cwd: config_snapshot.cwd,
|
||||
cwd,
|
||||
runtime_workspace_roots: config_snapshot.workspace_roots,
|
||||
instruction_sources,
|
||||
approval_policy: config_snapshot.approval_policy.into(),
|
||||
@@ -2601,7 +2602,7 @@ impl ThreadRequestProcessor {
|
||||
let config_snapshot = codex_thread.config_snapshot().await;
|
||||
let sandbox = thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
config_snapshot.cwd().as_path(),
|
||||
);
|
||||
let active_permission_profile = thread_response_active_permission_profile(
|
||||
config_snapshot.active_permission_profile,
|
||||
@@ -3335,7 +3336,7 @@ impl ThreadRequestProcessor {
|
||||
let config_snapshot = forked_thread.config_snapshot().await;
|
||||
let sandbox = thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
config_snapshot.cwd().as_path(),
|
||||
);
|
||||
let active_permission_profile =
|
||||
thread_response_active_permission_profile(config_snapshot.active_permission_profile);
|
||||
@@ -4205,7 +4206,7 @@ fn build_thread_from_snapshot(
|
||||
updated_at: now,
|
||||
status: ThreadStatus::NotLoaded,
|
||||
path,
|
||||
cwd: config_snapshot.cwd.clone(),
|
||||
cwd: config_snapshot.cwd().clone(),
|
||||
cli_version: env!("CARGO_PKG_VERSION").to_string(),
|
||||
agent_nickname: config_snapshot.session_source.get_nickname(),
|
||||
agent_role: config_snapshot.session_source.get_agent_role(),
|
||||
|
||||
@@ -77,6 +77,7 @@ mod thread_processor_behavior_tests {
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::SubAgentSource;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_state::ThreadMetadataBuilder;
|
||||
use codex_thread_store::StoredThread;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
@@ -685,7 +686,7 @@ mod thread_processor_behavior_tests {
|
||||
approvals_reviewer: codex_protocol::config_types::ApprovalsReviewer::User,
|
||||
permission_profile: codex_protocol::models::PermissionProfile::Disabled,
|
||||
active_permission_profile: None,
|
||||
cwd,
|
||||
environments: TurnEnvironmentSelections::new(cwd, Vec::new()),
|
||||
workspace_roots: Vec::new(),
|
||||
profile_workspace_roots: Vec::new(),
|
||||
ephemeral: false,
|
||||
|
||||
@@ -190,12 +190,12 @@ pub(crate) fn thread_settings_from_config_snapshot(
|
||||
config_snapshot: &ThreadConfigSnapshot,
|
||||
) -> ThreadSettings {
|
||||
ThreadSettings {
|
||||
cwd: config_snapshot.cwd.clone(),
|
||||
cwd: config_snapshot.cwd().clone(),
|
||||
approval_policy: config_snapshot.approval_policy.into(),
|
||||
approvals_reviewer: config_snapshot.approvals_reviewer.into(),
|
||||
sandbox_policy: thread_response_sandbox_policy(
|
||||
&config_snapshot.permission_profile,
|
||||
config_snapshot.cwd.as_path(),
|
||||
config_snapshot.cwd().as_path(),
|
||||
),
|
||||
active_permission_profile: thread_response_active_permission_profile(
|
||||
config_snapshot.active_permission_profile.clone(),
|
||||
@@ -213,24 +213,36 @@ pub(crate) fn thread_settings_from_config_snapshot(
|
||||
pub(crate) fn thread_settings_from_core_snapshot(
|
||||
snapshot: codex_protocol::protocol::ThreadSettingsSnapshot,
|
||||
) -> ThreadSettings {
|
||||
let codex_protocol::protocol::ThreadSettingsSnapshot {
|
||||
model,
|
||||
model_provider_id,
|
||||
service_tier,
|
||||
approval_policy,
|
||||
approvals_reviewer,
|
||||
permission_profile,
|
||||
active_permission_profile,
|
||||
cwd,
|
||||
reasoning_effort,
|
||||
reasoning_summary,
|
||||
personality,
|
||||
collaboration_mode,
|
||||
} = snapshot;
|
||||
let sandbox_policy = thread_response_sandbox_policy(&permission_profile, cwd.as_path());
|
||||
ThreadSettings {
|
||||
sandbox_policy: thread_response_sandbox_policy(
|
||||
&snapshot.permission_profile,
|
||||
snapshot.cwd.as_path(),
|
||||
),
|
||||
cwd: snapshot.cwd,
|
||||
approval_policy: snapshot.approval_policy.into(),
|
||||
approvals_reviewer: snapshot.approvals_reviewer.into(),
|
||||
sandbox_policy,
|
||||
cwd,
|
||||
approval_policy: approval_policy.into(),
|
||||
approvals_reviewer: approvals_reviewer.into(),
|
||||
active_permission_profile: thread_response_active_permission_profile(
|
||||
snapshot.active_permission_profile,
|
||||
active_permission_profile,
|
||||
),
|
||||
model: snapshot.model,
|
||||
model_provider: snapshot.model_provider_id,
|
||||
service_tier: snapshot.service_tier,
|
||||
effort: snapshot.reasoning_effort,
|
||||
summary: snapshot.reasoning_summary,
|
||||
collaboration_mode: snapshot.collaboration_mode,
|
||||
personality: snapshot.personality,
|
||||
model,
|
||||
model_provider: model_provider_id,
|
||||
service_tier,
|
||||
effort: reasoning_effort,
|
||||
summary: reasoning_summary,
|
||||
collaboration_mode,
|
||||
personality,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -43,7 +43,7 @@ fn map_additional_context(
|
||||
|
||||
struct ThreadSettingsBuildParams {
|
||||
method: &'static str,
|
||||
cwd: Option<AbsolutePathBuf>,
|
||||
environments: Option<TurnEnvironmentSelections>,
|
||||
runtime_workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
approval_policy: Option<codex_app_server_protocol::AskForApproval>,
|
||||
approvals_reviewer: Option<codex_app_server_protocol::ApprovalsReviewer>,
|
||||
@@ -406,12 +406,14 @@ impl TurnRequestProcessor {
|
||||
let additional_context = map_additional_context(params.additional_context);
|
||||
let turn_has_input = !mapped_items.is_empty();
|
||||
let cwd = resolve_request_cwd(params.cwd)?;
|
||||
let environments =
|
||||
Self::build_environment_override(thread.as_ref(), cwd, environment_selections).await;
|
||||
let thread_settings = self
|
||||
.build_thread_settings_overrides(
|
||||
thread.as_ref(),
|
||||
ThreadSettingsBuildParams {
|
||||
method: "turn/start",
|
||||
cwd,
|
||||
environments,
|
||||
runtime_workspace_roots: params.runtime_workspace_roots,
|
||||
approval_policy: params.approval_policy,
|
||||
approvals_reviewer: params.approvals_reviewer,
|
||||
@@ -430,7 +432,6 @@ impl TurnRequestProcessor {
|
||||
// Start the turn by submitting the user input. Return its submission id as turn_id.
|
||||
let turn_op = Op::UserInput {
|
||||
items: mapped_items,
|
||||
environments: environment_selections,
|
||||
final_output_json_schema: params.output_schema,
|
||||
responsesapi_client_metadata: params.responsesapi_client_metadata,
|
||||
additional_context,
|
||||
@@ -478,6 +479,31 @@ impl TurnRequestProcessor {
|
||||
Ok(TurnStartResponse { turn })
|
||||
}
|
||||
|
||||
async fn build_environment_override(
|
||||
thread: &CodexThread,
|
||||
cwd: Option<AbsolutePathBuf>,
|
||||
environment_selections: Option<Vec<TurnEnvironmentSelection>>,
|
||||
) -> Option<TurnEnvironmentSelections> {
|
||||
if cwd.is_none() && environment_selections.is_none() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let snapshot = thread.config_snapshot().await;
|
||||
let environment_selections =
|
||||
environment_selections.unwrap_or_else(|| snapshot.environment_selections().to_vec());
|
||||
let legacy_fallback_cwd = cwd.unwrap_or_else(|| {
|
||||
environment_selections
|
||||
.iter()
|
||||
.find(|selection| selection.environment_id == LOCAL_ENVIRONMENT_ID)
|
||||
.map(|selection| selection.cwd.clone())
|
||||
.unwrap_or_else(|| snapshot.cwd().clone())
|
||||
});
|
||||
Some(TurnEnvironmentSelections::new(
|
||||
legacy_fallback_cwd,
|
||||
environment_selections,
|
||||
))
|
||||
}
|
||||
|
||||
async fn build_thread_settings_overrides(
|
||||
&self,
|
||||
thread: &CodexThread,
|
||||
@@ -485,7 +511,7 @@ impl TurnRequestProcessor {
|
||||
) -> Result<codex_protocol::protocol::ThreadSettingsOverrides, JSONRPCErrorError> {
|
||||
let ThreadSettingsBuildParams {
|
||||
method,
|
||||
cwd,
|
||||
environments,
|
||||
runtime_workspace_roots,
|
||||
approval_policy,
|
||||
approvals_reviewer,
|
||||
@@ -508,6 +534,7 @@ impl TurnRequestProcessor {
|
||||
let collaboration_mode =
|
||||
collaboration_mode.map(|mode| self.normalize_collaboration_mode(mode));
|
||||
let runtime_workspace_roots_request = runtime_workspace_roots;
|
||||
let has_environment_override = environments.is_some();
|
||||
// `thread/settings/update` only acknowledges that the update was queued.
|
||||
// Clients that send dependent partial updates should wait for
|
||||
// `thread/settings/updated` or combine the fields in one request.
|
||||
@@ -517,7 +544,7 @@ impl TurnRequestProcessor {
|
||||
None
|
||||
};
|
||||
|
||||
let has_any_overrides = cwd.is_some()
|
||||
let has_any_overrides = has_environment_override
|
||||
|| runtime_workspace_roots_request.is_some()
|
||||
|| approval_policy.is_some()
|
||||
|| approvals_reviewer.is_some()
|
||||
@@ -545,7 +572,9 @@ impl TurnRequestProcessor {
|
||||
)));
|
||||
};
|
||||
let overrides = ConfigOverrides {
|
||||
cwd: cwd.as_ref().map(AbsolutePathBuf::to_path_buf),
|
||||
cwd: environments
|
||||
.as_ref()
|
||||
.map(|environments| environments.legacy_fallback_cwd.to_path_buf()),
|
||||
workspace_roots: Some(
|
||||
runtime_workspace_roots
|
||||
.clone()
|
||||
@@ -561,7 +590,7 @@ impl TurnRequestProcessor {
|
||||
.load_for_cwd(
|
||||
/*request_overrides*/ None,
|
||||
overrides,
|
||||
Some(snapshot.cwd.to_path_buf()),
|
||||
Some(snapshot.cwd().to_path_buf()),
|
||||
)
|
||||
.await
|
||||
.map_err(|err| config_load_error(&err))?;
|
||||
@@ -588,7 +617,7 @@ impl TurnRequestProcessor {
|
||||
if has_any_overrides {
|
||||
thread
|
||||
.preview_thread_settings_overrides(CodexThreadSettingsOverrides {
|
||||
cwd: cwd.clone(),
|
||||
environments: environments.clone(),
|
||||
workspace_roots: runtime_workspace_roots.clone(),
|
||||
approval_policy,
|
||||
approvals_reviewer,
|
||||
@@ -611,7 +640,7 @@ impl TurnRequestProcessor {
|
||||
}
|
||||
|
||||
Ok(codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd,
|
||||
environments,
|
||||
workspace_roots: runtime_workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
@@ -636,12 +665,18 @@ impl TurnRequestProcessor {
|
||||
) -> Result<ThreadSettingsUpdateResponse, JSONRPCErrorError> {
|
||||
let (_, thread) = self.load_thread(¶ms.thread_id).await?;
|
||||
let cwd = resolve_request_cwd(params.cwd)?;
|
||||
let environments = Self::build_environment_override(
|
||||
thread.as_ref(),
|
||||
cwd,
|
||||
/*environment_selections*/ None,
|
||||
)
|
||||
.await;
|
||||
let thread_settings = self
|
||||
.build_thread_settings_overrides(
|
||||
thread.as_ref(),
|
||||
ThreadSettingsBuildParams {
|
||||
method: "thread/settings/update",
|
||||
cwd,
|
||||
environments,
|
||||
runtime_workspace_roots: None,
|
||||
approval_policy: params.approval_policy,
|
||||
approvals_reviewer: params.approvals_reviewer,
|
||||
|
||||
@@ -458,7 +458,6 @@ async fn send_input_submits_user_message() {
|
||||
let expected = (
|
||||
thread_id,
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello from tests".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -797,7 +796,6 @@ async fn spawn_agent_creates_thread_and_sends_prompt() {
|
||||
let expected = (
|
||||
thread_id,
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "spawned".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1017,7 +1015,6 @@ async fn spawn_agent_can_fork_parent_thread_history_with_sanitized_items() {
|
||||
let expected = (
|
||||
child_thread_id,
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "child task".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -196,7 +196,6 @@ pub(crate) async fn run_codex_thread_one_shot(
|
||||
|
||||
// Send the initial input to kick off the one-shot turn.
|
||||
io.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: input,
|
||||
final_output_json_schema,
|
||||
responsesapi_client_metadata: None,
|
||||
|
||||
@@ -32,6 +32,7 @@ use codex_protocol::protocol::ThreadMemoryMode;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TokenUsageInfo;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_thread_store::StoredThread;
|
||||
@@ -59,7 +60,7 @@ pub struct ThreadConfigSnapshot {
|
||||
pub approvals_reviewer: ApprovalsReviewer,
|
||||
pub permission_profile: PermissionProfile,
|
||||
pub active_permission_profile: Option<ActivePermissionProfile>,
|
||||
pub cwd: AbsolutePathBuf,
|
||||
pub environments: TurnEnvironmentSelections,
|
||||
pub workspace_roots: Vec<AbsolutePathBuf>,
|
||||
pub profile_workspace_roots: Vec<AbsolutePathBuf>,
|
||||
pub ephemeral: bool,
|
||||
@@ -114,10 +115,18 @@ impl TryStartTurnIfIdleError {
|
||||
}
|
||||
|
||||
impl ThreadConfigSnapshot {
|
||||
pub fn cwd(&self) -> &AbsolutePathBuf {
|
||||
&self.environments.legacy_fallback_cwd
|
||||
}
|
||||
|
||||
pub fn environment_selections(&self) -> &[TurnEnvironmentSelection] {
|
||||
&self.environments.environments
|
||||
}
|
||||
|
||||
pub fn sandbox_policy(&self) -> SandboxPolicy {
|
||||
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
|
||||
&self.permission_profile,
|
||||
self.cwd.as_path(),
|
||||
self.cwd().as_path(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -125,7 +134,7 @@ impl ThreadConfigSnapshot {
|
||||
/// Thread settings overrides that app-server validates before starting a turn.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct CodexThreadSettingsOverrides {
|
||||
pub cwd: Option<AbsolutePathBuf>,
|
||||
pub environments: Option<TurnEnvironmentSelections>,
|
||||
pub workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub profile_workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub approval_policy: Option<AskForApproval>,
|
||||
@@ -330,7 +339,7 @@ impl CodexThread {
|
||||
overrides: CodexThreadSettingsOverrides,
|
||||
) -> SessionSettingsUpdate {
|
||||
let CodexThreadSettingsOverrides {
|
||||
cwd,
|
||||
environments,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
@@ -357,7 +366,7 @@ impl CodexThread {
|
||||
};
|
||||
|
||||
SessionSettingsUpdate {
|
||||
cwd,
|
||||
environments,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
|
||||
@@ -721,19 +721,27 @@ async fn run_review_on_session(
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
let guardian_permission_profile = PermissionProfile::read_only();
|
||||
let parent_turn_environments = params.parent_turn.environments.to_selections();
|
||||
let parent_turn_legacy_fallback_cwd = params
|
||||
.parent_turn
|
||||
.environments
|
||||
.primary()
|
||||
.map(|environment| environment.cwd.clone())
|
||||
.unwrap_or_else(|| params.parent_turn.config.cwd.clone());
|
||||
|
||||
let submit_result = run_before_review_deadline(
|
||||
deadline,
|
||||
params.external_cancel.as_ref(),
|
||||
Box::pin(review_session.codex.submit(Op::UserInput {
|
||||
items: prompt_items.items,
|
||||
environments: None,
|
||||
final_output_json_schema: Some(params.schema.clone()),
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
#[allow(deprecated)]
|
||||
cwd: Some(params.parent_turn.cwd.clone()),
|
||||
environments: Some(codex_protocol::protocol::TurnEnvironmentSelections::new(
|
||||
parent_turn_legacy_fallback_cwd,
|
||||
parent_turn_environments,
|
||||
)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: None,
|
||||
permission_profile: Some(guardian_permission_profile),
|
||||
|
||||
@@ -122,7 +122,7 @@ async fn thread_settings_update(
|
||||
thread_settings: ThreadSettingsOverrides,
|
||||
) -> SessionSettingsUpdate {
|
||||
let ThreadSettingsOverrides {
|
||||
cwd,
|
||||
environments,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
@@ -151,7 +151,7 @@ async fn thread_settings_update(
|
||||
}
|
||||
};
|
||||
SessionSettingsUpdate {
|
||||
cwd,
|
||||
environments,
|
||||
workspace_roots,
|
||||
profile_workspace_roots,
|
||||
approval_policy,
|
||||
@@ -173,6 +173,7 @@ async fn thread_settings_applied_event(sess: &Session) -> EventMsg {
|
||||
let state = sess.state.lock().await;
|
||||
state.session_configuration.thread_config_snapshot()
|
||||
};
|
||||
let cwd = snapshot.cwd().clone();
|
||||
EventMsg::ThreadSettingsApplied(ThreadSettingsAppliedEvent {
|
||||
thread_settings: ThreadSettingsSnapshot {
|
||||
model: snapshot.model,
|
||||
@@ -182,7 +183,7 @@ async fn thread_settings_applied_event(sess: &Session) -> EventMsg {
|
||||
approvals_reviewer: snapshot.approvals_reviewer,
|
||||
permission_profile: snapshot.permission_profile,
|
||||
active_permission_profile: snapshot.active_permission_profile,
|
||||
cwd: snapshot.cwd,
|
||||
cwd,
|
||||
reasoning_effort: snapshot.reasoning_effort,
|
||||
reasoning_summary: snapshot.reasoning_summary,
|
||||
personality: snapshot.personality,
|
||||
@@ -200,7 +201,6 @@ pub(super) async fn user_input_or_turn_inner(
|
||||
) {
|
||||
let Op::UserInput {
|
||||
items,
|
||||
environments,
|
||||
final_output_json_schema,
|
||||
responsesapi_client_metadata,
|
||||
additional_context,
|
||||
@@ -216,7 +216,6 @@ pub(super) async fn user_input_or_turn_inner(
|
||||
SessionSettingsUpdate::default()
|
||||
};
|
||||
updates.final_output_json_schema = Some(final_output_json_schema);
|
||||
updates.environments = environments;
|
||||
|
||||
let Ok(current_context) = sess.new_turn_with_sub_id(sub_id.clone(), updates).await else {
|
||||
// new_turn_with_sub_id already emits the error event.
|
||||
|
||||
@@ -116,6 +116,7 @@ use codex_protocol::protocol::TurnAbortReason;
|
||||
use codex_protocol::protocol::TurnContextItem;
|
||||
use codex_protocol::protocol::TurnContextNetworkItem;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::protocol::W3cTraceContext;
|
||||
use codex_protocol::request_permissions::PermissionGrantScope;
|
||||
use codex_protocol::request_permissions::RequestPermissionProfile;
|
||||
@@ -602,11 +603,13 @@ impl Codex {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: session_permission_profile_state_from_config(&config)?,
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(
|
||||
config.cwd.clone(),
|
||||
environment_selections.to_selections(),
|
||||
),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: environment_selections.to_selections(),
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name,
|
||||
app_server_client_name: None,
|
||||
@@ -814,7 +817,10 @@ impl Codex {
|
||||
|
||||
pub(crate) async fn thread_environment_selections(&self) -> Vec<TurnEnvironmentSelection> {
|
||||
let state = self.session.state.lock().await;
|
||||
state.session_configuration.environments.clone()
|
||||
state
|
||||
.session_configuration
|
||||
.environment_selections()
|
||||
.to_vec()
|
||||
}
|
||||
|
||||
pub(crate) fn state_db(&self) -> Option<state_db::StateDbHandle> {
|
||||
@@ -1114,7 +1120,6 @@ impl Session {
|
||||
self,
|
||||
self.next_internal_sub_id(),
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text,
|
||||
text_elements: Vec::new(),
|
||||
@@ -1414,12 +1419,12 @@ impl Session {
|
||||
.then(|| Self::build_effective_session_config(&state.session_configuration));
|
||||
let new_config =
|
||||
notify_config_contributors.then(|| Self::build_effective_session_config(&updated));
|
||||
let previous_cwd = state.session_configuration.cwd.clone();
|
||||
let previous_cwd = state.session_configuration.cwd().clone();
|
||||
let previous_permission_profile = state.session_configuration.permission_profile();
|
||||
let updated_permission_profile = updated.permission_profile();
|
||||
let permission_profile_changed =
|
||||
previous_permission_profile != updated_permission_profile;
|
||||
let next_cwd = updated.cwd.clone();
|
||||
let next_cwd = updated.cwd().clone();
|
||||
let codex_home = updated.codex_home.clone();
|
||||
let session_source = updated.session_source.clone();
|
||||
state.session_configuration = updated;
|
||||
|
||||
@@ -12,6 +12,7 @@ use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::protocol::MultiAgentVersion;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use std::sync::OnceLock;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
@@ -75,11 +76,9 @@ pub(crate) struct SessionConfiguration {
|
||||
pub(super) permission_profile_state: PermissionProfileState,
|
||||
pub(super) windows_sandbox_level: WindowsSandboxLevel,
|
||||
|
||||
/// Absolute working directory that should be treated as the *root* of the
|
||||
/// session. All relative paths supplied by the model as well as the
|
||||
/// execution sandbox are resolved against this directory **instead** of
|
||||
/// the process-wide current working directory.
|
||||
pub(super) cwd: AbsolutePathBuf,
|
||||
/// Sticky thread-level environment selections plus the legacy cwd used
|
||||
/// when a turn does not select an environment.
|
||||
pub(super) environments: TurnEnvironmentSelections,
|
||||
/// Thread-scoped runtime workspace roots for materializing symbolic
|
||||
/// workspace permissions at session runtime.
|
||||
pub(super) workspace_roots: Vec<AbsolutePathBuf>,
|
||||
@@ -87,8 +86,6 @@ pub(crate) struct SessionConfiguration {
|
||||
pub(super) codex_home: AbsolutePathBuf,
|
||||
/// Optional user-facing name for the thread, updated during the session.
|
||||
pub(super) thread_name: Option<String>,
|
||||
/// Sticky environments for turns that do not provide a turn-local override.
|
||||
pub(super) environments: Vec<TurnEnvironmentSelection>,
|
||||
|
||||
// TODO(pakrym): Remove config from here
|
||||
pub(super) original_config_do_not_use: Arc<Config>,
|
||||
@@ -110,6 +107,14 @@ pub(crate) struct SessionConfiguration {
|
||||
}
|
||||
|
||||
impl SessionConfiguration {
|
||||
pub(super) fn cwd(&self) -> &AbsolutePathBuf {
|
||||
&self.environments.legacy_fallback_cwd
|
||||
}
|
||||
|
||||
pub(super) fn environment_selections(&self) -> &[TurnEnvironmentSelection] {
|
||||
&self.environments.environments
|
||||
}
|
||||
|
||||
pub(crate) fn codex_home(&self) -> &AbsolutePathBuf {
|
||||
&self.codex_home
|
||||
}
|
||||
@@ -153,7 +158,7 @@ impl SessionConfiguration {
|
||||
let permission_profile = self.permission_profile();
|
||||
codex_sandboxing::compatibility_sandbox_policy_for_permission_profile(
|
||||
&permission_profile,
|
||||
&self.cwd,
|
||||
self.cwd(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -176,7 +181,7 @@ impl SessionConfiguration {
|
||||
approvals_reviewer: self.approvals_reviewer,
|
||||
permission_profile: self.permission_profile(),
|
||||
active_permission_profile: self.active_permission_profile(),
|
||||
cwd: self.cwd.clone(),
|
||||
environments: self.environments.clone(),
|
||||
workspace_roots: self.workspace_roots.clone(),
|
||||
profile_workspace_roots: self.profile_workspace_roots().to_vec(),
|
||||
ephemeral: self.original_config_do_not_use.ephemeral,
|
||||
@@ -199,11 +204,11 @@ impl SessionConfiguration {
|
||||
let legacy_file_system_projection =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
¤t_sandbox_policy,
|
||||
&self.cwd,
|
||||
self.cwd(),
|
||||
¤t_file_system_sandbox_policy,
|
||||
);
|
||||
let file_system_policy_matches_legacy = current_file_system_sandbox_policy
|
||||
.is_semantically_equivalent_to(&legacy_file_system_projection, &self.cwd);
|
||||
.is_semantically_equivalent_to(&legacy_file_system_projection, self.cwd());
|
||||
let file_system_policy_has_rebindable_project_root_write =
|
||||
current_file_system_sandbox_policy
|
||||
.entries
|
||||
@@ -249,18 +254,21 @@ impl SessionConfiguration {
|
||||
next_configuration.windows_sandbox_level = windows_sandbox_level;
|
||||
}
|
||||
|
||||
let absolute_cwd = updates.cwd.clone().unwrap_or_else(|| self.cwd.clone());
|
||||
|
||||
let cwd_changed = absolute_cwd.as_path() != self.cwd.as_path();
|
||||
next_configuration.cwd = absolute_cwd;
|
||||
let current_cwd = self.cwd().clone();
|
||||
let next_environments = updates
|
||||
.environments
|
||||
.clone()
|
||||
.unwrap_or_else(|| self.environments.clone());
|
||||
let cwd_changed = next_environments.legacy_fallback_cwd.as_path() != current_cwd.as_path();
|
||||
next_configuration.environments = next_environments;
|
||||
if let Some(workspace_roots) = updates.workspace_roots.clone() {
|
||||
next_configuration.workspace_roots = workspace_roots;
|
||||
} else if cwd_changed && self.workspace_roots.contains(&self.cwd) {
|
||||
} else if cwd_changed && self.workspace_roots.contains(¤t_cwd) {
|
||||
let mut retargeted_workspace_roots =
|
||||
Vec::with_capacity(next_configuration.workspace_roots.len());
|
||||
for root in &self.workspace_roots {
|
||||
let root = if root == &self.cwd {
|
||||
next_configuration.cwd.clone()
|
||||
let root = if root == ¤t_cwd {
|
||||
next_configuration.cwd().clone()
|
||||
} else {
|
||||
root.clone()
|
||||
};
|
||||
@@ -317,7 +325,7 @@ impl SessionConfiguration {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
&sandbox_policy,
|
||||
&next_configuration.cwd,
|
||||
next_configuration.cwd(),
|
||||
¤t_file_system_sandbox_policy,
|
||||
);
|
||||
let network_sandbox_policy = NetworkSandboxPolicy::from(&sandbox_policy);
|
||||
@@ -340,7 +348,7 @@ impl SessionConfiguration {
|
||||
let file_system_sandbox_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_preserving_deny_entries(
|
||||
¤t_sandbox_policy,
|
||||
&next_configuration.cwd,
|
||||
next_configuration.cwd(),
|
||||
¤t_file_system_sandbox_policy,
|
||||
);
|
||||
next_configuration
|
||||
@@ -401,7 +409,7 @@ impl SessionConfiguration {
|
||||
|
||||
#[derive(Default, Clone)]
|
||||
pub(crate) struct SessionSettingsUpdate {
|
||||
pub(crate) cwd: Option<AbsolutePathBuf>,
|
||||
pub(crate) environments: Option<TurnEnvironmentSelections>,
|
||||
pub(crate) workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub(crate) profile_workspace_roots: Option<Vec<AbsolutePathBuf>>,
|
||||
pub(crate) approval_policy: Option<AskForApproval>,
|
||||
@@ -414,10 +422,6 @@ pub(crate) struct SessionSettingsUpdate {
|
||||
pub(crate) reasoning_summary: Option<ReasoningSummaryConfig>,
|
||||
pub(crate) service_tier: Option<Option<String>>,
|
||||
pub(crate) final_output_json_schema: Option<Option<Value>>,
|
||||
/// Turn-local environment override. `None` inherits the sticky thread
|
||||
/// environments stored on `SessionConfiguration`; `Some([])` explicitly
|
||||
/// disables environments for this turn.
|
||||
pub(crate) environments: Option<Vec<TurnEnvironmentSelection>>,
|
||||
pub(crate) personality: Option<Personality>,
|
||||
pub(crate) app_server_client_name: Option<String>,
|
||||
pub(crate) app_server_client_version: Option<String>,
|
||||
@@ -634,7 +638,7 @@ impl Session {
|
||||
Arc::clone(&environment_manager),
|
||||
Arc::clone(&plugins_manager),
|
||||
Arc::clone(&skills_manager),
|
||||
session_configuration.environments.clone(),
|
||||
session_configuration.environment_selections().to_vec(),
|
||||
)
|
||||
.instrument(info_span!(
|
||||
"session_init.plugin_skill_warmup",
|
||||
@@ -686,7 +690,7 @@ impl Session {
|
||||
nickname: session_configuration.session_source.get_nickname(),
|
||||
agent_role: session_configuration.session_source.get_agent_role(),
|
||||
session_source: session_configuration.session_source.clone(),
|
||||
cwd: session_configuration.cwd.to_path_buf(),
|
||||
cwd: session_configuration.cwd().to_path_buf(),
|
||||
rollout_path: rollout_path.clone(),
|
||||
model: session_configuration.collaboration_mode.model().to_string(),
|
||||
provider_name: config.model_provider_id.clone(),
|
||||
@@ -790,7 +794,7 @@ impl Session {
|
||||
/*inc*/ 1,
|
||||
&[(
|
||||
"is_git",
|
||||
if get_git_repo_root(&session_configuration.cwd).is_some() {
|
||||
if get_git_repo_root(session_configuration.cwd()).is_some() {
|
||||
"true"
|
||||
} else {
|
||||
"false"
|
||||
@@ -809,7 +813,7 @@ impl Session {
|
||||
config.permissions.approval_policy.value(),
|
||||
config
|
||||
.permissions
|
||||
.legacy_sandbox_policy(session_configuration.cwd.as_path()),
|
||||
.legacy_sandbox_policy(session_configuration.cwd().as_path()),
|
||||
mcp_servers.keys().map(String::as_str).collect(),
|
||||
);
|
||||
|
||||
@@ -844,7 +848,7 @@ impl Session {
|
||||
ShellSnapshot::start_snapshotting(
|
||||
config.codex_home.clone(),
|
||||
thread_id,
|
||||
session_configuration.cwd.clone(),
|
||||
session_configuration.cwd().clone(),
|
||||
&mut default_shell,
|
||||
session_telemetry.clone(),
|
||||
state_db_ctx.clone(),
|
||||
@@ -1089,7 +1093,7 @@ impl Session {
|
||||
approvals_reviewer: session_configuration.approvals_reviewer,
|
||||
permission_profile: session_configuration.permission_profile(),
|
||||
active_permission_profile: session_configuration.active_permission_profile(),
|
||||
cwd: session_configuration.cwd.clone(),
|
||||
cwd: session_configuration.cwd().clone(),
|
||||
reasoning_effort: session_configuration.collaboration_mode.reasoning_effort(),
|
||||
initial_messages,
|
||||
network_proxy: session_network_proxy.filter(|_| {
|
||||
@@ -1135,7 +1139,7 @@ impl Session {
|
||||
}
|
||||
let turn_environment = crate::environment_selection::resolve_environment_selections(
|
||||
sess.services.environment_manager.as_ref(),
|
||||
&session_configuration.environments,
|
||||
session_configuration.environment_selections(),
|
||||
)
|
||||
.map_err(|err| {
|
||||
CodexErr::InvalidRequest(err.to_string().replace(
|
||||
@@ -1152,7 +1156,7 @@ impl Session {
|
||||
),
|
||||
None => McpRuntimeContext::new(
|
||||
Arc::clone(&sess.services.environment_manager),
|
||||
session_configuration.cwd.to_path_buf(),
|
||||
session_configuration.cwd().to_path_buf(),
|
||||
),
|
||||
};
|
||||
let (mcp_connection_manager, cancel_token) = McpConnectionManager::new(
|
||||
|
||||
+135
-127
@@ -22,6 +22,7 @@ use codex_config::RequirementSource;
|
||||
use codex_config::Sourced;
|
||||
use codex_config::loader::project_trust_key;
|
||||
use codex_config::types::ToolSuggestDisabledTool;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
|
||||
use codex_features::Feature;
|
||||
use codex_login::CodexAuth;
|
||||
@@ -53,6 +54,7 @@ use codex_protocol::permissions::FileSystemSpecialPath;
|
||||
use codex_protocol::protocol::NonSteerableTurnKind;
|
||||
use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::request_permissions::PermissionGrantScope;
|
||||
use codex_protocol::request_permissions::RequestPermissionProfile;
|
||||
use tracing::Span;
|
||||
@@ -142,6 +144,7 @@ use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::test_codex::local;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_path_buf;
|
||||
use core_test_support::tracing::install_test_tracing;
|
||||
@@ -2392,7 +2395,8 @@ async fn session_permission_profile_rebinds_runtime_workspace_roots() -> anyhow:
|
||||
);
|
||||
|
||||
let mut session_configuration = make_session_configuration_for_tests().await;
|
||||
session_configuration.cwd = config.cwd.clone();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(config.cwd.clone(), Vec::new());
|
||||
session_configuration.workspace_roots = config.workspace_roots.clone();
|
||||
session_configuration.permission_profile_state = session_permission_profile_state;
|
||||
|
||||
@@ -2404,8 +2408,8 @@ async fn session_permission_profile_rebinds_runtime_workspace_roots() -> anyhow:
|
||||
..Default::default()
|
||||
})?;
|
||||
let updated_policy = updated.file_system_sandbox_policy();
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd().as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd().as_path()));
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -2437,7 +2441,6 @@ async fn fork_startup_context_then_first_turn_diff_snapshot() -> anyhow::Result<
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "fork seed".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2483,7 +2486,6 @@ async fn fork_startup_context_then_first_turn_diff_snapshot() -> anyhow::Result<
|
||||
forked
|
||||
.thread
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after fork".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3157,11 +3159,10 @@ async fn set_rate_limits_retains_previous_credits() {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), Vec::new()),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -3265,11 +3266,10 @@ async fn set_rate_limits_updates_plan_type_when_present() {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), Vec::new()),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -3797,11 +3797,10 @@ pub(crate) async fn make_session_configuration_for_tests() -> SessionConfigurati
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), Vec::new()),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -3920,7 +3919,8 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd
|
||||
let project_root = project_root.abs();
|
||||
let docs_dir = docs_dir.abs();
|
||||
|
||||
session_configuration.cwd = original_cwd.abs();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(original_cwd.abs(), Vec::new());
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
@@ -3954,7 +3954,7 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
cwd: Some(project_root),
|
||||
environments: Some(TurnEnvironmentSelections::new(project_root, Vec::new())),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("cwd-only update should succeed");
|
||||
@@ -3969,7 +3969,8 @@ async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd
|
||||
async fn session_configuration_apply_permission_profile_preserves_existing_deny_read_entries() {
|
||||
let mut session_configuration = make_session_configuration_for_tests().await;
|
||||
let cwd = tempfile::tempdir().expect("create temp dir");
|
||||
session_configuration.cwd = cwd.path().abs();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(cwd.path().abs(), Vec::new());
|
||||
|
||||
let workspace_policy = SandboxPolicy::new_workspace_write_policy();
|
||||
let deny_entry = FileSystemSandboxEntry {
|
||||
@@ -3981,7 +3982,7 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
|
||||
let mut existing_file_system_policy =
|
||||
FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&workspace_policy,
|
||||
session_configuration.cwd.as_path(),
|
||||
session_configuration.cwd().as_path(),
|
||||
);
|
||||
existing_file_system_policy.glob_scan_max_depth = Some(2);
|
||||
existing_file_system_policy.entries.push(deny_entry.clone());
|
||||
@@ -3997,7 +3998,7 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
|
||||
|
||||
let requested_file_system_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&workspace_policy,
|
||||
session_configuration.cwd.as_path(),
|
||||
session_configuration.cwd().as_path(),
|
||||
);
|
||||
let permission_profile = codex_protocol::models::PermissionProfile::from_runtime_permissions(
|
||||
&requested_file_system_policy,
|
||||
@@ -4024,7 +4025,8 @@ async fn session_configuration_apply_permission_profile_preserves_existing_deny_
|
||||
async fn session_configuration_apply_permission_profile_accepts_direct_write_roots() {
|
||||
let mut session_configuration = make_session_configuration_for_tests().await;
|
||||
let cwd = tempfile::tempdir().expect("create cwd");
|
||||
session_configuration.cwd = cwd.path().abs();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(cwd.path().abs(), Vec::new());
|
||||
let external_write_dir = tempfile::tempdir().expect("create external write root");
|
||||
let external_write_path = AbsolutePathBuf::from_absolute_path(
|
||||
codex_utils_absolute_path::canonicalize_preserving_symlinks(external_write_dir.path())
|
||||
@@ -4100,8 +4102,8 @@ async fn session_configuration_apply_rebinds_symbolic_profile_to_updated_workspa
|
||||
.expect("permission profile update should succeed");
|
||||
|
||||
let updated_policy = updated.file_system_sandbox_policy();
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd().as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd().as_path()));
|
||||
assert_eq!(
|
||||
updated.active_permission_profile(),
|
||||
Some(ActivePermissionProfile::new("dev"))
|
||||
@@ -4118,7 +4120,8 @@ async fn session_configuration_apply_retargets_implicit_workspace_root_on_cwd_up
|
||||
let old_root = old_root.path().abs();
|
||||
let new_root = new_root.path().abs();
|
||||
let extra_root = extra_root.path().abs();
|
||||
session_configuration.cwd = old_root.clone();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(old_root.clone(), Vec::new());
|
||||
session_configuration.workspace_roots = vec![old_root.clone(), extra_root.clone()];
|
||||
|
||||
let file_system_sandbox_policy =
|
||||
@@ -4138,7 +4141,7 @@ async fn session_configuration_apply_retargets_implicit_workspace_root_on_cwd_up
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
cwd: Some(new_root.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(new_root.clone(), Vec::new())),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("cwd-only update should succeed");
|
||||
@@ -4148,9 +4151,9 @@ async fn session_configuration_apply_retargets_implicit_workspace_root_on_cwd_up
|
||||
vec![new_root.clone(), extra_root.clone()]
|
||||
);
|
||||
let updated_policy = updated.file_system_sandbox_policy();
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(updated_policy.can_write_path_with_cwd(extra_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd.as_path()));
|
||||
assert!(updated_policy.can_write_path_with_cwd(new_root.as_path(), updated.cwd().as_path()));
|
||||
assert!(updated_policy.can_write_path_with_cwd(extra_root.as_path(), updated.cwd().as_path()));
|
||||
assert!(!updated_policy.can_write_path_with_cwd(old_root.as_path(), updated.cwd().as_path()));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -4353,8 +4356,9 @@ async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_upda
|
||||
let workspace = tempfile::tempdir().expect("create temp dir");
|
||||
let original_cwd = workspace.path().join("repo-a").abs();
|
||||
let project_root = workspace.path().join("repo-b").abs();
|
||||
session_configuration.cwd = original_cwd.clone();
|
||||
session_configuration.workspace_roots = vec![session_configuration.cwd.clone()];
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(original_cwd.clone(), Vec::new());
|
||||
session_configuration.workspace_roots = vec![session_configuration.cwd().clone()];
|
||||
let sandbox_policy = SandboxPolicy::WorkspaceWrite {
|
||||
writable_roots: Vec::new(),
|
||||
network_access: false,
|
||||
@@ -4363,7 +4367,7 @@ async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_upda
|
||||
};
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::from_legacy_sandbox_policy_for_cwd(
|
||||
&sandbox_policy,
|
||||
&session_configuration.cwd,
|
||||
session_configuration.cwd(),
|
||||
);
|
||||
session_configuration
|
||||
.set_permission_profile_for_tests(
|
||||
@@ -4377,7 +4381,10 @@ async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_upda
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
cwd: Some(project_root.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
project_root.clone(),
|
||||
Vec::new(),
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("cwd-only update should succeed");
|
||||
@@ -4386,13 +4393,13 @@ async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_upda
|
||||
assert!(
|
||||
updated
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_path_with_cwd(project_root.as_path(), updated.cwd.as_path()),
|
||||
.can_write_path_with_cwd(project_root.as_path(), updated.cwd().as_path()),
|
||||
"cwd-only update should keep the new cwd writable"
|
||||
);
|
||||
assert!(
|
||||
!updated
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_path_with_cwd(original_cwd.as_path(), updated.cwd.as_path()),
|
||||
.can_write_path_with_cwd(original_cwd.as_path(), updated.cwd().as_path()),
|
||||
"cwd-only update should not keep the old implicit cwd writable"
|
||||
);
|
||||
}
|
||||
@@ -4408,7 +4415,8 @@ async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_up
|
||||
let original_cwd = original_cwd.abs();
|
||||
let next_cwd = next_cwd.abs();
|
||||
|
||||
session_configuration.cwd = original_cwd.clone();
|
||||
session_configuration.environments =
|
||||
TurnEnvironmentSelections::new(original_cwd.clone(), Vec::new());
|
||||
let file_system_sandbox_policy = FileSystemSandboxPolicy::restricted(vec![
|
||||
FileSystemSandboxEntry {
|
||||
path: FileSystemPath::Special {
|
||||
@@ -4435,7 +4443,7 @@ async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_up
|
||||
|
||||
let updated = session_configuration
|
||||
.apply(&SessionSettingsUpdate {
|
||||
cwd: Some(next_cwd.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(next_cwd.clone(), Vec::new())),
|
||||
..Default::default()
|
||||
})
|
||||
.expect("cwd-only update should succeed");
|
||||
@@ -4447,13 +4455,13 @@ async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_up
|
||||
assert!(
|
||||
updated
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_path_with_cwd(original_cwd.as_path(), updated.cwd.as_path()),
|
||||
.can_write_path_with_cwd(original_cwd.as_path(), updated.cwd().as_path()),
|
||||
"absolute grant to the old cwd must remain writable"
|
||||
);
|
||||
assert!(
|
||||
!updated
|
||||
.file_system_sandbox_policy()
|
||||
.can_write_path_with_cwd(next_cwd.as_path(), updated.cwd.as_path()),
|
||||
.can_write_path_with_cwd(next_cwd.as_path(), updated.cwd().as_path()),
|
||||
"cwd-only update must not reinterpret an absolute old-cwd grant as :workspace_roots"
|
||||
);
|
||||
}
|
||||
@@ -4463,11 +4471,21 @@ async fn session_update_settings_does_not_rewrite_sticky_environment_cwds() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
#[allow(deprecated)]
|
||||
let updated_cwd = turn_context.cwd.join("project");
|
||||
let current_environments = {
|
||||
let state = session.state.lock().await;
|
||||
state
|
||||
.session_configuration
|
||||
.environment_selections()
|
||||
.to_vec()
|
||||
};
|
||||
std::fs::create_dir_all(updated_cwd.as_path()).expect("create project dir");
|
||||
|
||||
session
|
||||
.update_settings(SessionSettingsUpdate {
|
||||
cwd: Some(updated_cwd.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
updated_cwd.clone(),
|
||||
current_environments,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
@@ -4475,7 +4493,7 @@ async fn session_update_settings_does_not_rewrite_sticky_environment_cwds() {
|
||||
|
||||
let session_cwd = {
|
||||
let state = session.state.lock().await;
|
||||
state.session_configuration.cwd.clone()
|
||||
state.session_configuration.cwd().clone()
|
||||
};
|
||||
let config = session.get_config().await;
|
||||
let next_turn = session.new_default_turn().await;
|
||||
@@ -4495,55 +4513,65 @@ async fn relative_cwd_update_without_environments_resolves_under_session_cwd() {
|
||||
let (session, _turn_context) = make_session_and_context().await;
|
||||
let original_cwd = {
|
||||
let mut state = session.state.lock().await;
|
||||
state.session_configuration.environments = Vec::new();
|
||||
state.session_configuration.cwd.clone()
|
||||
state.session_configuration.environments.environments = Vec::new();
|
||||
state.session_configuration.cwd().clone()
|
||||
};
|
||||
let updated_cwd = original_cwd.join("project");
|
||||
std::fs::create_dir_all(updated_cwd.as_path()).expect("create project dir");
|
||||
|
||||
session
|
||||
.update_settings(SessionSettingsUpdate {
|
||||
cwd: Some(updated_cwd.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
updated_cwd.clone(),
|
||||
Vec::new(),
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect("cwd update should succeed");
|
||||
|
||||
let state = session.state.lock().await;
|
||||
assert_eq!(state.session_configuration.cwd, updated_cwd);
|
||||
assert!(state.session_configuration.environments.is_empty());
|
||||
assert_eq!(state.session_configuration.cwd(), &updated_cwd);
|
||||
assert!(
|
||||
state
|
||||
.session_configuration
|
||||
.environment_selections()
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn cwd_update_does_not_rewrite_sticky_environment_cwd() {
|
||||
async fn cwd_update_rewrites_sticky_environment_cwd() {
|
||||
let (session, _turn_context) = make_session_and_context().await;
|
||||
let (original_cwd, environment_cwd) = {
|
||||
let (original_cwd, environment_cwd, environments) = {
|
||||
let mut state = session.state.lock().await;
|
||||
let original_cwd = state.session_configuration.cwd.clone();
|
||||
let original_cwd = state.session_configuration.cwd().clone();
|
||||
let environment_cwd = original_cwd.join("environment");
|
||||
state.session_configuration.environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: environment_cwd.clone(),
|
||||
}];
|
||||
(original_cwd, environment_cwd)
|
||||
let environments = vec![local(environment_cwd.clone())];
|
||||
state.session_configuration.environments.environments = environments.clone();
|
||||
(original_cwd, environment_cwd, environments)
|
||||
};
|
||||
let updated_cwd = original_cwd.join("project");
|
||||
std::fs::create_dir_all(updated_cwd.as_path()).expect("create project dir");
|
||||
|
||||
session
|
||||
.update_settings(SessionSettingsUpdate {
|
||||
cwd: Some(updated_cwd.clone()),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
updated_cwd.clone(),
|
||||
environments,
|
||||
)),
|
||||
..Default::default()
|
||||
})
|
||||
.await
|
||||
.expect("cwd update should succeed");
|
||||
|
||||
let state = session.state.lock().await;
|
||||
assert_eq!(state.session_configuration.cwd, updated_cwd);
|
||||
assert_eq!(state.session_configuration.cwd(), &updated_cwd);
|
||||
assert_eq!(
|
||||
state.session_configuration.environments[0].cwd,
|
||||
environment_cwd
|
||||
state.session_configuration.environment_selections()[0].cwd,
|
||||
updated_cwd
|
||||
);
|
||||
assert_ne!(environment_cwd, updated_cwd);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -4551,7 +4579,7 @@ async fn absolute_cwd_update_with_turn_environment_is_allowed() {
|
||||
let (session, _turn_context, _rx) = make_session_and_context_with_rx().await;
|
||||
let absolute_cwd = {
|
||||
let state = session.state.lock().await;
|
||||
state.session_configuration.cwd.join("absolute-turn")
|
||||
state.session_configuration.cwd().join("absolute-turn")
|
||||
};
|
||||
std::fs::create_dir_all(absolute_cwd.as_path()).expect("create absolute turn dir");
|
||||
|
||||
@@ -4559,11 +4587,10 @@ async fn absolute_cwd_update_with_turn_environment_is_allowed() {
|
||||
.new_turn_with_sub_id(
|
||||
"sub-1".to_string(),
|
||||
SessionSettingsUpdate {
|
||||
cwd: Some(absolute_cwd.clone()),
|
||||
environments: Some(vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: absolute_cwd.clone(),
|
||||
}]),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
absolute_cwd.clone(),
|
||||
vec![local(absolute_cwd.clone())],
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -4622,11 +4649,10 @@ async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh() {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), Vec::new()),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: Vec::new(),
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -4712,10 +4738,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
developer_instructions: None,
|
||||
},
|
||||
};
|
||||
let default_environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: config.cwd.clone(),
|
||||
}];
|
||||
let default_environments = vec![local(config.cwd.clone())];
|
||||
let session_configuration = SessionConfiguration {
|
||||
provider: config.model_provider.clone(),
|
||||
collaboration_mode,
|
||||
@@ -4733,11 +4756,10 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), default_environments),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -4751,7 +4773,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
user_shell_override: None,
|
||||
};
|
||||
let per_turn_config =
|
||||
Session::build_per_turn_config(&session_configuration, session_configuration.cwd.clone());
|
||||
Session::build_per_turn_config(&session_configuration, session_configuration.cwd().clone());
|
||||
let model_info = construct_model_info_offline_for_tests(
|
||||
session_configuration.collaboration_mode.model(),
|
||||
&per_turn_config.to_models_manager_config(),
|
||||
@@ -4863,7 +4885,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
.skills_for_config(&skills_input, Some(Arc::clone(&skill_fs)))
|
||||
.await,
|
||||
);
|
||||
let turn_environments = turn_environments_for_tests(&environment, &session_configuration.cwd);
|
||||
let turn_environments = turn_environments_for_tests(&environment, session_configuration.cwd());
|
||||
let turn_context = Session::make_turn_context(
|
||||
thread_id,
|
||||
SessionId::from(thread_id),
|
||||
@@ -4880,7 +4902,7 @@ pub(crate) async fn make_session_and_context() -> (Session, TurnContext) {
|
||||
&models_manager,
|
||||
/*network*/ None,
|
||||
turn_environments,
|
||||
session_configuration.cwd.clone(),
|
||||
session_configuration.cwd().clone(),
|
||||
"turn_id".to_string(),
|
||||
skills_outcome,
|
||||
);
|
||||
@@ -4948,10 +4970,7 @@ async fn make_session_with_config_and_rx(
|
||||
developer_instructions: None,
|
||||
},
|
||||
};
|
||||
let default_environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: config.cwd.clone(),
|
||||
}];
|
||||
let default_environments = vec![local(config.cwd.clone())];
|
||||
let session_configuration = SessionConfiguration {
|
||||
provider: config.model_provider.clone(),
|
||||
collaboration_mode,
|
||||
@@ -4969,11 +4988,10 @@ async fn make_session_with_config_and_rx(
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), default_environments),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -5053,10 +5071,7 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
developer_instructions: None,
|
||||
},
|
||||
};
|
||||
let default_environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: config.cwd.clone(),
|
||||
}];
|
||||
let default_environments = vec![local(config.cwd.clone())];
|
||||
let session_configuration = SessionConfiguration {
|
||||
provider: config.model_provider.clone(),
|
||||
collaboration_mode,
|
||||
@@ -5074,11 +5089,10 @@ async fn make_session_with_history_source_and_agent_control_and_rx(
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), default_environments),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -5937,7 +5951,6 @@ fn submission_dispatch_span_uses_debug_for_realtime_audio() {
|
||||
fn op_kind_for_input_and_context_ops() {
|
||||
assert_eq!(
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![],
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
@@ -5969,12 +5982,11 @@ async fn user_turn_updates_approvals_reviewer() {
|
||||
text: "hello".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(config.cwd.clone()),
|
||||
environments: Some(local_selections(config.cwd.clone())),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
approvals_reviewer: Some(codex_config::types::ApprovalsReviewer::AutoReview),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
@@ -6013,10 +6025,10 @@ async fn turn_environments_set_primary_environment() {
|
||||
.new_turn_with_sub_id(
|
||||
"sub-1".to_string(),
|
||||
SessionSettingsUpdate {
|
||||
environments: Some(vec![TurnEnvironmentSelection {
|
||||
environment_id: "local".to_string(),
|
||||
cwd: selected_cwd.clone(),
|
||||
}]),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
selected_cwd.clone(),
|
||||
vec![local(selected_cwd.clone())],
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -6041,7 +6053,7 @@ async fn turn_environments_set_primary_environment() {
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn default_turn_overlays_session_cwd_onto_stored_thread_environments() {
|
||||
async fn default_turn_does_not_overlay_legacy_fallback_cwd_onto_stored_thread_environments() {
|
||||
let (session, _turn_context, _rx) = make_session_and_context_with_rx().await;
|
||||
let session_cwd = session.get_config().await.cwd.clone();
|
||||
let selected_cwd =
|
||||
@@ -6049,10 +6061,7 @@ async fn default_turn_overlays_session_cwd_onto_stored_thread_environments() {
|
||||
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.session_configuration.environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: "local".to_string(),
|
||||
cwd: selected_cwd.clone(),
|
||||
}];
|
||||
state.session_configuration.environments.environments = vec![local(selected_cwd.clone())];
|
||||
}
|
||||
|
||||
let turn_context = session.new_default_turn().await;
|
||||
@@ -6069,8 +6078,8 @@ async fn default_turn_overlays_session_cwd_onto_stored_thread_environments() {
|
||||
));
|
||||
#[allow(deprecated)]
|
||||
let turn_cwd = turn_context.cwd.clone();
|
||||
assert_eq!(turn_cwd, session_cwd);
|
||||
assert_eq!(turn_context.config.cwd, session_cwd);
|
||||
assert_eq!(turn_cwd, selected_cwd);
|
||||
assert_eq!(turn_context.config.cwd, selected_cwd);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
@@ -6080,7 +6089,7 @@ async fn default_turn_honors_empty_stored_thread_environments() {
|
||||
|
||||
{
|
||||
let mut state = session.state.lock().await;
|
||||
state.session_configuration.environments = Vec::new();
|
||||
state.session_configuration.environments.environments = Vec::new();
|
||||
}
|
||||
|
||||
let turn_context = session.new_default_turn().await;
|
||||
@@ -6143,7 +6152,10 @@ async fn empty_turn_environments_clear_primary_environment() {
|
||||
.new_turn_with_sub_id(
|
||||
"sub-1".to_string(),
|
||||
SessionSettingsUpdate {
|
||||
environments: Some(vec![]),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
session.get_config().await.cwd.clone(),
|
||||
vec![],
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -6170,10 +6182,13 @@ async fn unknown_turn_environment_returns_error() {
|
||||
.new_turn_with_sub_id(
|
||||
"sub-1".to_string(),
|
||||
SessionSettingsUpdate {
|
||||
environments: Some(vec![TurnEnvironmentSelection {
|
||||
environment_id: "missing".to_string(),
|
||||
cwd: original_configuration.cwd.clone(),
|
||||
}]),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
original_configuration.cwd().clone(),
|
||||
vec![TurnEnvironmentSelection {
|
||||
environment_id: "missing".to_string(),
|
||||
cwd: original_configuration.cwd().clone(),
|
||||
}],
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -6186,10 +6201,10 @@ async fn unknown_turn_environment_returns_error() {
|
||||
};
|
||||
assert!(matches!(err, CodexErr::InvalidRequest(_)));
|
||||
assert!(err.to_string().contains("missing"));
|
||||
assert_eq!(current_configuration.cwd, original_configuration.cwd);
|
||||
assert_eq!(current_configuration.cwd(), original_configuration.cwd());
|
||||
assert_eq!(
|
||||
current_configuration.environments,
|
||||
original_configuration.environments
|
||||
current_configuration.environment_selections(),
|
||||
original_configuration.environment_selections()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6205,16 +6220,13 @@ async fn duplicate_turn_environment_returns_error_without_mutating_session() {
|
||||
.new_turn_with_sub_id(
|
||||
"sub-1".to_string(),
|
||||
SessionSettingsUpdate {
|
||||
environments: Some(vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: "local".to_string(),
|
||||
cwd: original_configuration.cwd.clone(),
|
||||
},
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: "local".to_string(),
|
||||
cwd: original_configuration.cwd.join("second"),
|
||||
},
|
||||
]),
|
||||
environments: Some(TurnEnvironmentSelections::new(
|
||||
original_configuration.cwd().clone(),
|
||||
vec![
|
||||
local(original_configuration.cwd().clone()),
|
||||
local(original_configuration.cwd().join("second")),
|
||||
],
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -6227,10 +6239,10 @@ async fn duplicate_turn_environment_returns_error_without_mutating_session() {
|
||||
};
|
||||
assert!(matches!(err, CodexErr::InvalidRequest(_)));
|
||||
assert!(err.to_string().contains("duplicate"));
|
||||
assert_eq!(current_configuration.cwd, original_configuration.cwd);
|
||||
assert_eq!(current_configuration.cwd(), original_configuration.cwd());
|
||||
assert_eq!(
|
||||
current_configuration.environments,
|
||||
original_configuration.environments
|
||||
current_configuration.environment_selections(),
|
||||
original_configuration.environment_selections()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6789,10 +6801,7 @@ where
|
||||
developer_instructions: None,
|
||||
},
|
||||
};
|
||||
let default_environments = vec![TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: config.cwd.clone(),
|
||||
}];
|
||||
let default_environments = vec![local(config.cwd.clone())];
|
||||
let session_configuration = SessionConfiguration {
|
||||
provider: config.model_provider.clone(),
|
||||
collaboration_mode,
|
||||
@@ -6810,11 +6819,10 @@ where
|
||||
approvals_reviewer: config.approvals_reviewer,
|
||||
permission_profile_state: config.permissions.permission_profile_state().clone(),
|
||||
windows_sandbox_level: WindowsSandboxLevel::from_config(&config),
|
||||
cwd: config.cwd.clone(),
|
||||
environments: TurnEnvironmentSelections::new(config.cwd.clone(), default_environments),
|
||||
workspace_roots: config.workspace_roots.clone(),
|
||||
codex_home: config.codex_home.clone(),
|
||||
thread_name: None,
|
||||
environments: default_environments,
|
||||
original_config_do_not_use: Arc::clone(&config),
|
||||
metrics_service_name: None,
|
||||
app_server_client_name: None,
|
||||
@@ -6828,7 +6836,7 @@ where
|
||||
user_shell_override: None,
|
||||
};
|
||||
let per_turn_config =
|
||||
Session::build_per_turn_config(&session_configuration, session_configuration.cwd.clone());
|
||||
Session::build_per_turn_config(&session_configuration, session_configuration.cwd().clone());
|
||||
let model_info = construct_model_info_offline_for_tests(
|
||||
session_configuration.collaboration_mode.model(),
|
||||
&per_turn_config.to_models_manager_config(),
|
||||
@@ -6940,7 +6948,7 @@ where
|
||||
.skills_for_config(&skills_input, Some(Arc::clone(&skill_fs)))
|
||||
.await,
|
||||
);
|
||||
let turn_environments = turn_environments_for_tests(&environment, &session_configuration.cwd);
|
||||
let turn_environments = turn_environments_for_tests(&environment, session_configuration.cwd());
|
||||
let turn_context = Arc::new(Session::make_turn_context(
|
||||
thread_id,
|
||||
SessionId::from(thread_id),
|
||||
@@ -6957,7 +6965,7 @@ where
|
||||
&models_manager,
|
||||
/*network*/ None,
|
||||
turn_environments,
|
||||
session_configuration.cwd.clone(),
|
||||
session_configuration.cwd().clone(),
|
||||
"turn_id".to_string(),
|
||||
skills_outcome,
|
||||
));
|
||||
|
||||
@@ -441,7 +441,7 @@ impl Session {
|
||||
session_configuration: &SessionConfiguration,
|
||||
) -> Config {
|
||||
let mut config =
|
||||
Self::build_per_turn_config(session_configuration, session_configuration.cwd.clone());
|
||||
Self::build_per_turn_config(session_configuration, session_configuration.cwd().clone());
|
||||
config.model = Some(session_configuration.collaboration_mode.model().to_string());
|
||||
config.permissions.approval_policy = session_configuration.approval_policy.clone();
|
||||
config.workspace_roots = session_configuration.workspace_roots.clone();
|
||||
@@ -587,19 +587,9 @@ impl Session {
|
||||
let mut state = self.state.lock().await;
|
||||
match state.session_configuration.clone().apply(&updates) {
|
||||
Ok(next) => {
|
||||
let mut effective_environments = updates
|
||||
.environments
|
||||
.clone()
|
||||
.unwrap_or_else(|| next.environments.clone());
|
||||
if updates.environments.is_none() {
|
||||
Self::overlay_runtime_cwd_on_primary_environment(
|
||||
&mut effective_environments,
|
||||
&next.cwd,
|
||||
);
|
||||
}
|
||||
let turn_environments =
|
||||
self.resolve_turn_environments(&effective_environments)?;
|
||||
let previous_cwd = state.session_configuration.cwd.clone();
|
||||
self.resolve_turn_environments(next.environment_selections())?;
|
||||
let previous_cwd = state.session_configuration.cwd().clone();
|
||||
let previous_permission_profile =
|
||||
state.session_configuration.permission_profile();
|
||||
let next_permission_profile = next.permission_profile();
|
||||
@@ -656,7 +646,7 @@ impl Session {
|
||||
self.emit_config_changed_contributors(previous_config.as_ref(), new_config.as_ref());
|
||||
self.maybe_refresh_shell_snapshot_for_cwd(
|
||||
&previous_cwd,
|
||||
&session_configuration.cwd,
|
||||
session_configuration.cwd(),
|
||||
&codex_home,
|
||||
&session_source,
|
||||
);
|
||||
@@ -731,7 +721,7 @@ impl Session {
|
||||
let cwd = primary_turn_environment
|
||||
.as_ref()
|
||||
.map(|turn_environment| turn_environment.cwd.clone())
|
||||
.unwrap_or_else(|| session_configuration.cwd.clone());
|
||||
.unwrap_or_else(|| session_configuration.cwd().clone());
|
||||
let per_turn_config = Self::build_per_turn_config(&session_configuration, cwd.clone());
|
||||
{
|
||||
let mcp_connection_manager = self.services.mcp_connection_manager.read().await;
|
||||
@@ -871,29 +861,14 @@ impl Session {
|
||||
let state = self.state.lock().await;
|
||||
state.session_configuration.clone()
|
||||
};
|
||||
let mut effective_environments = session_configuration.environments.clone();
|
||||
Self::overlay_runtime_cwd_on_primary_environment(
|
||||
&mut effective_environments,
|
||||
&session_configuration.cwd,
|
||||
);
|
||||
let turn_environments = match self.resolve_turn_environments(&effective_environments) {
|
||||
Ok(turn_environments) => turn_environments,
|
||||
Err(err) => {
|
||||
warn!("failed to resolve stored session environments: {err}");
|
||||
ResolvedTurnEnvironments::default()
|
||||
}
|
||||
};
|
||||
let turn_environments =
|
||||
match self.resolve_turn_environments(session_configuration.environment_selections()) {
|
||||
Ok(turn_environments) => turn_environments,
|
||||
Err(err) => {
|
||||
warn!("failed to resolve stored session environments: {err}");
|
||||
ResolvedTurnEnvironments::default()
|
||||
}
|
||||
};
|
||||
(session_configuration, turn_environments)
|
||||
}
|
||||
|
||||
fn overlay_runtime_cwd_on_primary_environment(
|
||||
environments: &mut [TurnEnvironmentSelection],
|
||||
runtime_cwd: &AbsolutePathBuf,
|
||||
) {
|
||||
if let Some(turn_environment) = environments.first_mut()
|
||||
&& turn_environment.cwd != *runtime_cwd
|
||||
{
|
||||
turn_environment.cwd = runtime_cwd.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::ThreadSource;
|
||||
use codex_protocol::protocol::TurnStartedEvent;
|
||||
use codex_protocol::protocol::UserMessageEvent;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::PathBufExt;
|
||||
use core_test_support::PathExt;
|
||||
use core_test_support::responses::mount_models_once;
|
||||
@@ -343,99 +342,6 @@ async fn start_thread_rejects_explicit_local_environment_when_default_provider_i
|
||||
assert!(manager.list_thread_ids().await.is_empty());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn start_thread_uses_all_default_environments_from_codex_home() {
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
let mut config = test_config().await;
|
||||
config.codex_home = temp_dir.path().join("codex-home").abs();
|
||||
config.cwd = config.codex_home.abs();
|
||||
std::fs::create_dir_all(&config.codex_home).expect("create codex home");
|
||||
std::fs::write(
|
||||
config.codex_home.join("environments.toml"),
|
||||
r#"
|
||||
default = "dev"
|
||||
|
||||
[[environments]]
|
||||
id = "dev"
|
||||
program = "ssh"
|
||||
args = ["dev", "cd /tmp && true"]
|
||||
"#,
|
||||
)
|
||||
.expect("write environments.toml");
|
||||
|
||||
let runtime_paths = codex_exec_server::ExecServerRuntimePaths::new(
|
||||
std::env::current_exe().expect("current exe path"),
|
||||
/*codex_linux_sandbox_exe*/ None,
|
||||
)
|
||||
.expect("runtime paths");
|
||||
let environment_manager = Arc::new(
|
||||
codex_exec_server::EnvironmentManager::from_codex_home(
|
||||
config.codex_home.clone(),
|
||||
Some(runtime_paths),
|
||||
)
|
||||
.await
|
||||
.expect("environment manager"),
|
||||
);
|
||||
assert_eq!(
|
||||
environment_manager.default_environment_ids(),
|
||||
vec!["dev".to_string(), "local".to_string()]
|
||||
);
|
||||
|
||||
let manager = ThreadManager::with_models_provider_and_home_for_tests(
|
||||
CodexAuth::from_api_key("dummy"),
|
||||
config.model_provider.clone(),
|
||||
config.codex_home.to_path_buf(),
|
||||
environment_manager,
|
||||
);
|
||||
|
||||
let thread = manager
|
||||
.start_thread(config)
|
||||
.await
|
||||
.expect("thread should start");
|
||||
|
||||
let prompt_items = crate::prompt_debug::build_prompt_input_from_session(
|
||||
thread.thread.codex.session.as_ref(),
|
||||
Vec::<UserInput>::new(),
|
||||
)
|
||||
.await
|
||||
.expect("prompt input");
|
||||
let environment_context = prompt_items
|
||||
.iter()
|
||||
.filter_map(|item| match item {
|
||||
ResponseItem::Message { content, .. } => Some(content),
|
||||
_ => None,
|
||||
})
|
||||
.flatten()
|
||||
.find_map(|content| match content {
|
||||
ContentItem::InputText { text } if text.contains("<environment_context>") => {
|
||||
Some(text.as_str())
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.expect("environment context prompt item");
|
||||
assert!(environment_context.contains("<environments>"));
|
||||
let cwd = thread.session_configured.cwd.display().to_string();
|
||||
let dev_entry = format!(
|
||||
r#"<environment id="dev">
|
||||
<cwd>{cwd}</cwd>
|
||||
<shell>"#
|
||||
);
|
||||
let local_entry = format!(
|
||||
r#"<environment id="local">
|
||||
<cwd>{cwd}</cwd>
|
||||
<shell>"#
|
||||
);
|
||||
let dev_position = environment_context
|
||||
.find(&dev_entry)
|
||||
.expect("dev environment entry");
|
||||
let local_position = environment_context
|
||||
.find(&local_entry)
|
||||
.expect("local environment entry");
|
||||
assert!(dev_position < local_position);
|
||||
assert!(!environment_context.contains("\n <cwd>"));
|
||||
assert!(!environment_context.contains("\n <shell>"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn start_thread_keeps_internal_threads_hidden_from_normal_lookups() {
|
||||
let temp_dir = tempdir().expect("tempdir");
|
||||
|
||||
@@ -2676,7 +2676,6 @@ async fn send_input_accepts_structured_items() {
|
||||
.expect("send_input should succeed");
|
||||
|
||||
let expected = Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![
|
||||
UserInput::Mention {
|
||||
name: "drive".to_string(),
|
||||
|
||||
@@ -40,6 +40,7 @@ use codex_protocol::protocol::SandboxPolicy;
|
||||
use codex_protocol::protocol::SessionConfiguredEvent;
|
||||
use codex_protocol::protocol::SessionSource;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelections;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use futures::future::BoxFuture;
|
||||
@@ -70,6 +71,17 @@ const REMOTE_EXEC_SERVER_URL_ENV_VAR: &str = "CODEX_TEST_REMOTE_EXEC_SERVER_URL"
|
||||
static REMOTE_TEST_INSTANCE_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
const SUBMIT_TURN_COMPLETE_TIMEOUT: Duration = Duration::from_secs(30);
|
||||
|
||||
pub fn local(cwd: AbsolutePathBuf) -> TurnEnvironmentSelection {
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: codex_exec_server::LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn local_selections(cwd: AbsolutePathBuf) -> TurnEnvironmentSelections {
|
||||
TurnEnvironmentSelections::new(cwd.clone(), vec![local(cwd)])
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TestEnv {
|
||||
environment: codex_exec_server::Environment,
|
||||
@@ -789,18 +801,20 @@ impl TestCodex {
|
||||
let (sandbox_policy, permission_profile) =
|
||||
turn_permission_fields(permission_profile, self.config.cwd.as_path());
|
||||
let session_model = self.session_configured.model.clone();
|
||||
let turn_environment_selections = environments.map(|environments| {
|
||||
TurnEnvironmentSelections::new(self.config.cwd.clone(), environments)
|
||||
});
|
||||
self.codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(self.config.cwd.clone()),
|
||||
environments: turn_environment_selections,
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -46,7 +46,6 @@ async fn interrupt_long_running_tool_emits_turn_aborted() {
|
||||
// Kick off a turn that triggers the function call.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start sleep".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -104,7 +103,6 @@ async fn interrupt_tool_records_history_entries() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start history recording".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -126,7 +124,6 @@ async fn interrupt_tool_records_history_entries() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -210,7 +207,6 @@ async fn interrupt_persists_turn_aborted_marker_in_next_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start interrupt marker".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -232,7 +228,6 @@ async fn interrupt_persists_turn_aborted_marker_in_next_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -37,7 +37,6 @@ async fn additional_context_is_model_visible_but_not_a_user_message_item() -> Re
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "inspect the active tab".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -136,7 +135,6 @@ async fn external_context_like_user_text_remains_a_user_message_item() -> Result
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![user_input.clone()],
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
@@ -182,7 +180,6 @@ async fn additional_context_trust_controls_message_role() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "inspect context".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -263,7 +260,6 @@ async fn additional_context_is_deduplicated_between_turns_while_retained() -> Re
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -281,7 +277,6 @@ async fn additional_context_is_deduplicated_between_turns_while_retained() -> Re
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "second turn".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -343,7 +338,6 @@ async fn additional_context_removes_one_value_while_adding_another() -> Result<(
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -376,7 +370,6 @@ async fn additional_context_removes_one_value_while_adding_another() -> Result<(
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "second turn".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -409,7 +402,6 @@ async fn additional_context_removes_one_value_while_adding_another() -> Result<(
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "third turn".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -506,7 +498,6 @@ async fn additional_context_values_are_truncated_before_model_input() -> Result<
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "summarize context".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -7,6 +7,7 @@ use core_test_support::responses::ev_apply_patch_custom_tool_call;
|
||||
use core_test_support::responses::ev_apply_patch_shell_command_call_via_heredoc;
|
||||
use core_test_support::responses::ev_shell_command_call;
|
||||
use core_test_support::test_codex::ApplyPatchModelOutput;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::fs;
|
||||
use std::path::PathBuf;
|
||||
@@ -52,6 +53,7 @@ use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_remote;
|
||||
use core_test_support::test_codex::TestCodexBuilder;
|
||||
use core_test_support::test_codex::TestCodexHarness;
|
||||
use core_test_support::test_codex::local;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -100,12 +102,11 @@ async fn submit_without_wait_with_turn_permissions(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(harness.cwd_abs()),
|
||||
environments: Some(local_selections(harness.cwd_abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -1631,27 +1632,27 @@ async fn apply_patch_turn_diff_tracks_local_and_remote_environment_paths() -> Re
|
||||
|
||||
let (sandbox_policy, permission_profile) =
|
||||
turn_permission_fields(PermissionProfile::Disabled, test.config.cwd.as_path());
|
||||
let environments = vec![
|
||||
local(shared_cwd.clone()),
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: shared_cwd.clone(),
|
||||
},
|
||||
];
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: "apply matching patches to local and remote environments".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: Some(vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: shared_cwd.clone(),
|
||||
},
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: shared_cwd.clone(),
|
||||
},
|
||||
]),
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(codex_protocol::protocol::TurnEnvironmentSelections::new(
|
||||
test.config.cwd.clone(),
|
||||
environments,
|
||||
)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -39,6 +39,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -658,12 +659,11 @@ async fn submit_turn(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
@@ -2619,12 +2619,11 @@ async fn env_zsh_script_spawned_by_python_can_request_escalation_under_zsh_fork(
|
||||
text: "run nested env zsh script through python".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
@@ -2764,12 +2763,11 @@ async fn matched_prefix_rule_runs_unsandboxed_under_zsh_fork() -> Result<()> {
|
||||
text: "run allowed touch under zsh fork".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
@@ -3356,12 +3354,11 @@ allow_local_binding = true
|
||||
text: "deny-read network retry".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(turn_sandbox_policy),
|
||||
|
||||
@@ -34,6 +34,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -160,12 +161,11 @@ async fn remote_model_override_uses_catalog_model_for_strict_auto_review() -> Re
|
||||
text: "run the Guardian model override check".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -66,6 +66,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::sse_failed;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use dunce::canonicalize as normalize_path;
|
||||
@@ -386,7 +387,6 @@ async fn resume_includes_initial_messages_and_sends_prior_items() {
|
||||
// 2) Submit new input; the request body must include the prior items, then initial context, then new user input.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -755,7 +755,6 @@ async fn includes_session_id_thread_id_and_model_headers_in_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -968,7 +967,6 @@ async fn includes_base_instructions_override_in_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1026,7 +1024,6 @@ async fn chatgpt_auth_sends_correct_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1151,7 +1148,6 @@ async fn prefers_apikey_when_config_prefers_apikey_even_with_chatgpt_tokens() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1191,7 +1187,6 @@ async fn includes_user_instructions_message_in_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1280,7 +1275,6 @@ async fn includes_apps_guidance_as_developer_message_for_chatgpt_auth() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1344,7 +1338,6 @@ async fn omits_apps_guidance_for_api_key_auth_even_when_feature_enabled() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1404,7 +1397,6 @@ async fn omits_apps_guidance_when_configured_off() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1447,7 +1439,6 @@ async fn omits_environment_context_when_configured_off() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1505,7 +1496,6 @@ async fn skills_append_to_developer_message() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1589,7 +1579,6 @@ async fn skills_use_aliases_in_developer_message_under_budget_pressure() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1651,7 +1640,6 @@ async fn includes_configured_effort_in_request() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1694,7 +1682,6 @@ async fn includes_no_effort_in_request() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1738,7 +1725,6 @@ async fn includes_default_reasoning_effort_in_request_when_defined_by_model_info
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1794,12 +1780,11 @@ async fn user_turn_collaboration_mode_overrides_model_and_effort() -> anyhow::Re
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(config.cwd.clone()),
|
||||
environments: Some(local_selections(config.cwd.clone())),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
summary: Some(
|
||||
@@ -1847,7 +1832,6 @@ async fn configured_reasoning_summary_is_sent() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1904,7 +1888,6 @@ async fn responses_lite_sets_all_turns_context_and_disables_parallel_tool_calls(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1972,12 +1955,11 @@ async fn user_turn_explicit_reasoning_summary_overrides_model_catalog_default()
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(config.cwd.clone()),
|
||||
environments: Some(local_selections(config.cwd.clone())),
|
||||
approval_policy: Some(config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(config.legacy_sandbox_policy()),
|
||||
summary: Some(ReasoningSummary::Concise),
|
||||
@@ -2029,7 +2011,6 @@ async fn reasoning_summary_is_omitted_when_disabled() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2089,7 +2070,6 @@ async fn reasoning_summary_none_overrides_model_catalog_default() -> anyhow::Res
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2129,7 +2109,6 @@ async fn includes_default_verbosity_in_request() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2178,7 +2157,6 @@ async fn configured_verbosity_not_sent_for_models_without_support() -> anyhow::R
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2226,7 +2204,6 @@ async fn configured_verbosity_is_sent() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2279,7 +2256,6 @@ async fn includes_developer_instructions_message_in_request() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2577,7 +2553,6 @@ async fn token_count_includes_rate_limits_snapshot() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2719,7 +2694,6 @@ async fn usage_limit_error_emits_rate_limit_event() -> anyhow::Result<()> {
|
||||
|
||||
let submission_id = codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2797,7 +2771,6 @@ async fn context_window_error_sets_total_tokens_to_model_window() -> anyhow::Res
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "seed turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2813,7 +2786,6 @@ async fn context_window_error_sets_total_tokens_to_model_window() -> anyhow::Res
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "trigger context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2899,7 +2871,6 @@ async fn incomplete_response_emits_content_filter_error_message() -> anyhow::Res
|
||||
.await?;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "trigger incomplete".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3011,7 +2982,6 @@ async fn azure_overrides_assign_properties_used_for_responses_url() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3101,7 +3071,6 @@ async fn env_var_overrides_loaded_auth() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3159,7 +3128,6 @@ async fn history_dedupes_streamed_and_final_messages_across_turns() {
|
||||
// Turn 1: user sends U1; wait for completion.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "U1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3176,7 +3144,6 @@ async fn history_dedupes_streamed_and_final_messages_across_turns() {
|
||||
// Turn 2: user sends U2; wait for completion.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "U2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3193,7 +3160,6 @@ async fn history_dedupes_streamed_and_final_messages_across_turns() {
|
||||
// Turn 3: user sends U3; wait for completion.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "U3".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -1231,7 +1231,6 @@ async fn responses_websocket_usage_limit_error_emits_rate_limit_event() {
|
||||
let submission_id = test
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1322,7 +1321,6 @@ async fn responses_websocket_invalid_request_error_with_status_is_forwarded() {
|
||||
let submission_id = test
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -3199,12 +3199,14 @@ text(
|
||||
text: "use exec to inspect and call hidden tools".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(codex_protocol::protocol::TurnEnvironmentSelections::new(
|
||||
cwd,
|
||||
Vec::new(),
|
||||
)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -13,6 +13,7 @@ use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -72,7 +73,6 @@ async fn no_collaboration_instructions_by_default() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -127,7 +127,6 @@ async fn user_input_includes_collaboration_instructions_after_override() -> Resu
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -169,12 +168,11 @@ async fn collaboration_instructions_added_on_user_turn() -> Result<()> {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
summary: Some(
|
||||
@@ -220,12 +218,11 @@ async fn collaboration_instructions_omitted_when_disabled() -> Result<()> {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
summary: Some(
|
||||
@@ -276,7 +273,6 @@ async fn override_then_next_turn_uses_updated_collaboration_instructions() -> Re
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -329,12 +325,11 @@ async fn user_turn_overrides_collaboration_instructions_after_override() -> Resu
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(test.config.permissions.approval_policy.value()),
|
||||
sandbox_policy: Some(test.config.legacy_sandbox_policy()),
|
||||
summary: Some(
|
||||
@@ -390,7 +385,6 @@ async fn collaboration_mode_update_emits_new_instruction_message() -> Result<()>
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -414,7 +408,6 @@ async fn collaboration_mode_update_emits_new_instruction_message() -> Result<()>
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -467,7 +460,6 @@ async fn collaboration_mode_update_noop_does_not_append() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -491,7 +483,6 @@ async fn collaboration_mode_update_noop_does_not_append() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -546,7 +537,6 @@ async fn collaboration_mode_update_emits_new_instruction_message_when_mode_chang
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -573,7 +563,6 @@ async fn collaboration_mode_update_emits_new_instruction_message_when_mode_chang
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -629,7 +618,6 @@ async fn collaboration_mode_update_noop_does_not_append_when_mode_is_unchanged()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -656,7 +644,6 @@ async fn collaboration_mode_update_noop_does_not_append_when_mode_is_unchanged()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -715,7 +702,6 @@ async fn resume_replays_collaboration_instructions() -> Result<()> {
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -732,7 +718,6 @@ async fn resume_replays_collaboration_instructions() -> Result<()> {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -785,7 +770,6 @@ async fn empty_collaboration_instructions_are_ignored() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -31,6 +31,7 @@ use core_test_support::hooks::trust_discovered_hooks;
|
||||
use core_test_support::responses::ev_reasoning_item;
|
||||
use core_test_support::responses::mount_models_once;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::test_path_buf;
|
||||
@@ -96,12 +97,11 @@ fn disabled_permission_user_turn(text: impl Into<String>, cwd: PathBuf, model: S
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -404,7 +404,6 @@ async fn summarize_context_three_requests_and_instructions() {
|
||||
// 1) Normal user input – should hit server once.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -430,7 +429,6 @@ async fn summarize_context_three_requests_and_instructions() {
|
||||
// 3) Next user input – third hit; history should include only the summary.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: THIRD_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -606,7 +604,6 @@ async fn manual_pre_compact_block_decision_does_not_block_compaction() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello before blocked compact".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -680,7 +677,6 @@ async fn compact_hooks_respect_matchers_and_post_runs_after_compaction() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello before matched compact".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -751,7 +747,6 @@ async fn manual_compact_uses_custom_prompt() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -899,7 +894,6 @@ async fn manual_compact_emits_context_compaction_items() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "manual compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1066,7 +1060,6 @@ async fn multiple_auto_compact_per_task_runs_after_token_limit_hit() {
|
||||
// Start the conversation with the user message
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1539,7 +1532,6 @@ async fn auto_compact_runs_after_token_limit_hit() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: FIRST_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1556,7 +1548,6 @@ async fn auto_compact_runs_after_token_limit_hit() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: SECOND_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1573,7 +1564,6 @@ async fn auto_compact_runs_after_token_limit_hit() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: POST_AUTO_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1745,7 +1735,6 @@ async fn auto_compact_emits_context_compaction_items() {
|
||||
for user in [FIRST_AUTO_MSG, SECOND_AUTO_MSG, POST_AUTO_USER_MSG] {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1827,7 +1816,6 @@ async fn auto_compact_starts_after_turn_started() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: FIRST_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1843,7 +1831,6 @@ async fn auto_compact_starts_after_turn_started() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: SECOND_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1859,7 +1846,6 @@ async fn auto_compact_starts_after_turn_started() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: POST_AUTO_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2388,7 +2374,6 @@ async fn auto_compact_persists_rollout_entries() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: FIRST_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2404,7 +2389,6 @@ async fn auto_compact_persists_rollout_entries() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: SECOND_AUTO_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2420,7 +2404,6 @@ async fn auto_compact_persists_rollout_entries() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: POST_AUTO_USER_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2510,7 +2493,6 @@ async fn manual_compact_retries_after_context_window_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2615,7 +2597,6 @@ async fn manual_compact_non_context_failure_retries_then_emits_task_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2711,7 +2692,6 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2730,7 +2710,6 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2749,7 +2728,6 @@ async fn manual_compact_twice_preserves_latest_user_messages() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: final_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2961,7 +2939,6 @@ async fn auto_compact_allows_multiple_attempts_when_interleaved_with_other_turn_
|
||||
for user in [MULTI_AUTO_MSG, follow_up_user, final_user] {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3067,7 +3044,6 @@ async fn snapshot_request_shape_mid_turn_continuation_compaction() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: FUNCTION_CALL_LIMIT_MSG.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3499,7 +3475,6 @@ async fn auto_compact_counts_encrypted_reasoning_before_last_user() {
|
||||
{
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3619,7 +3594,6 @@ async fn auto_compact_runs_when_reasoning_header_clears_between_turns() {
|
||||
for user in [first_user, second_user, third_user] {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3682,7 +3656,6 @@ async fn snapshot_request_shape_pre_turn_compaction_including_incoming_user_mess
|
||||
for user in ["USER_ONE", "USER_TWO"] {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3699,7 +3672,9 @@ async fn snapshot_request_shape_pre_turn_compaction_including_incoming_user_mess
|
||||
core_test_support::submit_thread_settings(
|
||||
&codex,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test_path_buf(PRETURN_CONTEXT_DIFF_CWD).abs()),
|
||||
environments: Some(local_selections(
|
||||
test_path_buf(PRETURN_CONTEXT_DIFF_CWD).abs(),
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -3709,7 +3684,6 @@ async fn snapshot_request_shape_pre_turn_compaction_including_incoming_user_mess
|
||||
.to_string();
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![
|
||||
UserInput::Image {
|
||||
image_url: image_url.clone(),
|
||||
@@ -3905,7 +3879,6 @@ async fn snapshot_request_shape_pre_turn_compaction_context_window_exceeded() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3921,7 +3894,6 @@ async fn snapshot_request_shape_pre_turn_compaction_context_window_exceeded() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3995,7 +3967,6 @@ async fn snapshot_request_shape_manual_compact_without_previous_user_messages()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "AFTER_MANUAL_EMPTY_COMPACT".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![allow(clippy::expect_used)]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::fs;
|
||||
|
||||
use anyhow::Result;
|
||||
@@ -324,7 +325,6 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -342,7 +342,6 @@ async fn remote_compact_replaces_history_for_followups() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -585,7 +584,6 @@ async fn assert_remote_manual_compact_request_parity(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "TURN_ONE_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -600,7 +598,6 @@ async fn assert_remote_manual_compact_request_parity(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![
|
||||
UserInput::Text {
|
||||
text: "TURN_TWO_PREFIX".to_string(),
|
||||
@@ -621,7 +618,6 @@ async fn assert_remote_manual_compact_request_parity(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "TURN_THREE_TOOL_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -636,7 +632,6 @@ async fn assert_remote_manual_compact_request_parity(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![
|
||||
UserInput::Image {
|
||||
image_url,
|
||||
@@ -657,7 +652,6 @@ async fn assert_remote_manual_compact_request_parity(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "TURN_FIVE_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -826,7 +820,6 @@ async fn remote_compact_v2_reuses_compaction_trigger_for_followups() -> Result<(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -844,7 +837,6 @@ async fn remote_compact_v2_reuses_compaction_trigger_for_followups() -> Result<(
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -976,7 +968,6 @@ async fn remote_compact_v2_retries_failures_with_stream_retry_budget() -> Result
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -994,7 +985,6 @@ async fn remote_compact_v2_retries_failures_with_stream_retry_budget() -> Result
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1081,7 +1071,6 @@ async fn remote_compact_v2_accepts_additional_output_items_before_compaction() -
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1099,7 +1088,6 @@ async fn remote_compact_v2_accepts_additional_output_items_before_compaction() -
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1187,7 +1175,6 @@ async fn remote_compact_filters_deferred_dynamic_tools() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1260,7 +1247,6 @@ async fn remote_compact_runs_automatically() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1398,7 +1384,6 @@ async fn remote_compact_trims_function_call_history_to_fit_context_window() -> R
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1413,7 +1398,6 @@ async fn remote_compact_trims_function_call_history_to_fit_context_window() -> R
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1528,7 +1512,6 @@ async fn remote_compact_rewrites_multiple_trailing_function_call_outputs() -> Re
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1543,7 +1526,6 @@ async fn remote_compact_rewrites_multiple_trailing_function_call_outputs() -> Re
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1656,7 +1638,6 @@ async fn auto_remote_compact_trims_function_call_history_to_fit_context_window()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1671,7 +1652,6 @@ async fn auto_remote_compact_trims_function_call_history_to_fit_context_window()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1692,7 +1672,6 @@ async fn auto_remote_compact_trims_function_call_history_to_fit_context_window()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "turn that triggers auto compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1816,7 +1795,6 @@ async fn remote_compact_trims_tool_search_output_to_empty_tools_array() -> Resul
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Find the oversized deferred tool".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1897,7 +1875,6 @@ async fn auto_remote_compact_failure_stops_agent_loop() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "turn that exceeds token threshold".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1912,7 +1889,6 @@ async fn auto_remote_compact_failure_stops_agent_loop() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "turn that triggers auto compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2007,7 +1983,6 @@ async fn remote_compact_trim_estimate_uses_session_base_instructions() -> Result
|
||||
|
||||
baseline_codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2025,7 +2000,6 @@ async fn remote_compact_trim_estimate_uses_session_base_instructions() -> Result
|
||||
|
||||
baseline_codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2117,7 +2091,6 @@ async fn remote_compact_trim_estimate_uses_session_base_instructions() -> Result
|
||||
|
||||
override_codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: first_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2135,7 +2108,6 @@ async fn remote_compact_trim_estimate_uses_session_base_instructions() -> Result
|
||||
|
||||
override_codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: second_user_message.into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2212,7 +2184,6 @@ async fn remote_manual_compact_emits_context_compaction_items() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "manual remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2294,7 +2265,6 @@ async fn remote_manual_compact_failure_emits_task_error_event() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "manual remote compact".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2379,7 +2349,6 @@ async fn remote_compact_persists_replacement_history_in_rollout() -> Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "needs compaction".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2523,7 +2492,6 @@ async fn remote_compact_and_resume_refresh_stale_developer_instructions() -> Res
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start remote compact flow".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2542,7 +2510,6 @@ async fn remote_compact_and_resume_refresh_stale_developer_instructions() -> Res
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact in same session".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2568,7 +2535,6 @@ async fn remote_compact_and_resume_refresh_stale_developer_instructions() -> Res
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2665,7 +2631,6 @@ async fn remote_compact_refreshes_stale_developer_instructions_without_resume()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "start remote compact flow".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2683,7 +2648,6 @@ async fn remote_compact_refreshes_stale_developer_instructions_without_resume()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after compact in same session".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2756,7 +2720,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_restates_realtime_sta
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2771,7 +2734,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_restates_realtime_sta
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2839,7 +2801,6 @@ async fn remote_request_uses_custom_experimental_realtime_start_instructions() -
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2901,7 +2862,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_restates_realtime_end
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2918,7 +2878,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_restates_realtime_end
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2994,7 +2953,6 @@ async fn snapshot_request_shape_remote_manual_compact_restates_realtime_start()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3012,7 +2970,6 @@ async fn snapshot_request_shape_remote_manual_compact_restates_realtime_start()
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3096,7 +3053,6 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_does_not_restate_real
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "SETUP_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3113,7 +3069,6 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_does_not_restate_real
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3205,7 +3160,6 @@ async fn snapshot_request_shape_remote_compact_resume_restates_realtime_end() ->
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3236,7 +3190,6 @@ async fn snapshot_request_shape_remote_compact_resume_restates_realtime_end() ->
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3318,7 +3271,9 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_including_incoming_us
|
||||
core_test_support::submit_thread_settings(
|
||||
&codex,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test_path_buf(PRETURN_CONTEXT_DIFF_CWD).abs()),
|
||||
environments: Some(local_selections(
|
||||
test_path_buf(PRETURN_CONTEXT_DIFF_CWD).abs(),
|
||||
)),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
@@ -3326,7 +3281,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_including_incoming_us
|
||||
}
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3414,7 +3368,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_strips_incoming_model
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "BEFORE_SWITCH_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3437,7 +3390,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_strips_incoming_model
|
||||
.await?;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "AFTER_SWITCH_USER".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3557,7 +3509,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_context_window_exceed
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3572,7 +3523,6 @@ async fn snapshot_request_shape_remote_pre_turn_compaction_context_window_exceed
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3658,7 +3608,6 @@ async fn snapshot_request_shape_remote_mid_turn_continuation_compaction() -> Res
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3737,7 +3686,6 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_summary_only_reinject
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3824,7 +3772,6 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_multi_summary_reinjec
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3842,7 +3789,6 @@ async fn snapshot_request_shape_remote_mid_turn_compaction_multi_summary_reinjec
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_TWO".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3925,7 +3871,6 @@ async fn snapshot_request_shape_remote_manual_compact_without_previous_user_mess
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "USER_ONE".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -605,7 +605,6 @@ async fn capture_from_requests(
|
||||
async fn submit_user_input(codex: &codex_core::CodexThread, items: Vec<UserInput>) -> Result<()> {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
|
||||
@@ -34,6 +34,7 @@ use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_once_match;
|
||||
use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -551,7 +552,7 @@ async fn snapshot_rollback_followup_turn_trims_context_updates() -> Result<()> {
|
||||
core_test_support::submit_thread_settings(
|
||||
&conversation,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(override_cwd.clone()),
|
||||
environments: Some(local_selections(override_cwd.clone())),
|
||||
collaboration_mode: Some(CollaborationMode {
|
||||
mode: ModeKind::Default,
|
||||
settings: Settings {
|
||||
@@ -774,7 +775,6 @@ async fn start_test_conversation(
|
||||
async fn user_turn(conversation: &Arc<CodexThread>, text: &str) {
|
||||
conversation
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -17,6 +17,7 @@ use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -51,12 +52,11 @@ async fn submit_user_turn(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -210,12 +210,11 @@ async fn execpolicy_blocks_shell_invocation() -> Result<()> {
|
||||
text: "run shell command".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -50,7 +50,6 @@ async fn fork_thread_twice_drops_to_first_message() {
|
||||
for text in ["first", "second", "third"] {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -173,7 +172,6 @@ async fn fork_thread_from_history_does_not_require_source_rollout_path() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "fork me from stored history".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -19,6 +19,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -111,7 +112,6 @@ printf '%s\n' "${@: -1}" >> "${payload_path}""#,
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "run a command that requires Guardian review".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -120,7 +120,7 @@ printf '%s\n' "${@: -1}" >> "${payload_path}""#,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::AutoReview),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
|
||||
@@ -1843,7 +1843,6 @@ async fn blocked_queued_prompt_does_not_strand_earlier_accepted_prompt() -> Resu
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "initial prompt".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1863,7 +1862,6 @@ async fn blocked_queued_prompt_does_not_strand_earlier_accepted_prompt() -> Resu
|
||||
for text in ["accepted queued prompt", "blocked queued prompt"] {
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -18,6 +18,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -125,12 +126,11 @@ async fn copy_paste_local_image_persists_rollout_request_shape() -> anyhow::Resu
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -224,12 +224,11 @@ async fn drag_drop_image_persists_rollout_request_shape() -> anyhow::Result<()>
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -35,6 +35,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -56,12 +57,11 @@ fn disabled_plan_turn(
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -117,7 +117,6 @@ async fn user_message_item_is_emitted() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![expected_input.clone()],
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
@@ -174,7 +173,6 @@ async fn assistant_message_item_is_emitted() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please summarize results".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -236,7 +234,6 @@ async fn reasoning_item_is_emitted() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "explain your reasoning".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -299,7 +296,6 @@ async fn web_search_item_is_emitted() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "find the weather".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -380,7 +376,6 @@ async fn image_generation_call_event_is_emitted() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "generate a tiny blue square".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -468,7 +463,6 @@ async fn image_generation_call_event_is_emitted_when_image_save_fails() -> anyho
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "generate an image".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -525,7 +519,6 @@ async fn agent_message_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "please stream text".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1110,7 +1103,6 @@ async fn reasoning_content_delta_has_item_metadata() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "reason through it".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1166,7 +1158,6 @@ async fn reasoning_raw_content_delta_respects_flag() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "show raw reasoning".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -8,6 +8,7 @@ use codex_protocol::user_input::UserInput;
|
||||
use core_test_support::responses;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -81,12 +82,11 @@ async fn codex_returns_json_result(model: String) -> anyhow::Result<()> {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: Some(serde_json::from_str(SCHEMA)?),
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -32,6 +32,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_event_match;
|
||||
@@ -73,12 +74,11 @@ async fn submit_user_turn(
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -127,7 +127,6 @@ async fn response_body_for_remote_model(
|
||||
text: "list tools".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -277,7 +276,6 @@ async fn remote_multi_agent_selector_uses_model_selected_before_first_turn() ->
|
||||
text: ROOT_PROMPT.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
|
||||
@@ -32,6 +32,7 @@ use core_test_support::responses::sse_completed;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -45,12 +46,11 @@ fn read_only_user_turn(test: &TestCodex, items: Vec<UserInput>, model: String) -
|
||||
turn_permission_fields(PermissionProfile::read_only(), test.cwd_path());
|
||||
Op::UserInput {
|
||||
items,
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![allow(clippy::expect_used)]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::fs;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -124,12 +125,11 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
|
||||
text: "first turn".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(first_turn_cwd),
|
||||
environments: Some(local_selections(first_turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(first_sandbox_policy),
|
||||
permission_profile: first_permission_profile,
|
||||
@@ -160,12 +160,11 @@ async fn snapshot_model_visible_layout_turn_overrides() -> Result<()> {
|
||||
text: "second turn with context updates".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(preturn_context_diff_cwd),
|
||||
environments: Some(local_selections(preturn_context_diff_cwd)),
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
sandbox_policy: Some(second_sandbox_policy),
|
||||
permission_profile: second_permission_profile,
|
||||
@@ -252,12 +251,11 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R
|
||||
text: "first turn in agents_one".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_one.clone()),
|
||||
environments: Some(local_selections(cwd_one.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(first_sandbox_policy),
|
||||
permission_profile: first_permission_profile,
|
||||
@@ -286,12 +284,11 @@ async fn snapshot_model_visible_layout_cwd_change_does_not_refresh_agents() -> R
|
||||
text: "second turn in agents_two".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_two),
|
||||
environments: Some(local_selections(cwd_two)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(second_sandbox_policy),
|
||||
permission_profile: second_permission_profile,
|
||||
@@ -366,7 +363,6 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul
|
||||
.await;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "seed resume history".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -413,12 +409,11 @@ async fn snapshot_model_visible_layout_resume_with_personality_change() -> Resul
|
||||
text: "resume and change personality".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(resume_override_cwd),
|
||||
environments: Some(local_selections(resume_override_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -483,7 +478,6 @@ async fn snapshot_model_visible_layout_resume_override_matches_rollout_model() -
|
||||
.await;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "seed resume history".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -517,7 +511,7 @@ async fn snapshot_model_visible_layout_resume_override_matches_rollout_model() -
|
||||
core_test_support::submit_thread_settings(
|
||||
&resumed.codex,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(resume_override_cwd),
|
||||
environments: Some(local_selections(resume_override_cwd)),
|
||||
model: Some("gpt-5.2".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -526,7 +520,6 @@ async fn snapshot_model_visible_layout_resume_override_matches_rollout_model() -
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first resumed turn after model override".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
@@ -97,12 +98,11 @@ async fn renews_cache_ttl_on_matching_models_etag() -> Result<()> {
|
||||
text: "hi".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(codex_protocol::protocol::AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![cfg(not(target_os = "windows"))]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
@@ -110,12 +111,11 @@ async fn refresh_models_on_models_etag_mismatch_and_avoid_duplicate_models_fetch
|
||||
text: "please run a tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -120,7 +120,6 @@ async fn responses_api_emits_api_request_event() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -167,7 +166,6 @@ async fn process_sse_emits_tracing_for_output_item() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -214,7 +212,6 @@ async fn process_sse_emits_failed_event_on_parse_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -262,7 +259,6 @@ async fn process_sse_records_failed_event_when_stream_closes_without_completed()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -330,7 +326,6 @@ async fn process_sse_failed_event_records_response_error_message() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -396,7 +391,6 @@ async fn process_sse_failed_event_logs_parse_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -449,7 +443,6 @@ async fn process_sse_failed_event_logs_missing_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -511,7 +504,6 @@ async fn process_sse_failed_event_logs_response_completed_parse_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -567,7 +559,6 @@ async fn process_sse_emits_completed_telemetry() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -647,7 +638,6 @@ async fn turn_and_completed_response_spans_record_token_usage() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -736,7 +726,6 @@ async fn handle_responses_span_records_response_kind_and_tool_name() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -831,7 +820,6 @@ async fn record_responses_sets_span_fields_for_response_events() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -921,7 +909,6 @@ async fn handle_response_item_records_tool_result_for_custom_tool_call() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -998,7 +985,6 @@ async fn handle_response_item_records_tool_result_for_function_call() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1076,7 +1062,6 @@ async fn handle_response_item_records_tool_result_for_shell_command_call() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1250,7 +1235,6 @@ async fn handle_shell_command_autoapprove_from_config_records_tool_decision() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1306,7 +1290,6 @@ async fn handle_shell_command_user_approved_records_tool_decision() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "approved".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1377,7 +1360,6 @@ async fn handle_shell_command_user_approved_for_session_records_tool_decision()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "persist".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1448,7 +1430,6 @@ async fn handle_sandbox_error_user_approves_retry_records_tool_decision() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "retry".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1519,7 +1500,6 @@ async fn handle_shell_command_user_denies_records_tool_decision() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "deny".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1590,7 +1570,6 @@ async fn handle_sandbox_error_user_approves_for_session_records_tool_decision()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "persist".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1662,7 +1641,6 @@ async fn handle_sandbox_error_user_denies_records_tool_decision() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "deny".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -9,6 +9,7 @@ use codex_protocol::protocol::Op;
|
||||
use core_test_support::TempDirExt;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use tempfile::TempDir;
|
||||
@@ -68,7 +69,7 @@ async fn thread_settings_update_without_user_turn_does_not_record_environment_up
|
||||
core_test_support::submit_thread_settings(
|
||||
&test.codex,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(new_cwd.abs()),
|
||||
environments: Some(local_selections(new_cwd.abs())),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::sync::Arc;
|
||||
|
||||
use codex_core::CodexThread;
|
||||
@@ -96,7 +97,6 @@ async fn build_codex(server: &StreamingSseServer) -> Arc<CodexThread> {
|
||||
async fn submit_user_input(codex: &CodexThread, text: &str) {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -119,12 +119,11 @@ async fn submit_danger_full_access_user_turn(test: &TestCodex, text: &str) {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -288,7 +287,6 @@ async fn injected_user_input_triggers_follow_up_request_with_deltas() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first prompt".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -308,7 +306,6 @@ async fn injected_user_input_triggers_follow_up_request_with_deltas() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "second prompt".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -51,7 +51,6 @@ async fn permissions_message_sent_once_on_start() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -92,7 +91,6 @@ async fn permissions_message_added_on_override_change() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -116,7 +114,6 @@ async fn permissions_message_added_on_override_change() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -163,7 +160,6 @@ async fn permissions_message_not_added_when_no_change() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -178,7 +174,6 @@ async fn permissions_message_not_added_when_no_change() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -225,7 +220,6 @@ async fn permissions_message_omitted_when_disabled() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -249,7 +243,6 @@ async fn permissions_message_omitted_when_disabled() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -309,7 +302,6 @@ async fn resume_replays_permissions_messages() -> Result<()> {
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -334,7 +326,6 @@ async fn resume_replays_permissions_messages() -> Result<()> {
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -351,7 +342,6 @@ async fn resume_replays_permissions_messages() -> Result<()> {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -412,7 +402,6 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -437,7 +426,6 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
initial
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -460,7 +448,6 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -496,7 +483,6 @@ async fn resume_and_fork_append_permissions_messages() -> Result<()> {
|
||||
forked
|
||||
.thread
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "after fork".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -558,7 +544,6 @@ async fn permissions_message_includes_writable_roots() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -26,6 +26,7 @@ use core_test_support::responses::sse_completed;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -65,12 +66,11 @@ fn read_only_text_turn_with_personality(
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -180,7 +180,6 @@ async fn capability_sections_render_in_developer_message_in_order() -> Result<()
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![codex_protocol::user_input::UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -261,7 +260,6 @@ async fn explicit_plugin_mentions_inject_plugin_guidance() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![codex_protocol::user_input::UserInput::Mention {
|
||||
name: "sample".into(),
|
||||
path: format!("plugin://{SAMPLE_PLUGIN_CONFIG_NAME}"),
|
||||
@@ -345,7 +343,6 @@ async fn explicit_plugin_mentions_track_plugin_used_analytics() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![codex_protocol::user_input::UserInput::Mention {
|
||||
name: "sample".into(),
|
||||
path: format!("plugin://{SAMPLE_PLUGIN_CONFIG_NAME}"),
|
||||
|
||||
@@ -25,6 +25,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -153,7 +154,6 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -168,7 +168,6 @@ async fn prompt_tools_are_consistent_across_requests() -> anyhow::Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -251,7 +250,6 @@ async fn gpt_5_tools_without_apply_patch_append_apply_patch_instructions() -> an
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -266,7 +264,6 @@ async fn gpt_5_tools_without_apply_patch_append_apply_patch_instructions() -> an
|
||||
wait_for_event(&codex, |ev| matches!(ev, EventMsg::TurnComplete(_))).await;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -334,7 +331,6 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -349,7 +345,6 @@ async fn prefixes_context_and_instructions_once_and_consistently_across_requests
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -435,7 +430,6 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an
|
||||
// First turn
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -474,7 +468,6 @@ async fn overrides_turn_context_but_keeps_cached_prefix_and_key_constant() -> an
|
||||
// Second turn after overrides
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -572,7 +565,6 @@ async fn override_before_first_turn_emits_environment_context() -> anyhow::Resul
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first message".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -729,7 +721,6 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
|
||||
// First turn
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -759,12 +750,11 @@ async fn per_turn_overrides_keep_cached_prefix_and_key_constant() -> anyhow::Res
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(new_cwd.abs()),
|
||||
environments: Some(local_selections(new_cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -876,12 +866,11 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(default_cwd.clone()),
|
||||
environments: Some(local_selections(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
@@ -905,12 +894,11 @@ async fn send_user_turn_with_no_changes_does_not_send_environment_context() -> a
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(default_cwd.clone()),
|
||||
environments: Some(local_selections(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
@@ -1019,12 +1007,11 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
text: "hello 1".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(default_cwd.clone()),
|
||||
environments: Some(local_selections(default_cwd.clone())),
|
||||
approval_policy: Some(default_approval_policy),
|
||||
sandbox_policy: Some(default_sandbox_policy.clone()),
|
||||
summary: Some(default_summary.unwrap_or(ReasoningSummary::Auto)),
|
||||
@@ -1050,12 +1037,11 @@ async fn send_user_turn_with_changes_sends_environment_context() -> anyhow::Resu
|
||||
text: "hello 2".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(default_cwd.clone()),
|
||||
environments: Some(local_selections(default_cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -41,7 +41,6 @@ async fn quota_exceeded_emits_single_error_event() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "quota?".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -2158,7 +2158,6 @@ async fn conversation_user_text_turn_is_sent_to_realtime_when_active() -> Result
|
||||
let prefixed_user_text = format!("[USER] {user_text}");
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user_text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -2294,7 +2293,6 @@ async fn conversation_user_text_turn_is_capped_when_mirrored_to_realtime() -> Re
|
||||
);
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: user_text.clone(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -3491,7 +3489,6 @@ async fn inbound_handoff_request_steers_active_turn() -> Result<()> {
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first prompt".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -41,6 +41,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::test_env;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -70,18 +71,21 @@ async fn submit_turn_with_approval_and_environments(
|
||||
prompt: &str,
|
||||
environments: Vec<TurnEnvironmentSelection>,
|
||||
) -> Result<()> {
|
||||
let turn_environment_selections = codex_protocol::protocol::TurnEnvironmentSelections::new(
|
||||
test.config.cwd.clone(),
|
||||
environments,
|
||||
);
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: Some(environments),
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(turn_environment_selections),
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(SandboxPolicy::new_read_only_policy()),
|
||||
@@ -284,10 +288,7 @@ async fn exec_command_routes_to_selected_remote_environment() -> Result<()> {
|
||||
let test = unified_exec_test(&server).await?;
|
||||
let local_cwd = TempDir::new()?;
|
||||
fs::write(local_cwd.path().join("marker.txt"), "local-routing")?;
|
||||
let local_selection = TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
};
|
||||
let local_selection = local(local_cwd.path().abs());
|
||||
let remote_cwd = PathBuf::from(format!(
|
||||
"/tmp/codex-remote-routing-{}",
|
||||
SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis()
|
||||
@@ -462,10 +463,7 @@ async fn remote_request_permissions_grant_unblocks_later_remote_exec() -> Result
|
||||
&test,
|
||||
"request permissions, then write in the remote environment",
|
||||
vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
},
|
||||
local(local_cwd.path().abs()),
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: remote_cwd.clone(),
|
||||
@@ -601,10 +599,7 @@ async fn apply_patch_freeform_routes_to_selected_remote_environment() -> Result<
|
||||
test.submit_turn_with_environments(
|
||||
"apply patch to remote environment",
|
||||
Some(vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
},
|
||||
local(local_cwd.path().abs()),
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: remote_cwd.clone(),
|
||||
@@ -682,10 +677,7 @@ async fn apply_patch_approvals_are_remembered_per_environment() -> Result<()> {
|
||||
.await?;
|
||||
|
||||
let environments = vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
},
|
||||
local(local_cwd.path().abs()),
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: remote_cwd.clone(),
|
||||
@@ -882,10 +874,7 @@ async fn apply_patch_intercepted_exec_command_routes_to_selected_remote_environm
|
||||
test.submit_turn_with_environments(
|
||||
"apply patch through exec command to remote environment",
|
||||
Some(vec![
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
},
|
||||
local(local_cwd.path().abs()),
|
||||
TurnEnvironmentSelection {
|
||||
environment_id: REMOTE_ENVIRONMENT_ID.to_string(),
|
||||
cwd: remote_cwd.clone(),
|
||||
|
||||
@@ -37,6 +37,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -158,7 +159,6 @@ async fn remote_models_config_context_window_override_clamps_to_max_context_wind
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -226,7 +226,6 @@ async fn remote_models_config_override_above_max_uses_max_context_window() -> Re
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -293,7 +292,6 @@ async fn remote_models_use_context_window_when_config_override_is_absent() -> Re
|
||||
text: "check context window".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -374,7 +372,6 @@ async fn remote_models_long_model_slug_is_sent_with_custom_reasoning() -> Result
|
||||
text: "check model slug".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -425,7 +422,6 @@ async fn namespaced_model_slug_uses_catalog_metadata_without_fallback_warning()
|
||||
text: "check namespaced model metadata".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
@@ -583,12 +579,11 @@ async fn remote_models_remote_model_uses_unified_exec() -> Result<()> {
|
||||
text: "run call".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -811,12 +806,11 @@ async fn remote_models_apply_remote_base_instructions() -> Result<()> {
|
||||
text: "hello remote".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -40,7 +40,6 @@ async fn request_body_is_zstd_compressed_for_codex_backend_when_enabled() -> any
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "compress me".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -91,7 +90,6 @@ async fn request_body_is_not_compressed_for_api_key_auth_even_when_enabled() ->
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "do not compress".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -31,6 +31,7 @@ use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -195,12 +196,11 @@ async fn submit_turn(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
|
||||
@@ -28,6 +28,7 @@ use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -147,12 +148,11 @@ async fn submit_turn(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer,
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use codex_features::Feature;
|
||||
@@ -142,12 +143,11 @@ async fn request_user_input_round_trip_for_mode(mode: ModeKind) -> anyhow::Resul
|
||||
text: "please confirm".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -286,12 +286,11 @@ async fn request_user_input_interrupt_emits_deferred_token_count() -> anyhow::Re
|
||||
text: "please confirm".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -391,12 +390,11 @@ where
|
||||
text: "please confirm".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -20,6 +20,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -150,12 +151,11 @@ async fn submit_turn_with_timeout(test: &TestCodex, prompt: &str) -> Result<()>
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::OnRequest),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -86,7 +86,6 @@ async fn resume_includes_initial_messages_from_rollout_events() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record some messages".into(),
|
||||
text_elements: text_elements.clone(),
|
||||
@@ -173,7 +172,6 @@ async fn resume_includes_initial_messages_from_reasoning_events() -> Result<()>
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record reasoning messages".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -264,7 +262,6 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record initial instructions".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -308,7 +305,6 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Resume with different model".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -327,7 +323,6 @@ async fn resume_switches_models_preserves_base_instructions() -> Result<()> {
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Second turn after resume".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -401,7 +396,6 @@ async fn resume_model_switch_is_not_duplicated_after_pre_turn_override() -> Resu
|
||||
.await;
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Record initial instructions".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -440,7 +434,6 @@ async fn resume_model_switch_is_not_duplicated_after_pre_turn_override() -> Resu
|
||||
resumed
|
||||
.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first turn after override".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -23,6 +23,7 @@ use core_test_support::responses::ResponseMock;
|
||||
use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -705,7 +706,6 @@ async fn review_history_surfaces_in_parent_session() {
|
||||
let followup = "back to parent".to_string();
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: followup.clone(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -821,7 +821,7 @@ async fn review_uses_overridden_cwd_for_base_branch_merge_base() {
|
||||
core_test_support::submit_thread_settings(
|
||||
&codex,
|
||||
codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(repo_path.to_path_buf().abs()),
|
||||
environments: Some(local_selections(repo_path.to_path_buf().abs())),
|
||||
..Default::default()
|
||||
},
|
||||
)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
use anyhow::Context as _;
|
||||
use anyhow::ensure;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::ffi::OsString;
|
||||
@@ -128,12 +129,11 @@ fn user_turn_with_permission_profile(
|
||||
text: text.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -21,6 +21,7 @@ use core_test_support::responses::sse_response;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -42,12 +43,11 @@ fn disabled_text_turn(test: &TestCodex, text: &str) -> Op {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -524,7 +524,6 @@ async fn tool_search_returns_deferred_tools_without_follow_up_tool_injection() -
|
||||
let test = builder.build(&server).await?;
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Find the calendar create tool".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -934,7 +933,6 @@ async fn tool_search_returns_deferred_dynamic_tool_and_routes_follow_up_call() -
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Use the automation tool".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1245,7 +1243,6 @@ async fn tool_search_surfaced_mcp_tool_errors_are_returned_to_model() -> Result<
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Find the rmcp echo tool and call it.".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -1563,7 +1560,6 @@ async fn tool_search_matches_dynamic_tools_by_name_description_namespace_and_sch
|
||||
|
||||
test.codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "Search for the dynamic tool".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -14,6 +14,7 @@ use core_test_support::responses::ev_response_created;
|
||||
use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::test_codex::TestCodexHarness;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -164,12 +165,11 @@ async fn run_snapshot_command_with_options(
|
||||
text: "run unified exec with shell snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -265,12 +265,11 @@ async fn run_shell_command_snapshot_with_options(
|
||||
text: "run shell_command with shell snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -346,12 +345,11 @@ async fn run_tool_turn_on_harness(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -590,12 +588,11 @@ async fn shell_command_snapshot_still_intercepts_apply_patch() -> Result<()> {
|
||||
text: "apply patch via shell_command with snapshot".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.clone()),
|
||||
environments: Some(local_selections(cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -13,6 +13,7 @@ use core_test_support::responses::mount_function_call_agent_response;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_event_match;
|
||||
@@ -51,12 +52,11 @@ async fn submit_turn_with_policies(
|
||||
text: prompt.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -16,6 +16,7 @@ use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use std::sync::Arc;
|
||||
@@ -85,12 +86,11 @@ async fn user_turn_includes_skill_instructions() -> Result<()> {
|
||||
path: skill_path.clone(),
|
||||
},
|
||||
],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -30,6 +30,7 @@ use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::stdio_server_bin;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -148,7 +149,6 @@ async fn resume_restores_dynamic_tools_from_rollout_with_sqlite_enabled() -> Res
|
||||
started
|
||||
.thread
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "persist this thread".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -560,12 +560,11 @@ async fn mcp_call_marks_thread_memory_mode_polluted_when_configured() -> Result<
|
||||
text: "call the rmcp echo tool".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -94,7 +94,6 @@ async fn continue_after_stream_error() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "first message".into(),
|
||||
text_elements: Vec::new(),
|
||||
@@ -117,7 +116,6 @@ async fn continue_after_stream_error() {
|
||||
// error above, this submission would be rejected/queued indefinitely.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "follow up".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -76,7 +76,6 @@ async fn retries_on_early_close() {
|
||||
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -30,6 +30,7 @@ use core_test_support::responses::sse_response;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event_match;
|
||||
@@ -768,12 +769,11 @@ async fn subagent_stop_replaces_stop_and_skips_internal_subagents() -> Result<()
|
||||
text: INTERNAL_SUBAGENT_PROMPT.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#![cfg(not(target_os = "windows"))]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::fs;
|
||||
|
||||
use assert_matches::assert_matches;
|
||||
@@ -108,12 +109,11 @@ async fn shell_command_tool_executes_command_and_streams_output() -> anyhow::Res
|
||||
text: "please run the shell command".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -190,12 +190,11 @@ async fn update_plan_tool_emits_plan_update_event() -> anyhow::Result<()> {
|
||||
text: "please update the plan".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -282,12 +281,11 @@ async fn update_plan_tool_rejects_malformed_payload() -> anyhow::Result<()> {
|
||||
text: "please update the plan".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -384,12 +382,11 @@ async fn apply_patch_tool_executes_and_emits_patch_events() -> anyhow::Result<()
|
||||
text: "please apply a patch".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -523,12 +520,11 @@ async fn apply_patch_reports_parse_diagnostics() -> anyhow::Result<()> {
|
||||
text: "please apply a patch".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd_path),
|
||||
environments: Some(local_selections(cwd_path)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#![cfg(not(target_os = "windows"))]
|
||||
#![allow(clippy::unwrap_used)]
|
||||
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::fs;
|
||||
use std::time::Duration;
|
||||
use std::time::Instant;
|
||||
@@ -42,12 +43,11 @@ async fn run_turn(test: &TestCodex, prompt: &str) -> anyhow::Result<()> {
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -369,12 +369,11 @@ async fn shell_tools_start_before_response_completed_when_stream_delayed() -> an
|
||||
text: "stream delayed completion".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -16,7 +16,6 @@ use codex_protocol::permissions::FileSystemSandboxEntry;
|
||||
use codex_protocol::permissions::FileSystemSandboxPolicy;
|
||||
use codex_protocol::permissions::NetworkSandboxPolicy;
|
||||
use codex_protocol::protocol::AskForApproval;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use core_test_support::assert_regex_match;
|
||||
use core_test_support::responses::ev_assistant_message;
|
||||
use core_test_support::responses::ev_completed;
|
||||
@@ -29,6 +28,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::skip_if_sandbox;
|
||||
use core_test_support::test_codex::local;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use regex_lite::Regex;
|
||||
use serde_json::Value;
|
||||
@@ -117,10 +117,7 @@ async fn turn_environment_selection_keeps_environment_backed_tools() -> Result<(
|
||||
|
||||
test.submit_turn_with_environments(
|
||||
"which tools are available?",
|
||||
Some(vec![TurnEnvironmentSelection {
|
||||
environment_id: "local".to_string(),
|
||||
cwd: test.config.cwd.clone(),
|
||||
}]),
|
||||
Some(vec![local(test.config.cwd.clone())]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::stdio_server_bin;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_mcp_server;
|
||||
@@ -524,12 +525,11 @@ async fn mcp_image_output_preserves_image_and_no_text_summary() -> Result<()> {
|
||||
text: "call the rmcp image tool".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(fixture.cwd.abs()),
|
||||
environments: Some(local_selections(fixture.cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile: Some(permission_profile),
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::OsStr;
|
||||
use std::fs;
|
||||
@@ -198,12 +199,11 @@ async fn submit_unified_exec_turn(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -290,12 +290,11 @@ async fn unified_exec_intercepts_apply_patch_exec_command() -> Result<()> {
|
||||
text: "apply patch via unified exec".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -2146,12 +2145,11 @@ async fn unified_exec_keeps_long_running_session_after_turn_end() -> Result<()>
|
||||
text: "keep unified exec process after turn end".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(turn_cwd),
|
||||
environments: Some(local_selections(turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -2250,12 +2248,11 @@ async fn unified_exec_interrupt_preserves_long_running_session() -> Result<()> {
|
||||
text: "interrupt long-running unified exec".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(turn_cwd),
|
||||
environments: Some(local_selections(turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -2723,12 +2720,11 @@ async fn unified_exec_runs_under_sandbox() -> Result<()> {
|
||||
text: "summarize large output".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(turn_cwd),
|
||||
environments: Some(local_selections(turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -2846,12 +2842,11 @@ async fn unified_exec_enforces_glob_deny_read_policy() -> Result<()> {
|
||||
text: "read the fixture files".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(turn_cwd),
|
||||
environments: Some(local_selections(turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -2985,12 +2980,11 @@ async fn unified_exec_python_prompt_under_seatbelt() -> Result<()> {
|
||||
text: "start python under seatbelt".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(turn_cwd),
|
||||
environments: Some(local_selections(turn_cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -31,6 +31,7 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
use core_test_support::wait_for_event_with_timeout;
|
||||
@@ -406,12 +407,11 @@ async fn submit_turn_with_session_permissions(
|
||||
text: prompt.into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(approval_policy),
|
||||
approvals_reviewer: Some(ApprovalsReviewer::User),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
|
||||
@@ -57,7 +57,6 @@ mv "${tmp_path}" "${payload_path}""#,
|
||||
// 1) Normal user input – should hit server once.
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: "hello world".into(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -21,6 +21,7 @@ use core_test_support::responses::mount_sse_once;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event;
|
||||
@@ -179,12 +180,11 @@ async fn user_shell_command_does_not_replace_active_turn() -> anyhow::Result<()>
|
||||
text: "run model shell command".to_string(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd),
|
||||
environments: Some(local_selections(cwd)),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -42,6 +42,8 @@ use core_test_support::responses::sse;
|
||||
use core_test_support::responses::start_mock_server;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use core_test_support::wait_for_event_with_timeout;
|
||||
@@ -74,12 +76,11 @@ fn disabled_user_turn(test: &TestCodex, items: Vec<UserInput>, model: String) ->
|
||||
turn_permission_fields(PermissionProfile::Disabled, test.config.cwd.as_path());
|
||||
Op::UserInput {
|
||||
items,
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(test.config.cwd.clone()),
|
||||
environments: Some(local_selections(test.config.cwd.clone())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
@@ -456,10 +457,7 @@ async fn view_image_routes_to_selected_local_environment() -> anyhow::Result<()>
|
||||
|
||||
test.submit_turn_with_environments(
|
||||
"route local view image",
|
||||
Some(vec![TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: test.config.cwd.clone(),
|
||||
}]),
|
||||
Some(vec![local(test.config.cwd.clone())]),
|
||||
)
|
||||
.await?;
|
||||
|
||||
@@ -572,10 +570,7 @@ async fn view_image_routes_to_selected_remote_environment() -> anyhow::Result<()
|
||||
let test = builder.build_with_remote_and_local_env(&server).await?;
|
||||
let local_cwd = TempDir::new()?;
|
||||
fs::write(local_cwd.path().join("remote.png"), b"not a remote image")?;
|
||||
let local_selection = TurnEnvironmentSelection {
|
||||
environment_id: LOCAL_ENVIRONMENT_ID.to_string(),
|
||||
cwd: local_cwd.path().abs(),
|
||||
};
|
||||
let local_selection = local(local_cwd.path().abs());
|
||||
let remote_cwd = PathBuf::from(format!(
|
||||
"/tmp/codex-view-image-routing-{}",
|
||||
SystemTime::now().duration_since(UNIX_EPOCH)?.as_millis()
|
||||
|
||||
@@ -14,6 +14,7 @@ use core_test_support::responses::mount_sse_sequence;
|
||||
use core_test_support::responses::sse;
|
||||
use core_test_support::skip_if_no_network;
|
||||
use core_test_support::test_codex::TestCodex;
|
||||
use core_test_support::test_codex::local_selections;
|
||||
use core_test_support::test_codex::test_codex;
|
||||
use core_test_support::test_codex::turn_permission_fields;
|
||||
use pretty_assertions::assert_eq;
|
||||
@@ -158,12 +159,11 @@ async fn websocket_fallback_hides_first_websocket_retry_stream_error() -> Result
|
||||
text: "hello".into(),
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
thread_settings: codex_protocol::protocol::ThreadSettingsOverrides {
|
||||
cwd: Some(cwd.abs()),
|
||||
environments: Some(local_selections(cwd.abs())),
|
||||
approval_policy: Some(AskForApproval::Never),
|
||||
sandbox_policy: Some(sandbox_policy),
|
||||
permission_profile,
|
||||
|
||||
@@ -104,7 +104,6 @@ async fn window_id_advances_after_compact_persists_on_resume_and_resets_on_fork(
|
||||
async fn submit_user_turn(codex: &Arc<CodexThread>, text: &str) -> Result<()> {
|
||||
codex
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: text.to_string(),
|
||||
text_elements: Vec::new(),
|
||||
|
||||
@@ -103,7 +103,6 @@ pub async fn run_codex_tool_session(
|
||||
let submission = Submission {
|
||||
id: sub_id.clone(),
|
||||
op: Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: initial_prompt.clone(),
|
||||
// MCP tool prompts are plain text with no UI element ranges.
|
||||
@@ -155,7 +154,6 @@ pub async fn run_codex_tool_session_reply(
|
||||
.insert(request_id.clone(), thread_id);
|
||||
if let Err(e) = thread
|
||||
.submit(Op::UserInput {
|
||||
environments: None,
|
||||
items: vec![UserInput::Text {
|
||||
text: prompt,
|
||||
// MCP tool prompts are plain text with no UI element ranges.
|
||||
|
||||
@@ -259,7 +259,6 @@ impl MemoryStartupContext {
|
||||
.thread
|
||||
.submit(Op::UserInput {
|
||||
items: prompt,
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
|
||||
@@ -112,6 +112,34 @@ pub struct TurnEnvironmentSelection {
|
||||
pub cwd: AbsolutePathBuf,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct TurnEnvironmentSelections {
|
||||
pub legacy_fallback_cwd: AbsolutePathBuf,
|
||||
pub environments: Vec<TurnEnvironmentSelection>,
|
||||
}
|
||||
|
||||
impl TurnEnvironmentSelections {
|
||||
pub fn new(
|
||||
legacy_fallback_cwd: AbsolutePathBuf,
|
||||
environments: Vec<TurnEnvironmentSelection>,
|
||||
) -> Self {
|
||||
let mut settings = Self {
|
||||
legacy_fallback_cwd,
|
||||
environments,
|
||||
};
|
||||
settings.sync_primary_environment_cwd();
|
||||
settings
|
||||
}
|
||||
|
||||
fn sync_primary_environment_cwd(&mut self) {
|
||||
if let Some(turn_environment) = self.environments.first_mut()
|
||||
&& turn_environment.cwd != self.legacy_fallback_cwd
|
||||
{
|
||||
turn_environment.cwd = self.legacy_fallback_cwd.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema, TS)]
|
||||
#[serde(transparent)]
|
||||
#[ts(type = "string")]
|
||||
@@ -370,8 +398,8 @@ pub struct ConversationTextParams {
|
||||
/// on their own.
|
||||
#[derive(Debug, Clone, Default, PartialEq)]
|
||||
pub struct ThreadSettingsOverrides {
|
||||
/// Updated `cwd` for sandbox/tool calls.
|
||||
pub cwd: Option<AbsolutePathBuf>,
|
||||
/// Updated fallback `cwd` and environments supplied together as a complete pair.
|
||||
pub environments: Option<TurnEnvironmentSelections>,
|
||||
|
||||
/// Updated runtime workspace roots used to materialize symbolic
|
||||
/// `:workspace_roots` filesystem permissions.
|
||||
@@ -472,8 +500,6 @@ pub enum Op {
|
||||
UserInput {
|
||||
/// User input items, see `InputItem`
|
||||
items: Vec<UserInput>,
|
||||
/// Optional turn-scoped environments.
|
||||
environments: Option<Vec<TurnEnvironmentSelection>>,
|
||||
/// Optional JSON Schema used to constrain the final assistant message for this turn.
|
||||
final_output_json_schema: Option<Value>,
|
||||
/// Optional turn-scoped Responses API `client_metadata`.
|
||||
@@ -612,7 +638,6 @@ pub enum ThreadMemoryMode {
|
||||
impl From<Vec<UserInput>> for Op {
|
||||
fn from(value: Vec<UserInput>) -> Self {
|
||||
Op::UserInput {
|
||||
environments: None,
|
||||
items: value,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
|
||||
@@ -296,7 +296,6 @@ async fn run_turn(thread: &CodexThread, thread_id: &str, prompt: String) -> anyh
|
||||
text: prompt,
|
||||
text_elements: Vec::new(),
|
||||
}],
|
||||
environments: None,
|
||||
final_output_json_schema: None,
|
||||
responsesapi_client_metadata: None,
|
||||
additional_context: Default::default(),
|
||||
|
||||
Reference in New Issue
Block a user