Remove unused Rust helpers (#34345)

## What changed

- Remove unused APIs and test helpers across the Rust workspace.
- Route Linux sandbox test setup through the shared exec request path.
- Drop dependencies that became unnecessary after the cleanup.

GitOrigin-RevId: 48fd9b2b1575bad7add0819786b4d8ec88d8486f
This commit is contained in:
Charlie Marsh
2026-07-20 13:45:29 +00:00
committed by copyberry
parent 86102db5a1
commit 221a341029
39 changed files with 29 additions and 725 deletions
-3
View File
@@ -4405,8 +4405,6 @@ dependencies = [
name = "codex-utils-sandbox-summary"
version = "0.0.0"
dependencies = [
"codex-core",
"codex-model-provider-info",
"codex-protocol",
"codex-utils-absolute-path",
"pretty_assertions",
@@ -8911,7 +8909,6 @@ dependencies = [
"os_info",
"pretty_assertions",
"rmcp",
"serde",
"serde_json",
"shlex",
"tokio",
-7
View File
@@ -198,13 +198,6 @@ pub async fn bootstrap(options: BootstrapOptions) -> Result<BootstrapOutput> {
Daemon::from_environment()?.bootstrap(options).await
}
pub async fn ensure_remote_control_started() -> Result<RemoteControlStartOutput> {
ensure_supported_platform()?;
Daemon::from_environment()?
.ensure_remote_control_started()
.await
}
pub async fn ensure_remote_control_ready() -> Result<RemoteControlReadyOutput> {
ensure_supported_platform()?;
Daemon::from_environment()?
@@ -25,7 +25,6 @@ use crate::protocol::v2::ThreadItem;
use codex_protocol::ThreadId;
use codex_protocol::parse_command::ParsedCommand;
use codex_protocol::protocol::ApplyPatchApprovalRequestEvent;
use codex_protocol::protocol::ExecApprovalRequestEvent;
use codex_protocol::protocol::ExecCommandBeginEvent;
use codex_protocol::protocol::ExecCommandEndEvent;
use codex_protocol::protocol::FileChange;
@@ -76,28 +75,6 @@ pub fn build_file_change_end_item(payload: &PatchApplyEndEvent) -> ThreadItem {
}
}
pub fn build_command_execution_approval_request_item(
payload: &ExecApprovalRequestEvent,
) -> ThreadItem {
ThreadItem::CommandExecution {
id: payload.call_id.clone(),
command: shlex_join(&payload.command),
cwd: payload.cwd.clone().into(),
process_id: None,
source: CommandExecutionSource::Agent,
status: CommandExecutionStatus::InProgress,
command_actions: payload
.parsed_cmd
.iter()
.cloned()
.map(|parsed| CommandAction::from_core_with_cwd(parsed, &payload.cwd))
.collect(),
aggregated_output: None,
exit_code: None,
duration_ms: None,
}
}
pub fn build_command_execution_begin_item(payload: &ExecCommandBeginEvent) -> ThreadItem {
let command_actions = command_actions_for_path_uri(&payload.parsed_cmd, &payload.cwd);
ThreadItem::CommandExecution {
@@ -31,7 +31,6 @@ use codex_app_server_protocol::ConfigReadParams;
use codex_app_server_protocol::ConfigValueWriteParams;
use codex_app_server_protocol::ConsumeAccountRateLimitResetCreditParams;
use codex_app_server_protocol::ExperimentalFeatureListParams;
use codex_app_server_protocol::FeedbackUploadParams;
use codex_app_server_protocol::FsCopyParams;
use codex_app_server_protocol::FsCreateDirectoryParams;
use codex_app_server_protocol::FsGetMetadataParams;
@@ -71,9 +70,7 @@ use codex_app_server_protocol::PluginReadParams;
use codex_app_server_protocol::PluginSkillReadParams;
use codex_app_server_protocol::PluginUninstallParams;
use codex_app_server_protocol::ProcessKillParams;
use codex_app_server_protocol::ProcessResizePtyParams;
use codex_app_server_protocol::ProcessSpawnParams;
use codex_app_server_protocol::ProcessWriteStdinParams;
use codex_app_server_protocol::RemoteControlClientsListParams;
use codex_app_server_protocol::RemoteControlClientsRevokeParams;
use codex_app_server_protocol::RemoteControlPairingStartParams;
@@ -147,7 +144,6 @@ pub struct TestAppServer {
pending_messages: VecDeque<JSONRPCMessage>,
auto_env: Option<TestEnv>,
json_logs: JsonLogCapture,
codex_home: PathBuf,
// Fields drop in declaration order. Tear down the delayed child before
// removing an owned CODEX_HOME that may still be its cwd on Windows.
_delayed_exec_server: Option<(LocalWebsocketExecServer, WebsocketDelayInterposer)>,
@@ -205,11 +201,6 @@ impl TestAppServer {
})
}
/// Returns the effective CODEX_HOME used by the child app-server.
pub fn codex_home(&self) -> &Path {
&self.codex_home
}
/// Waits for a JSON stderr event whose structured `event.name` field matches.
pub async fn wait_for_json_log_event(
&self,
@@ -218,20 +209,6 @@ impl TestAppServer {
self.json_logs.wait_for_event(event_name).await
}
/// Waits for the requested number of JSON stderr events with the same `event.name` field.
pub async fn wait_for_json_log_events(
&self,
event_name: &str,
count: usize,
) -> anyhow::Result<Vec<serde_json::Value>> {
self.json_logs.wait_for_events(event_name, count).await
}
/// Returns every stderr line parsed and validated as a JSON log event.
pub fn json_log_events(&self) -> anyhow::Result<Vec<serde_json::Value>> {
self.json_logs.events()
}
async fn new_with_program_env_and_args(
codex_home: &Path,
program: &Path,
@@ -300,7 +277,6 @@ impl TestAppServer {
pending_messages: VecDeque::new(),
auto_env: None,
json_logs,
codex_home: codex_home.to_path_buf(),
_delayed_exec_server: None,
_owned_codex_home: None,
})
@@ -461,15 +437,6 @@ impl TestAppServer {
.await
}
/// Send a `feedback/upload` JSON-RPC request.
pub async fn send_feedback_upload_request(
&mut self,
params: FeedbackUploadParams,
) -> anyhow::Result<i64> {
let params = Some(serde_json::to_value(params)?);
self.send_request("feedback/upload", params).await
}
/// Send a `thread/start` JSON-RPC request.
pub async fn send_thread_start_request(
&mut self,
@@ -1047,24 +1014,6 @@ impl TestAppServer {
self.send_request("process/spawn", params).await
}
/// Send a `process/writeStdin` JSON-RPC request (v2).
pub async fn send_process_write_stdin_request(
&mut self,
params: ProcessWriteStdinParams,
) -> anyhow::Result<i64> {
let params = Some(serde_json::to_value(params)?);
self.send_request("process/writeStdin", params).await
}
/// Send a `process/resizePty` JSON-RPC request (v2).
pub async fn send_process_resize_pty_request(
&mut self,
params: ProcessResizePtyParams,
) -> anyhow::Result<i64> {
let params = Some(serde_json::to_value(params)?);
self.send_request("process/resizePty", params).await
}
/// Send a `process/kill` JSON-RPC request (v2).
pub async fn send_process_kill_request(
&mut self,
@@ -272,10 +272,6 @@ pub struct NetworkDomainPermissionsToml {
}
impl NetworkDomainPermissionsToml {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn allowed_domains(&self) -> Option<Vec<String>> {
let allowed_domains: Vec<String> = self
.entries
@@ -321,10 +317,6 @@ pub struct NetworkUnixSocketPermissionsToml {
}
impl NetworkUnixSocketPermissionsToml {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn allow_unix_sockets(&self) -> Vec<String> {
self.entries
.iter()
-8
View File
@@ -250,10 +250,6 @@ pub struct NetworkDomainPermissionsToml {
}
impl NetworkDomainPermissionsToml {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn allowed_domains(&self) -> Option<Vec<String>> {
let allowed_domains: Vec<String> = self
.entries
@@ -301,10 +297,6 @@ pub struct NetworkUnixSocketPermissionsToml {
}
impl NetworkUnixSocketPermissionsToml {
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn allow_unix_sockets(&self) -> Vec<String> {
self.entries
.iter()
-4
View File
@@ -75,10 +75,6 @@ impl ThreadConfigLoadError {
pub fn code(&self) -> ThreadConfigLoadErrorCode {
self.code
}
pub fn status_code(&self) -> Option<u16> {
self.status_code
}
}
/// Loads typed config sources for a new thread.
-12
View File
@@ -190,18 +190,6 @@ pub enum UriBasedFileOpener {
None,
}
impl UriBasedFileOpener {
pub fn get_scheme(&self) -> Option<&str> {
match self {
UriBasedFileOpener::VsCode => Some("vscode"),
UriBasedFileOpener::VsCodeInsiders => Some("vscode-insiders"),
UriBasedFileOpener::Windsurf => Some("windsurf"),
UriBasedFileOpener::Cursor => Some("cursor"),
UriBasedFileOpener::None => None,
}
}
}
/// Settings that govern if and what will be written to `~/.codex/history.jsonl`.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)]
#[serde(default)]
-47
View File
@@ -739,16 +739,6 @@ fn apply_blocking_to_resolved_file(
Ok(())
}
/// Persist edits asynchronously by offloading the blocking writer.
///
pub async fn apply(codex_home: &Path, edits: Vec<ConfigEdit>) -> anyhow::Result<()> {
let codex_home = codex_home.to_path_buf();
let config_path = codex_home.join(CONFIG_TOML_FILE);
task::spawn_blocking(move || apply_blocking_to_resolved_file(&config_path, &edits))
.await
.context("config persistence task panicked")?
}
/// Fluent builder to batch config edits and apply them atomically.
#[derive(Default)]
pub struct ConfigEditsBuilder {
@@ -790,12 +780,6 @@ impl ConfigEditsBuilder {
self
}
pub fn set_personality(mut self, personality: Option<Personality>) -> Self {
self.edits
.push(ConfigEdit::SetModelPersonality { personality });
self
}
pub fn set_hide_full_access_warning(mut self, acknowledged: bool) -> Self {
self.edits
.push(ConfigEdit::SetNoticeHideFullAccessWarning(acknowledged));
@@ -814,37 +798,6 @@ impl ConfigEditsBuilder {
self
}
pub fn set_hide_model_migration_prompt(mut self, model: &str, acknowledged: bool) -> Self {
self.edits
.push(ConfigEdit::SetNoticeHideModelMigrationPrompt(
model.to_string(),
acknowledged,
));
self
}
pub fn set_hide_external_config_migration_prompt_home(mut self, acknowledged: bool) -> Self {
self.edits
.push(ConfigEdit::SetNoticeHideExternalConfigMigrationPromptHome(
acknowledged,
));
self
}
pub fn set_hide_external_config_migration_prompt_project(
mut self,
project: &str,
acknowledged: bool,
) -> Self {
self.edits.push(
ConfigEdit::SetNoticeHideExternalConfigMigrationPromptProject(
project.to_string(),
acknowledged,
),
);
self
}
pub fn record_model_migration_seen(mut self, from: &str, to: &str) -> Self {
self.edits.push(ConfigEdit::RecordModelMigrationSeen {
from: from.to_string(),
-70
View File
@@ -1,70 +0,0 @@
use crate::spawn::SpawnChildRequest;
use crate::spawn::StdioPolicy;
use crate::spawn::spawn_child_async;
use codex_network_proxy::NetworkProxy;
use codex_protocol::models::PermissionProfile;
use codex_sandboxing::landlock::CODEX_LINUX_SANDBOX_ARG0;
use codex_sandboxing::landlock::allow_network_for_proxy;
use codex_sandboxing::landlock::create_linux_sandbox_command_args_for_permission_profile;
use codex_utils_absolute_path::AbsolutePathBuf;
use std::collections::HashMap;
use std::path::Path;
use tokio::process::Child;
/// Spawn a shell tool command under the Linux sandbox helper
/// (codex-linux-sandbox), which defaults to bubblewrap for filesystem
/// isolation plus seccomp for network restrictions.
///
/// Unlike macOS Seatbelt where we directly embed the policy text, the Linux
/// helper is a separate executable. We pass the canonical permission profile
/// as JSON and let the helper derive the runtime filesystem/network policies.
#[allow(clippy::too_many_arguments)]
pub async fn spawn_command_under_linux_sandbox<P>(
codex_linux_sandbox_exe: P,
command: Vec<String>,
command_cwd: AbsolutePathBuf,
permission_profile: &PermissionProfile,
sandbox_policy_cwd: &AbsolutePathBuf,
use_legacy_landlock: bool,
stdio_policy: StdioPolicy,
network: Option<&NetworkProxy>,
env: HashMap<String, String>,
) -> std::io::Result<Child>
where
P: AsRef<Path>,
{
let network_sandbox_policy = permission_profile.network_sandbox_policy();
let args = create_linux_sandbox_command_args_for_permission_profile(
command,
command_cwd.as_path(),
permission_profile,
sandbox_policy_cwd,
use_legacy_landlock,
allow_network_for_proxy(/*enforce_managed_network*/ false),
);
let codex_linux_sandbox_exe = codex_linux_sandbox_exe.as_ref();
// Preserve the helper alias when we already have it; otherwise force argv0
// so arg0 dispatch still reaches the Linux sandbox path.
let arg0 = if codex_linux_sandbox_exe
.file_name()
.and_then(|name| name.to_str())
== Some(CODEX_LINUX_SANDBOX_ARG0)
{
// Old bubblewrap builds without `--argv0` need a real helper path whose
// basename still dispatches to the Linux sandbox entrypoint.
codex_linux_sandbox_exe.to_string_lossy().into_owned()
} else {
CODEX_LINUX_SANDBOX_ARG0.to_string()
};
spawn_child_async(SpawnChildRequest {
program: codex_linux_sandbox_exe.to_path_buf(),
args,
arg0: Some(&arg0),
cwd: command_cwd,
network_sandbox_policy,
network,
stdio_policy,
env,
})
.await
}
-3
View File
@@ -53,8 +53,6 @@ mod guardian;
mod hook_runtime;
mod image_preparation;
mod installation_id;
pub(crate) mod landlock;
pub use landlock::spawn_command_under_linux_sandbox;
pub(crate) mod mcp;
mod mcp_skill_dependencies;
mod mcp_tool_approval_templates;
@@ -120,7 +118,6 @@ pub use thread_manager::build_models_manager;
pub use thread_manager::local_agent_graph_store_from_state_db;
pub use thread_manager::thread_store_from_config;
pub use web_search::web_search_action_detail;
pub use web_search::web_search_detail;
pub use windows_sandbox_read_grants::grant_read_root_non_elevated;
#[deprecated(note = "use ThreadManager")]
pub type ConversationManager = ThreadManager;
-6
View File
@@ -94,12 +94,6 @@ pub fn build_provider(
})
}
/// Filter predicate for exporting only Codex-owned events via OTEL.
/// Keeps events that originated from codex_otel module
pub fn codex_export_filter(meta: &tracing::Metadata<'_>) -> bool {
meta.target().starts_with("codex_otel")
}
pub fn record_process_start(otel: Option<&OtelProvider>, originator: &str) {
let Some(metrics) = otel.and_then(OtelProvider::metrics) else {
return;
-16
View File
@@ -101,22 +101,6 @@ pub fn thread_manager_with_models_provider_and_home(
)
}
pub fn thread_manager_with_models_provider_home_and_state(
auth: CodexAuth,
provider: ModelProviderInfo,
codex_home: PathBuf,
environment_manager: Arc<EnvironmentManager>,
state_db: Option<crate::StateDbHandle>,
) -> ThreadManager {
ThreadManager::with_models_provider_home_and_state_for_tests(
auth,
provider,
codex_home,
environment_manager,
state_db,
)
}
pub async fn start_thread_with_user_shell_override(
thread_manager: &ThreadManager,
config: Config,
+3 -10
View File
@@ -1,5 +1,3 @@
use std::path::Path;
use std::path::PathBuf;
use std::time::Duration;
use rand::Rng;
@@ -20,6 +18,9 @@ const BACKOFF_FACTOR: f64 = 2.0;
/// Example:
///
/// ```rust
/// let provider_id = "openai";
/// let request_id = "req-123";
///
/// codex_core::feedback_tags!(model = "gpt-5", cached = true);
/// codex_core::feedback_tags!(provider = provider_id, request_id = request_id);
/// ```
@@ -97,14 +98,6 @@ pub(crate) fn error_or_panic(message: impl std::string::ToString) {
}
}
pub fn resolve_path(base: &Path, path: &PathBuf) -> PathBuf {
if path.is_absolute() {
path.clone()
} else {
base.join(path)
}
}
/// Trim a thread name and return `None` if it is empty after trimming.
pub fn normalize_thread_name(name: &str) -> Option<String> {
let trimmed = name.trim();
-9
View File
@@ -28,12 +28,3 @@ pub fn web_search_action_detail(action: &WebSearchAction) -> String {
WebSearchAction::Other => String::new(),
}
}
pub fn web_search_detail(action: Option<&WebSearchAction>, query: &str) -> String {
let detail = action.map(web_search_action_detail).unwrap_or_default();
if detail.is_empty() {
query.to_string()
} else {
detail
}
}
+17 -54
View File
@@ -16,12 +16,6 @@ use std::path::Path;
use std::path::PathBuf;
use std::time::Instant;
/// Kill switch for the elevated sandbox NUX on Windows.
///
/// When false, revert to the previous sandbox NUX, which only
/// prompts users to enable the legacy sandbox feature.
pub const ELEVATED_SANDBOX_NUX_ENABLED: bool = true;
pub trait WindowsSandboxLevelExt {
fn from_config(config: &Config) -> WindowsSandboxLevel;
fn from_features(features: &Features) -> WindowsSandboxLevel;
@@ -48,14 +42,6 @@ impl WindowsSandboxLevelExt for WindowsSandboxLevel {
}
}
pub fn windows_sandbox_level_from_config(config: &Config) -> WindowsSandboxLevel {
WindowsSandboxLevel::from_config(config)
}
pub fn windows_sandbox_level_from_features(features: &Features) -> WindowsSandboxLevel {
WindowsSandboxLevel::from_features(features)
}
pub fn resolve_windows_sandbox_mode(cfg: &ConfigToml) -> Option<WindowsSandboxModeToml> {
cfg.windows
.as_ref()
@@ -112,38 +98,6 @@ pub fn sandbox_setup_is_complete(_codex_home: &Path) -> bool {
false
}
#[cfg(target_os = "windows")]
pub fn elevated_setup_failure_details(err: &anyhow::Error) -> Option<(String, String)> {
let failure = codex_windows_sandbox::extract_setup_failure(err)?;
let code = failure.code.as_str().to_string();
let message = codex_windows_sandbox::sanitize_setup_metric_tag_value(&failure.message);
Some((code, message))
}
#[cfg(not(target_os = "windows"))]
pub fn elevated_setup_failure_details(_err: &anyhow::Error) -> Option<(String, String)> {
None
}
#[cfg(target_os = "windows")]
pub fn elevated_setup_failure_metric_name(err: &anyhow::Error) -> &'static str {
if codex_windows_sandbox::extract_setup_failure(err).is_some_and(|failure| {
matches!(
failure.code,
codex_windows_sandbox::SetupErrorCode::OrchestratorHelperLaunchCanceled
)
}) {
"codex.windows_sandbox.elevated_setup_canceled"
} else {
"codex.windows_sandbox.elevated_setup_failure"
}
}
#[cfg(not(target_os = "windows"))]
pub fn elevated_setup_failure_metric_name(_err: &anyhow::Error) -> &'static str {
panic!("elevated_setup_failure_metric_name is only supported on Windows")
}
#[cfg(target_os = "windows")]
pub fn run_elevated_setup(
permission_profile: &PermissionProfile,
@@ -398,9 +352,11 @@ fn emit_windows_sandbox_setup_failure_metrics(
let mut failure_tags: Vec<(&str, &str)> = vec![("originator", originator_tag)];
let mut code_tag: Option<String> = None;
let mut message_tag: Option<String> = None;
if let Some((code, message)) = elevated_setup_failure_details(_err) {
code_tag = Some(code);
message_tag = Some(message);
if let Some(failure) = codex_windows_sandbox::extract_setup_failure(_err) {
code_tag = Some(failure.code.as_str().to_string());
message_tag = Some(codex_windows_sandbox::sanitize_setup_metric_tag_value(
&failure.message,
));
}
if let Some(code) = code_tag.as_deref() {
failure_tags.push(("code", code));
@@ -408,11 +364,18 @@ fn emit_windows_sandbox_setup_failure_metrics(
if let Some(message) = message_tag.as_deref() {
failure_tags.push(("message", message));
}
let _ = metrics.counter(
elevated_setup_failure_metric_name(_err),
/*inc*/ 1,
&failure_tags,
);
let metric_name =
if codex_windows_sandbox::extract_setup_failure(_err).is_some_and(|failure| {
matches!(
failure.code,
codex_windows_sandbox::SetupErrorCode::OrchestratorHelperLaunchCanceled
)
}) {
"codex.windows_sandbox.elevated_setup_canceled"
} else {
"codex.windows_sandbox.elevated_setup_failure"
};
let _ = metrics.counter(metric_name, /*inc*/ 1, &failure_tags);
}
} else {
let _ = metrics.counter(
-36
View File
@@ -929,21 +929,6 @@ pub fn ev_custom_tool_call_with_namespace(
})
}
pub fn ev_local_shell_call(call_id: &str, status: &str, command: Vec<&str>) -> Value {
serde_json::json!({
"type": "response.output_item.done",
"item": {
"type": "local_shell_call",
"call_id": call_id,
"status": status,
"action": {
"type": "exec",
"command": command,
}
}
})
}
/// Convenience: SSE event for an `apply_patch` custom tool call with raw patch
/// text. This mirrors the payload produced by the Responses API when the model
/// invokes `apply_patch` directly.
@@ -1064,27 +1049,6 @@ pub async fn mount_sse_once(server: &MockServer, body: String) -> ResponseMock {
response_mock
}
pub async fn mount_compact_json_once_match<M>(
server: &MockServer,
matcher: M,
body: serde_json::Value,
) -> ResponseMock
where
M: wiremock::Match + Send + Sync + 'static,
{
let (mock, response_mock) = compact_mock();
mock.and(matcher)
.respond_with(
ResponseTemplate::new(200)
.insert_header("content-type", "application/json")
.set_body_json(body.clone()),
)
.up_to_n_times(1)
.mount(server)
.await;
response_mock
}
pub async fn mount_compact_json_once(server: &MockServer, body: serde_json::Value) -> ResponseMock {
mount_compact_response_once(
server,
-29
View File
@@ -279,13 +279,6 @@ pub enum ApplyPatchModelOutput {
ShellCommandViaHeredoc,
}
/// A collection of different ways the model can output an apply_patch call
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ShellModelOutput {
ShellCommand,
// UnifiedExec has its own set of tests
}
/// Returns the permission fields required by test thread-settings overrides.
pub fn turn_permission_fields(
permission_profile: PermissionProfile,
@@ -1023,14 +1016,6 @@ pub struct TestCodexHarness {
}
impl TestCodexHarness {
pub async fn new() -> Result<Self> {
Self::with_builder(test_codex()).await
}
pub async fn with_config(mutator: impl FnOnce(&mut Config) + Send + 'static) -> Result<Self> {
Self::with_builder(test_codex().with_config(mutator)).await
}
pub async fn with_builder(mut builder: TestCodexBuilder) -> Result<Self> {
let server = start_mock_server().await;
let test = builder.build(&server).await?;
@@ -1055,10 +1040,6 @@ impl TestCodexHarness {
self.test.config.cwd.as_path()
}
pub fn cwd_abs(&self) -> AbsolutePathBuf {
self.test.config.cwd.clone()
}
pub fn path(&self, rel: impl AsRef<Path>) -> PathBuf {
self.path_abs(rel).into_path_buf()
}
@@ -1160,16 +1141,6 @@ impl TestCodexHarness {
Box::pin(self.test.submit_turn(prompt)).await
}
pub async fn submit_with_policy(
&self,
prompt: &str,
sandbox_policy: SandboxPolicy,
) -> Result<()> {
self.test
.submit_turn_with_policy(prompt, sandbox_policy)
.await
}
pub async fn submit_with_permission_profile(
&self,
prompt: &str,
-8
View File
@@ -625,14 +625,6 @@ impl ExecServerClient {
}
}
pub async fn initialize(
&self,
options: ExecServerClientConnectOptions,
) -> Result<InitializeResponse, ExecServerError> {
let rpc_client = self.rpc_client().await?;
self.initialize_rpc(&rpc_client, options).await
}
async fn initialize_rpc(
&self,
rpc_client: &RpcClient,
-6
View File
@@ -332,12 +332,6 @@ impl EnvironmentManager {
self.local_environment.as_ref().map(Arc::clone)
}
/// Returns the default environment or local environment when either exists.
pub fn default_or_local_environment(&self) -> Option<Arc<Environment>> {
self.default_environment()
.or_else(|| self.try_local_environment())
}
/// Returns a named environment instance.
pub fn get_environment(&self, environment_id: &str) -> Option<Arc<Environment>> {
self.environments
@@ -7,7 +7,6 @@ use codex_protocol::capabilities::SelectedCapabilityRoot;
use crate::Environment;
use crate::EnvironmentManager;
use crate::ExecutorFileSystem;
/// A selected capability root paired with its currently ready environment handle.
///
@@ -37,10 +36,6 @@ impl ResolvedSelectedCapabilityRoot {
pub fn environment(&self) -> &Arc<Environment> {
&self.environment
}
pub fn file_system(&self) -> Arc<dyn ExecutorFileSystem> {
self.environment.get_filesystem()
}
}
impl EnvironmentManager {
+6 -28
View File
@@ -11,7 +11,6 @@ use std::process::ExitStatus;
use tokio::fs::create_dir_all;
use tokio::process::Child;
#[cfg(target_os = "macos")]
async fn spawn_command_under_sandbox(
command: Vec<String>,
command_cwd: AbsolutePathBuf,
@@ -27,6 +26,12 @@ async fn spawn_command_under_sandbox(
use codex_protocol::config_types::WindowsSandboxLevel;
use std::process::Stdio;
#[cfg(target_os = "linux")]
let codex_linux_sandbox_exe = Some(
core_test_support::find_codex_linux_sandbox_exe()
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err))?,
);
#[cfg(target_os = "macos")]
let codex_linux_sandbox_exe = None;
let exec_request = build_exec_request(
ExecParams {
@@ -86,33 +91,6 @@ async fn spawn_command_under_sandbox(
child.kill_on_drop(true).spawn()
}
#[cfg(target_os = "linux")]
async fn spawn_command_under_sandbox(
command: Vec<String>,
command_cwd: AbsolutePathBuf,
permission_profile: &PermissionProfile,
sandbox_cwd: &AbsolutePathBuf,
stdio_policy: StdioPolicy,
env: HashMap<String, String>,
) -> std::io::Result<Child> {
use codex_core::spawn_command_under_linux_sandbox;
let codex_linux_sandbox_exe = core_test_support::find_codex_linux_sandbox_exe()
.map_err(|err| io::Error::new(io::ErrorKind::NotFound, err))?;
spawn_command_under_linux_sandbox(
codex_linux_sandbox_exe,
command,
command_cwd,
permission_profile,
sandbox_cwd,
/*use_legacy_landlock*/ false,
stdio_policy,
/*network*/ None,
env,
)
.await
}
#[cfg(target_os = "linux")]
/// Determines whether Linux sandbox tests can run on this host.
///
+1 -13
View File
@@ -395,10 +395,6 @@ pub struct FeedbackUploadOptions<'a> {
}
impl FeedbackSnapshot {
pub(crate) fn as_bytes(&self) -> &[u8] {
&self.bytes
}
pub fn feedback_diagnostics(&self) -> &FeedbackDiagnostics {
&self.feedback_diagnostics
}
@@ -416,14 +412,6 @@ impl FeedbackSnapshot {
self.feedback_diagnostics.attachment_text()
}
pub fn save_to_temp_file(&self) -> io::Result<PathBuf> {
let dir = std::env::temp_dir();
let filename = format!("codex-feedback-{}.log", self.thread_id);
let path = dir.join(filename);
fs::write(&path, self.as_bytes())?;
Ok(path)
}
/// Upload feedback to Sentry with optional attachments.
pub fn upload_feedback(&self, options: FeedbackUploadOptions<'_>) -> Result<()> {
use std::str::FromStr;
@@ -728,7 +716,7 @@ mod tests {
}
let snap = fb.snapshot(/*session_id*/ None);
// Capacity 8: after writing 10 bytes, we should keep the last 8.
pretty_assertions::assert_eq!(std::str::from_utf8(snap.as_bytes()).unwrap(), "cdefghij");
pretty_assertions::assert_eq!(std::str::from_utf8(&snap.bytes).unwrap(), "cdefghij");
}
#[test]
@@ -21,7 +21,6 @@ codex-utils-cargo-bin = { workspace = true }
rmcp = { workspace = true }
os_info = { workspace = true }
pretty_assertions = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
tokio = { workspace = true, features = [
"io-std",
-10
View File
@@ -12,13 +12,3 @@ pub use mock_model_server::create_mock_responses_server;
pub use responses::create_apply_patch_sse_response;
pub use responses::create_final_assistant_message_sse_response;
pub use responses::create_shell_command_sse_response;
use rmcp::model::JsonRpcResponse;
use serde::de::DeserializeOwned;
pub fn to_response<T: DeserializeOwned>(
response: JsonRpcResponse<serde_json::Value>,
) -> anyhow::Result<T> {
let value = serde_json::to_value(response.result)?;
let codex_response = serde_json::from_value(value)?;
Ok(codex_response)
}
-10
View File
@@ -361,16 +361,6 @@ pub enum ElicitationRequest {
},
}
impl ElicitationRequest {
pub fn message(&self) -> &str {
match self {
Self::Form { message, .. }
| Self::OpenAiForm { message, .. }
| Self::Url { message, .. } => message,
}
}
}
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, JsonSchema, TS)]
pub struct ElicitationRequestEvent {
/// Turn ID that this elicitation belongs to, when known.
-11
View File
@@ -630,17 +630,6 @@ fn serialize_hook_prompt_fragment(text: &str, hook_run_id: &str) -> Option<Strin
.ok()
}
impl AgentMessageItem {
pub fn new(content: &[AgentMessageContent]) -> Self {
Self {
id: new_item_id(),
content: content.to_vec(),
phase: None,
memory_citation: None,
}
}
}
impl TurnItem {
pub fn id(&self) -> String {
match self {
-16
View File
@@ -106,15 +106,6 @@ impl FileSystemPermissions {
}
}
pub fn explicit_path_entries(
&self,
) -> impl Iterator<Item = (&AbsolutePathBuf, FileSystemAccessMode)> {
self.entries.iter().filter_map(|entry| match &entry.path {
FileSystemPath::Path { path } => Some((path, entry.access)),
FileSystemPath::GlobPattern { .. } | FileSystemPath::Special { .. } => None,
})
}
pub fn legacy_read_write_roots(&self) -> Option<LegacyReadWriteRoots> {
self.as_legacy_permissions()
}
@@ -1966,13 +1957,6 @@ impl FunctionCallOutputPayload {
}
}
pub fn text_content_mut(&mut self) -> Option<&mut String> {
match &mut self.body {
FunctionCallOutputBody::Text(content) => Some(content),
FunctionCallOutputBody::ContentItems(_) => None,
}
}
pub fn content_items(&self) -> Option<&[FunctionCallOutputContentItem]> {
match &self.body {
FunctionCallOutputBody::Text(_) => None,
-74
View File
@@ -27,77 +27,3 @@ fn formatter() -> &'static DecimalFormatter {
pub fn format_with_separators(n: i64) -> String {
formatter().format(&Decimal::from(n)).to_string()
}
fn format_with_separators_with_formatter(n: i64, formatter: &DecimalFormatter) -> String {
formatter.format(&Decimal::from(n)).to_string()
}
fn format_si_suffix_with_formatter(n: i64, formatter: &DecimalFormatter) -> String {
let n = n.max(0);
if n < 1000 {
return formatter.format(&Decimal::from(n)).to_string();
}
// Format `n / scale` with the requested number of fractional digits.
let format_scaled = |n: i64, scale: i64, frac_digits: u32| -> String {
let value = n as f64 / scale as f64;
let scaled: i64 = (value * 10f64.powi(frac_digits as i32)).round() as i64;
let mut dec = Decimal::from(scaled);
dec.multiply_pow10(-(frac_digits as i16));
formatter.format(&dec).to_string()
};
const UNITS: [(i64, &str); 3] = [(1_000, "K"), (1_000_000, "M"), (1_000_000_000, "G")];
let f = n as f64;
for &(scale, suffix) in &UNITS {
if (100.0 * f / scale as f64).round() < 1000.0 {
return format!("{}{}", format_scaled(n, scale, 2), suffix);
} else if (10.0 * f / scale as f64).round() < 1000.0 {
return format!("{}{}", format_scaled(n, scale, 1), suffix);
} else if (f / scale as f64).round() < 1000.0 {
return format!("{}{}", format_scaled(n, scale, 0), suffix);
}
}
// Above 1000G, keep whole‑G precision.
format!(
"{}G",
format_with_separators_with_formatter(((n as f64) / 1e9).round() as i64, formatter)
)
}
/// Format token counts to 3 significant figures, using base-10 SI suffixes.
///
/// Examples (en-US):
/// - 999 -> "999"
/// - 1200 -> "1.20K"
/// - 123456789 -> "123M"
pub fn format_si_suffix(n: i64) -> String {
format_si_suffix_with_formatter(n, formatter())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn kmg() {
let formatter = make_en_us_formatter();
let fmt = |n: i64| format_si_suffix_with_formatter(n, &formatter);
assert_eq!(fmt(0), "0");
assert_eq!(fmt(999), "999");
assert_eq!(fmt(1_000), "1.00K");
assert_eq!(fmt(1_200), "1.20K");
assert_eq!(fmt(10_000), "10.0K");
assert_eq!(fmt(100_000), "100K");
assert_eq!(fmt(999_500), "1.00M");
assert_eq!(fmt(1_000_000), "1.00M");
assert_eq!(fmt(1_234_000), "1.23M");
assert_eq!(fmt(12_345_678), "12.3M");
assert_eq!(fmt(999_950_000), "1.00G");
assert_eq!(fmt(1_000_000_000), "1.00G");
assert_eq!(fmt(1_234_000_000), "1.23G");
// Above 1000G we keep whole‑G precision (no higher unit supported here).
assert_eq!(fmt(1_234_000_000_000), "1,234G");
}
}
-5
View File
@@ -37,11 +37,6 @@ pub fn is_protected_metadata_name(name: &OsStr) -> bool {
.any(|metadata_name| name == OsStr::new(metadata_name))
}
pub fn is_protected_metadata_directory_name(name: &OsStr) -> bool {
name == OsStr::new(PROTECTED_METADATA_AGENTS_PATH_NAME)
|| name == OsStr::new(PROTECTED_METADATA_CODEX_PATH_NAME)
}
/// Returns the protected workspace metadata name when an agent write to `path`
/// should be blocked before execution.
pub fn forbidden_agent_metadata_write(
-20
View File
@@ -501,22 +501,6 @@ where
self.previous_buffer_mut().reset();
}
/// Clear terminal scrollback (if supported) and force a full redraw.
pub fn clear_scrollback(&mut self) -> io::Result<()> {
if self.viewport_area.is_empty() {
return Ok(());
}
let home = Position { x: 0, y: 0 };
// Use an explicit cursor-home around scrollback purge for terminals that
// are sensitive to inline viewport cursor placement (e.g. Terminal.app).
self.set_cursor_position(home)?;
queue!(self.backend, Clear(crossterm::terminal::ClearType::Purge))?;
self.set_cursor_position(home)?;
std::io::Write::flush(&mut self.backend)?;
self.previous_buffer_mut().reset();
Ok(())
}
/// Clear the entire visible screen (not just the viewport) and force a full redraw.
pub fn clear_visible_screen(&mut self) -> io::Result<()> {
let home = Position { x: 0, y: 0 };
@@ -551,10 +535,6 @@ where
Ok(())
}
pub fn visible_history_rows(&self) -> u16 {
self.visible_history_rows
}
pub(crate) fn note_history_rows_inserted(&mut self, inserted_rows: u16) {
self.visible_history_rows = self
.visible_history_rows
+1 -1
View File
@@ -35,7 +35,7 @@ impl HistoryCell for UpdateAvailableHistoryCell {
let content = text![
line![
padded_emoji("✨").bold().cyan(),
"✨\u{200A}".bold().cyan(),
"Update available!".bold().cyan(),
" ",
format!("{CODEX_CLI_VERSION} -> {}", self.latest_version).bold(),
-7
View File
@@ -71,13 +71,6 @@ fn with_border_internal(
out
}
/// Return the emoji followed by a hair space (U+200A).
/// Using only the hair space avoids excessive padding after the emoji while
/// still providing a small visual gap across terminals.
pub(crate) fn padded_emoji(emoji: &str) -> String {
format!("{emoji}\u{200A}")
}
#[derive(Debug)]
struct TooltipHistoryCell {
tip: String,
-9
View File
@@ -35,10 +35,6 @@ impl RowBuilder {
}
}
pub fn width(&self) -> usize {
self.target_width
}
pub fn set_width(&mut self, width: usize) {
self.target_width = width.max(1);
// Rewrap everything we have (simple approach for Step 1).
@@ -76,11 +72,6 @@ impl RowBuilder {
}
}
/// Mark the end of the current logical line (equivalent to pushing a '\n').
pub fn end_line(&mut self) {
self.flush_current_line(/*explicit_break*/ true);
}
/// Return a snapshot of produced rows (non-draining).
pub fn rows(&self) -> &[Row] {
&self.rows
+1 -2
View File
@@ -1,6 +1,5 @@
#![cfg(not(debug_assertions))]
use crate::history_cell::padded_emoji;
use crate::key_hint;
use crate::legacy_core::config::Config;
use crate::render::Insets;
@@ -192,7 +191,7 @@ impl WidgetRef for &UpdatePromptScreen {
column.push("");
column.push(Line::from(vec![
padded_emoji(" ✨").bold().cyan(),
" ✨\u{200A}".bold().cyan(),
"Update available!".bold(),
" ".into(),
format!(
-55
View File
@@ -82,17 +82,6 @@ impl CliConfigOverrides {
})
.collect()
}
/// Apply all parsed overrides onto `target`. Intermediate objects will be
/// created as necessary. Values located at the destination path will be
/// replaced.
pub fn apply_on_value(&self, target: &mut Value) -> Result<(), String> {
let overrides = self.parse_overrides()?;
for (path, value) in overrides {
apply_single_override(target, &path, value);
}
Ok(())
}
}
fn canonicalize_override_key(key: &str) -> String {
@@ -103,50 +92,6 @@ fn canonicalize_override_key(key: &str) -> String {
}
}
/// Apply a single override onto `root`, creating intermediate objects as
/// necessary.
fn apply_single_override(root: &mut Value, path: &str, value: Value) {
use toml::value::Table;
let parts: Vec<&str> = path.split('.').collect();
let mut current = root;
for (i, part) in parts.iter().enumerate() {
let is_last = i == parts.len() - 1;
if is_last {
match current {
Value::Table(tbl) => {
tbl.insert((*part).to_string(), value);
}
_ => {
let mut tbl = Table::new();
tbl.insert((*part).to_string(), value);
*current = Value::Table(tbl);
}
}
return;
}
// Traverse or create intermediate table.
match current {
Value::Table(tbl) => {
current = tbl
.entry((*part).to_string())
.or_insert_with(|| Value::Table(Table::new()));
}
_ => {
*current = Value::Table(Table::new());
if let Value::Table(tbl) = current {
current = tbl
.entry((*part).to_string())
.or_insert_with(|| Value::Table(Table::new()));
}
}
}
}
}
fn parse_toml_value(raw: &str) -> Result<Value, toml::de::Error> {
let wrapped = format!("_x_ = {raw}");
let table: toml::Table = toml::from_str(&wrapped)?;
@@ -8,8 +8,6 @@ license.workspace = true
workspace = true
[dependencies]
codex-core = { workspace = true }
codex-model-provider-info = { workspace = true }
codex-protocol = { workspace = true }
codex-utils-absolute-path = { workspace = true }
@@ -1,44 +0,0 @@
use codex_core::config::Config;
use codex_model_provider_info::WireApi;
use crate::sandbox_summary::summarize_sandbox_policy;
/// Build a list of key/value pairs summarizing the effective configuration.
pub fn create_config_summary_entries(config: &Config, model: &str) -> Vec<(&'static str, String)> {
let mut entries = vec![
("workdir", config.cwd.display().to_string()),
("model", model.to_string()),
("provider", config.model_provider_id.clone()),
(
"approval",
config.permissions.approval_policy.value().to_string(),
),
(
"sandbox",
summarize_sandbox_policy(
&config
.permissions
.legacy_sandbox_policy(config.cwd.as_path()),
),
),
];
if config.model_provider.wire_api == WireApi::Responses {
let reasoning_effort = config
.model_reasoning_effort
.as_ref()
.map(std::string::ToString::to_string);
entries.push((
"reasoning effort",
reasoning_effort.unwrap_or_else(|| "none".to_string()),
));
entries.push((
"reasoning summaries",
config
.model_reasoning_summary
.map(|summary| summary.to_string())
.unwrap_or_else(|| "none".to_string()),
));
}
entries
}
@@ -1,6 +1,4 @@
mod config_summary;
mod sandbox_summary;
pub use config_summary::create_config_summary_entries;
pub use sandbox_summary::summarize_permission_profile;
pub use sandbox_summary::summarize_sandbox_policy;