Remove unused functions and methods

This commit is contained in:
Charlie Marsh
2026-06-04 07:35:33 -04:00
parent 80b65e9945
commit 83b04444ca
82 changed files with 63 additions and 1781 deletions
-60
View File
@@ -9,7 +9,6 @@ use base64::engine::general_purpose::URL_SAFE_NO_PAD;
use chrono::SecondsFormat;
use chrono::Utc;
use codex_protocol::auth::PlanType as AuthPlanType;
use codex_protocol::protocol::SessionSource;
use crypto_box::SecretKey as Curve25519SecretKey;
use ed25519_dalek::Signer as _;
use ed25519_dalek::SigningKey;
@@ -275,42 +274,11 @@ pub fn generate_agent_key_material() -> Result<GeneratedAgentKeyMaterial> {
})
}
pub fn public_key_ssh_from_private_key_pkcs8_base64(
private_key_pkcs8_base64: &str,
) -> Result<String> {
let signing_key = signing_key_from_private_key_pkcs8_base64(private_key_pkcs8_base64)?;
Ok(encode_ssh_ed25519_public_key(&signing_key.verifying_key()))
}
pub fn verifying_key_from_private_key_pkcs8_base64(
private_key_pkcs8_base64: &str,
) -> Result<VerifyingKey> {
let signing_key = signing_key_from_private_key_pkcs8_base64(private_key_pkcs8_base64)?;
Ok(signing_key.verifying_key())
}
pub fn curve25519_secret_key_from_private_key_pkcs8_base64(
private_key_pkcs8_base64: &str,
) -> Result<Curve25519SecretKey> {
let signing_key = signing_key_from_private_key_pkcs8_base64(private_key_pkcs8_base64)?;
Ok(curve25519_secret_key_from_signing_key(&signing_key))
}
pub fn agent_registration_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/v1/agent/register")
}
pub fn agent_task_registration_url(chatgpt_base_url: &str, agent_runtime_id: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/v1/agent/{agent_runtime_id}/task/register")
}
pub fn agent_identity_biscuit_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
format!("{trimmed}/authenticate_app_v2")
}
pub fn agent_identity_jwks_url(chatgpt_base_url: &str) -> String {
let trimmed = chatgpt_base_url.trim_end_matches('/');
if trimmed.contains("/backend-api") {
@@ -320,34 +288,6 @@ pub fn agent_identity_jwks_url(chatgpt_base_url: &str) -> String {
}
}
pub fn agent_identity_request_id() -> Result<String> {
let mut request_id_bytes = [0u8; 16];
OsRng
.try_fill_bytes(&mut request_id_bytes)
.context("failed to generate agent identity request id")?;
Ok(format!(
"codex-agent-identity-{}",
URL_SAFE_NO_PAD.encode(request_id_bytes)
))
}
pub fn build_abom(session_source: SessionSource) -> AgentBillOfMaterials {
AgentBillOfMaterials {
agent_version: env!("CARGO_PKG_VERSION").to_string(),
agent_harness_id: match &session_source {
SessionSource::VSCode => "codex-app".to_string(),
SessionSource::Cli
| SessionSource::Exec
| SessionSource::Mcp
| SessionSource::Custom(_)
| SessionSource::Internal(_)
| SessionSource::SubAgent(_)
| SessionSource::Unknown => "codex-cli".to_string(),
},
running_location: format!("{}-{}", session_source, std::env::consts::OS),
}
}
pub fn encode_ssh_ed25519_public_key(verifying_key: &VerifyingKey) -> String {
let mut blob = Vec::with_capacity(4 + 11 + 4 + 32);
append_ssh_string(&mut blob, b"ssh-ed25519");
-44
View File
@@ -665,29 +665,6 @@ impl InProcessAppServerClient {
.map_err(|source| TypedRequestError::Deserialize { method, source })
}
/// Sends a typed client notification.
pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> {
let (response_tx, response_rx) = oneshot::channel();
self.command_tx
.send(ClientCommand::Notify {
notification,
response_tx,
})
.await
.map_err(|_| {
IoError::new(
ErrorKind::BrokenPipe,
"in-process app-server worker channel is closed",
)
})?;
response_rx.await.map_err(|_| {
IoError::new(
ErrorKind::BrokenPipe,
"in-process app-server notify channel is closed",
)
})?
}
/// Resolves a pending server request.
///
/// This should only be called with request IDs obtained from the current
@@ -840,13 +817,6 @@ impl InProcessAppServerRequestHandle {
}
impl AppServerRequestHandle {
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
match self {
Self::InProcess(handle) => handle.request(request).await,
Self::Remote(handle) => handle.request(request).await,
}
}
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
where
T: DeserializeOwned,
@@ -859,13 +829,6 @@ impl AppServerRequestHandle {
}
impl AppServerClient {
pub async fn request(&self, request: ClientRequest) -> IoResult<RequestResult> {
match self {
Self::InProcess(client) => client.request(request).await,
Self::Remote(client) => client.request(request).await,
}
}
pub async fn request_typed<T>(&self, request: ClientRequest) -> Result<T, TypedRequestError>
where
T: DeserializeOwned,
@@ -876,13 +839,6 @@ impl AppServerClient {
}
}
pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> {
match self {
Self::InProcess(client) => client.notify(notification).await,
Self::Remote(client) => client.notify(notification).await,
}
}
pub async fn resolve_server_request(
&self,
request_id: RequestId,
-22
View File
@@ -524,28 +524,6 @@ impl RemoteAppServerClient {
.map_err(|source| TypedRequestError::Deserialize { method, source })
}
pub async fn notify(&self, notification: ClientNotification) -> IoResult<()> {
let (response_tx, response_rx) = oneshot::channel();
self.command_tx
.send(RemoteClientCommand::Notify {
notification,
response_tx,
})
.await
.map_err(|_| {
IoError::new(
ErrorKind::BrokenPipe,
"remote app-server worker channel is closed",
)
})?;
response_rx.await.map_err(|_| {
IoError::new(
ErrorKind::BrokenPipe,
"remote app-server notify channel is closed",
)
})?
}
pub async fn resolve_server_request(
&self,
request_id: RequestId,
-7
View File
@@ -197,13 +197,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()?
@@ -24,7 +24,6 @@ use crate::protocol::v2::PatchChangeKind;
use crate::protocol::v2::ThreadItem;
use codex_protocol::ThreadId;
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;
@@ -63,28 +62,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(),
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 {
ThreadItem::CommandExecution {
id: payload.call_id.clone(),
@@ -227,15 +227,6 @@ pub enum ForcedChatgptWorkspaceIds {
Multiple(Vec<String>),
}
impl ForcedChatgptWorkspaceIds {
pub fn into_vec(self) -> Vec<String> {
match self {
Self::Single(value) => vec![value],
Self::Multiple(values) => values,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, JsonSchema, TS, ExperimentalApi)]
#[serde(rename_all = "snake_case")]
#[ts(export_to = "v2/")]
@@ -336,13 +336,6 @@ pub struct ActivePermissionProfile {
}
impl ActivePermissionProfile {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
extends: None,
}
}
pub fn read_only() -> Self {
CoreActivePermissionProfile::read_only().into()
}
@@ -837,13 +837,6 @@ pub enum ThreadMemoryMode {
}
impl ThreadMemoryMode {
pub fn as_str(self) -> &'static str {
match self {
Self::Enabled => "enabled",
Self::Disabled => "disabled",
}
}
pub fn to_core(self) -> codex_protocol::protocol::ThreadMemoryMode {
match self {
Self::Enabled => codex_protocol::protocol::ThreadMemoryMode::Enabled,
@@ -240,10 +240,6 @@ impl TextElement {
}
}
pub fn set_placeholder(&mut self, placeholder: Option<String>) {
self.placeholder = placeholder;
}
pub fn placeholder(&self) -> Option<&str> {
self.placeholder.as_deref()
}
-21
View File
@@ -283,27 +283,6 @@ impl InProcessClientHandle {
self.client.notify(notification)
}
/// Resolves a pending [`ServerRequest`](InProcessServerEvent::ServerRequest).
///
/// This should be used only with request IDs received from the current
/// runtime event stream; sending arbitrary IDs has no effect on app-server
/// state and can mask a stuck approval flow in the caller.
pub fn respond_to_server_request(&self, request_id: RequestId, result: Result) -> IoResult<()> {
self.client.respond_to_server_request(request_id, result)
}
/// Rejects a pending [`ServerRequest`](InProcessServerEvent::ServerRequest).
///
/// Use this when the embedder cannot satisfy a server request; leaving
/// requests unanswered can stall turn progress.
pub fn fail_server_request(
&self,
request_id: RequestId,
error: JSONRPCErrorError,
) -> IoResult<()> {
self.client.fail_server_request(request_id, error)
}
/// Receives the next server event from the in-process runtime.
///
/// Returns `None` when the runtime task exits and no more events are
-21
View File
@@ -372,27 +372,6 @@ fn log_format_from_env() -> LogFormat {
LogFormat::from_env_value(value.as_deref())
}
pub async fn run_main(
arg0_paths: Arg0DispatchPaths,
cli_config_overrides: CliConfigOverrides,
loader_overrides: LoaderOverrides,
strict_config: bool,
default_analytics_enabled: bool,
) -> IoResult<()> {
run_main_with_transport_options(
arg0_paths,
cli_config_overrides,
loader_overrides,
strict_config,
default_analytics_enabled,
AppServerTransport::Stdio,
SessionSource::VSCode,
AppServerWebsocketAuthSettings::default(),
AppServerRuntimeOptions::default(),
)
.await
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PluginStartupTasks {
Start,
@@ -69,11 +69,6 @@ impl ChatGptAuthFixture {
self.last_refresh = Some(last_refresh);
self
}
pub fn claims(mut self, claims: ChatGptIdTokenClaims) -> Self {
self.claims = claims;
self
}
}
#[derive(Debug, Clone, Default)]
@@ -99,11 +94,6 @@ impl ChatGptIdTokenClaims {
self
}
pub fn chatgpt_user_id(mut self, chatgpt_user_id: impl Into<String>) -> Self {
self.chatgpt_user_id = Some(chatgpt_user_id.into());
self
}
pub fn chatgpt_account_id(mut self, chatgpt_account_id: impl Into<String>) -> Self {
self.chatgpt_account_id = Some(chatgpt_account_id.into());
self
@@ -24,7 +24,6 @@ use codex_app_server_protocol::ConfigBatchWriteParams;
use codex_app_server_protocol::ConfigReadParams;
use codex_app_server_protocol::ConfigValueWriteParams;
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;
@@ -64,9 +63,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;
@@ -410,15 +407,6 @@ impl TestAppServer {
self.send_request("account/login/start", params).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,
@@ -887,24 +875,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,
-4
View File
@@ -93,10 +93,6 @@ impl AwsAuthContext {
&self.region
}
pub fn service(&self) -> &str {
&self.service
}
pub async fn sign(&self, request: AwsRequestToSign) -> Result<AwsSignedRequest, AwsAuthError> {
self.sign_at(request, SystemTime::now()).await
}
-35
View File
@@ -1,4 +1,3 @@
use crate::types::AccountsCheckResponse;
use crate::types::CodeTaskDetailsResponse;
use crate::types::ConfigBundleResponse;
use crate::types::PaginatedListTaskListItem;
@@ -189,21 +188,6 @@ impl Client {
self
}
pub fn with_chatgpt_account_id(mut self, account_id: impl Into<String>) -> Self {
self.chatgpt_account_id = Some(account_id.into());
self
}
pub fn with_fedramp_routing_header(mut self) -> Self {
self.chatgpt_account_is_fedramp = true;
self
}
pub fn with_path_style(mut self, style: PathStyle) -> Self {
self.path_style = style;
self
}
fn headers(&self) -> HeaderMap {
let mut h = HeaderMap::new();
if let Some(ua) = &self.user_agent {
@@ -283,15 +267,6 @@ impl Client {
}
}
pub async fn get_rate_limits(&self) -> Result<RateLimitSnapshot> {
let snapshots = self.get_rate_limits_many().await?;
let preferred = snapshots
.iter()
.find(|snapshot| snapshot.limit_id.as_deref() == Some("codex"))
.cloned();
Ok(preferred.unwrap_or_else(|| snapshots[0].clone()))
}
pub async fn get_rate_limits_many(&self) -> Result<Vec<RateLimitSnapshot>> {
let url = match self.path_style {
PathStyle::CodexApi => format!("{}/api/codex/usage", self.base_url),
@@ -303,16 +278,6 @@ impl Client {
Ok(Self::rate_limit_snapshots_from_payload(payload))
}
pub async fn get_accounts_check(&self) -> Result<AccountsCheckResponse> {
let url = match self.path_style {
PathStyle::CodexApi => format!("{}/api/codex/accounts/check", self.base_url),
PathStyle::ChatGptApi => format!("{}/wham/accounts/check", self.base_url),
};
let req = self.http.get(&url).headers(self.headers());
let (body, ct) = self.exec_request(req, "GET", &url).await?;
self.decode_json(&url, &ct, &body)
}
pub async fn send_add_credits_nudge_email(
&self,
credit_type: AddCreditsNudgeCreditType,
-22
View File
@@ -49,28 +49,6 @@ async fn connector_auth(config: &Config) -> anyhow::Result<CodexAuth> {
Ok(auth)
}
pub async fn list_connectors(config: &Config) -> anyhow::Result<Vec<AppInfo>> {
if !apps_enabled(config).await {
return Ok(Vec::new());
}
let (connectors_result, accessible_result) = tokio::join!(
list_all_connectors(config),
list_accessible_connectors_from_mcp_tools(config),
);
let connectors = connectors_result?;
let accessible = accessible_result?;
Ok(with_app_enabled_state(
merge_connectors_with_accessible(
connectors, accessible, /*all_connectors_loaded*/ true,
),
config,
))
}
pub async fn list_all_connectors(config: &Config) -> anyhow::Result<Vec<AppInfo>> {
list_all_connectors_with_options(config, /*force_refetch*/ false).await
}
pub async fn list_cached_all_connectors(config: &Config) -> Option<Vec<AppInfo>> {
if !apps_enabled(config).await {
return Some(Vec::new());
-5
View File
@@ -43,11 +43,6 @@ impl HttpClient {
self
}
pub fn with_chatgpt_account_id(mut self, account_id: impl Into<String>) -> Self {
self.backend = self.backend.clone().with_chatgpt_account_id(account_id);
self
}
fn tasks_api(&self) -> api::Tasks<'_> {
api::Tasks::new(self)
}
@@ -6,7 +6,6 @@ use crate::images::ImageGenerationRequest;
use crate::images::ImageResponse;
use crate::provider::Provider;
use codex_client::HttpTransport;
use codex_client::RequestTelemetry;
use http::HeaderMap;
use http::Method;
use serde::Serialize;
@@ -24,12 +23,6 @@ impl<T: HttpTransport> ImagesClient<T> {
}
}
pub fn with_telemetry(self, request: Option<Arc<dyn RequestTelemetry>>) -> Self {
Self {
session: self.session.with_request_telemetry(request),
}
}
pub async fn generate(
&self,
request: &ImageGenerationRequest,
@@ -7,7 +7,6 @@ use crate::provider::Provider;
use bytes::Bytes;
use codex_client::HttpTransport;
use codex_client::RequestBody;
use codex_client::RequestTelemetry;
use http::HeaderMap;
use http::HeaderValue;
use http::Method;
@@ -51,12 +50,6 @@ impl<T: HttpTransport> RealtimeCallClient<T> {
}
}
pub fn with_telemetry(self, request: Option<Arc<dyn RequestTelemetry>>) -> Self {
Self {
session: self.session.with_request_telemetry(request),
}
}
fn path() -> &'static str {
"realtime/calls"
}
@@ -5,7 +5,6 @@ use crate::provider::Provider;
use crate::search::SearchRequest;
use crate::search::SearchResponse;
use codex_client::HttpTransport;
use codex_client::RequestTelemetry;
use http::HeaderMap;
use http::Method;
use serde_json::to_value;
@@ -22,12 +21,6 @@ impl<T: HttpTransport> SearchClient<T> {
}
}
pub fn with_telemetry(self, request: Option<Arc<dyn RequestTelemetry>>) -> Self {
Self {
session: self.session.with_request_telemetry(request),
}
}
fn path() -> &'static str {
"alpha/search"
}
@@ -8,7 +8,6 @@ use reqwest::IntoUrl;
use reqwest::Method;
use reqwest::Response;
use serde::Serialize;
use std::fmt::Display;
use std::time::Duration;
use tracing::Span;
use tracing_opentelemetry::OpenTelemetrySpanExt;
@@ -85,13 +84,6 @@ impl CodexRequestBuilder {
self.map(|builder| builder.header(key, value))
}
pub fn bearer_auth<T>(self, token: T) -> Self
where
T: Display,
{
self.map(|builder| builder.bearer_auth(token))
}
pub fn timeout(self, timeout: Duration) -> Self {
self.map(|builder| builder.timeout(timeout))
}
-5
View File
@@ -67,11 +67,6 @@ impl Request {
self
}
pub fn with_raw_body(mut self, body: impl Into<Bytes>) -> Self {
self.body = Some(RequestBody::Raw(body.into()));
self
}
pub fn with_compression(mut self, compression: RequestCompression) -> Self {
self.compression = compression;
self
@@ -242,10 +242,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
@@ -291,10 +287,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
@@ -74,10 +74,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
@@ -148,18 +148,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)]
-44
View File
@@ -847,29 +847,6 @@ impl PluginsManager {
self.install_resolved_plugin(resolved).await
}
pub async fn install_plugin_with_remote_sync(
&self,
config: &PluginsConfigInput,
auth: Option<&CodexAuth>,
request: PluginInstallRequest,
) -> Result<PluginInstallOutcome, PluginInstallError> {
let resolved = find_installable_marketplace_plugin(
&request.marketplace_path,
&request.plugin_name,
self.restriction_product,
)?;
let plugin_id = resolved.plugin_id.as_key();
// This only forwards the backend mutation before the local install flow.
crate::remote_legacy::enable_remote_plugin(
&remote_plugin_service_config(config),
auth,
&plugin_id,
)
.await
.map_err(PluginInstallError::from)?;
self.install_resolved_plugin(resolved).await
}
async fn install_resolved_plugin(
&self,
resolved: ResolvedMarketplacePlugin,
@@ -935,27 +912,6 @@ impl PluginsManager {
self.uninstall_plugin_id(plugin_id).await
}
pub async fn uninstall_plugin_with_remote_sync(
&self,
config: &PluginsConfigInput,
auth: Option<&CodexAuth>,
plugin_id: String,
) -> Result<(), PluginUninstallError> {
// TODO: Remove this legacy remote-sync path once remote plugins have
// their own manager and installed-state API.
let plugin_id = PluginId::parse(&plugin_id)?;
let plugin_key = plugin_id.as_key();
// This only forwards the backend mutation before the local uninstall flow.
crate::remote_legacy::uninstall_remote_plugin(
&remote_plugin_service_config(config),
auth,
&plugin_key,
)
.await
.map_err(PluginUninstallError::from)?;
self.uninstall_plugin_id(plugin_id).await
}
async fn uninstall_plugin_id(&self, plugin_id: PluginId) -> Result<(), PluginUninstallError> {
let plugin_telemetry = if self.store.active_plugin_root(&plugin_id).is_some() {
Some(installed_plugin_telemetry_metadata(self.codex_home.as_path(), &plugin_id).await)
@@ -194,24 +194,6 @@ pub async fn fetch_remote_featured_plugin_ids(
})
}
pub async fn enable_remote_plugin(
config: &RemotePluginServiceConfig,
auth: Option<&CodexAuth>,
plugin_id: &str,
) -> Result<(), RemotePluginMutationError> {
post_remote_plugin_mutation(config, auth, plugin_id, "enable").await?;
Ok(())
}
pub async fn uninstall_remote_plugin(
config: &RemotePluginServiceConfig,
auth: Option<&CodexAuth>,
plugin_id: &str,
) -> Result<(), RemotePluginMutationError> {
post_remote_plugin_mutation(config, auth, plugin_id, "uninstall").await?;
Ok(())
}
fn ensure_codex_backend_auth(
auth: Option<&CodexAuth>,
) -> Result<&CodexAuth, RemotePluginMutationError> {
-6
View File
@@ -114,12 +114,6 @@ impl SkillLoadOutcome {
.collect()
}
pub fn skills_with_enabled(&self) -> impl Iterator<Item = (&SkillMetadata, bool)> {
self.skills
.iter()
.map(|skill| (skill, self.is_skill_enabled(skill)))
}
pub(crate) fn file_system_for_skill(
&self,
skill: &SkillMetadata,
-105
View File
@@ -7,7 +7,6 @@ use std::path::PathBuf;
use std::time::Duration;
use codex_login::CodexAuth;
use codex_login::default_client::build_reqwest_client;
const REMOTE_SKILLS_API_TIMEOUT: Duration = Duration::from_secs(30);
@@ -86,110 +85,6 @@ struct RemoteSkill {
description: String,
}
pub async fn list_remote_skills(
chatgpt_base_url: String,
auth: Option<&CodexAuth>,
scope: RemoteSkillScope,
product_surface: RemoteSkillProductSurface,
enabled: Option<bool>,
) -> Result<Vec<RemoteSkillSummary>> {
let base_url = chatgpt_base_url.trim_end_matches('/');
let auth = ensure_codex_backend_auth(auth)?;
let url = format!("{base_url}/hazelnuts");
let product_surface = as_query_product_surface(product_surface);
let mut query_params = vec![("product_surface", product_surface)];
if let Some(scope) = as_query_scope(scope) {
query_params.push(("scope", scope));
}
if let Some(enabled) = enabled {
let enabled = if enabled { "true" } else { "false" };
query_params.push(("enabled", enabled));
}
let client = build_reqwest_client();
let request = client
.get(&url)
.timeout(REMOTE_SKILLS_API_TIMEOUT)
.query(&query_params)
.headers(codex_model_provider::auth_provider_from_auth(auth).to_auth_headers());
let response = request
.send()
.await
.with_context(|| format!("Failed to send request to {url}"))?;
let status = response.status();
let body = response.text().await.unwrap_or_default();
if !status.is_success() {
anyhow::bail!("Request failed with status {status} from {url}: {body}");
}
let parsed: RemoteSkillsResponse =
serde_json::from_str(&body).context("Failed to parse skills response")?;
Ok(parsed
.skills
.into_iter()
.map(|skill| RemoteSkillSummary {
id: skill.id,
name: skill.name,
description: skill.description,
})
.collect())
}
pub async fn export_remote_skill(
chatgpt_base_url: String,
codex_home: PathBuf,
auth: Option<&CodexAuth>,
skill_id: &str,
) -> Result<RemoteSkillDownloadResult> {
let auth = ensure_codex_backend_auth(auth)?;
let client = build_reqwest_client();
let base_url = chatgpt_base_url.trim_end_matches('/');
let url = format!("{base_url}/hazelnuts/{skill_id}/export");
let request = client
.get(&url)
.timeout(REMOTE_SKILLS_API_TIMEOUT)
.headers(codex_model_provider::auth_provider_from_auth(auth).to_auth_headers());
let response = request
.send()
.await
.with_context(|| format!("Failed to send download request to {url}"))?;
let status = response.status();
let body = response.bytes().await.context("Failed to read download")?;
if !status.is_success() {
let body_text = String::from_utf8_lossy(&body);
anyhow::bail!("Download failed with status {status} from {url}: {body_text}");
}
if !is_zip_payload(&body) {
anyhow::bail!("Downloaded remote skill payload is not a zip archive");
}
let output_dir = codex_home.join("skills").join(skill_id);
tokio::fs::create_dir_all(&output_dir)
.await
.context("Failed to create downloaded skills directory")?;
let zip_bytes = body.to_vec();
let output_dir_clone = output_dir.clone();
let prefix_candidates = vec![skill_id.to_string()];
tokio::task::spawn_blocking(move || {
extract_zip_to_dir(zip_bytes, &output_dir_clone, &prefix_candidates)
})
.await
.context("Zip extraction task failed")??;
Ok(RemoteSkillDownloadResult {
id: skill_id.to_string(),
path: output_dir,
})
}
fn safe_join(base: &Path, name: &str) -> Result<PathBuf> {
let path = Path::new(name);
for component in path.components() {
-6
View File
@@ -30,7 +30,6 @@ use codex_protocol::protocol::SandboxPolicy;
use codex_protocol::protocol::SessionConfiguredEvent;
use codex_protocol::protocol::SessionSource;
use codex_protocol::protocol::Submission;
use codex_protocol::protocol::ThreadMemoryMode;
use codex_protocol::protocol::ThreadSource;
use codex_protocol::protocol::TokenUsageInfo;
use codex_protocol::protocol::TurnEnvironmentSelection;
@@ -240,11 +239,6 @@ impl CodexThread {
.await
}
/// Persist whether this thread is eligible for future memory generation.
pub async fn set_thread_memory_mode(&self, mode: ThreadMemoryMode) -> anyhow::Result<()> {
self.codex.set_thread_memory_mode(mode).await
}
pub async fn steer_input(
&self,
input: Vec<UserInput>,
-41
View File
@@ -738,16 +738,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 {
@@ -813,37 +803,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(),
-63
View File
@@ -1542,24 +1542,6 @@ impl Config {
)
.await
}
/// This is a secondary way of creating [Config], which is appropriate when
/// the harness is meant to be used with a specific configuration that
/// ignores user settings. For example, the `codex exec` subcommand is
/// designed to use [AskForApproval::Never] exclusively.
///
/// Further, [ConfigOverrides] contains some options that are not supported
/// in [ConfigToml], such as `cwd`, `codex_self_exe`, `codex_linux_sandbox_exe`, and
/// `main_execve_wrapper_exe`.
pub async fn load_with_cli_overrides_and_harness_overrides(
cli_overrides: Vec<(String, TomlValue)>,
harness_overrides: ConfigOverrides,
) -> std::io::Result<Self> {
ConfigBuilder::default()
.cli_overrides(cli_overrides)
.harness_overrides(harness_overrides)
.build()
.await
}
}
pub fn resolve_profile_v2_config_path(
@@ -1572,38 +1554,6 @@ pub fn resolve_profile_v2_config_path(
)
}
/// DEPRECATED: Use [Config::load_with_cli_overrides()] instead because working
/// with [ConfigToml] directly means that [ConfigRequirements] have not been
/// applied yet, which risks failing to enforce required constraints.
pub async fn load_config_as_toml_with_cli_overrides(
codex_home: &Path,
cwd: Option<&AbsolutePathBuf>,
cli_overrides: Vec<(String, TomlValue)>,
loader_overrides: LoaderOverrides,
) -> std::io::Result<ConfigToml> {
load_config_as_toml_with_cli_and_loader_overrides(
codex_home,
cwd,
cli_overrides,
loader_overrides,
)
.await
}
/// DEPRECATED for most callers: prefer [Config::load_with_cli_overrides()] or
/// [ConfigBuilder] because working with [ConfigToml] directly means
/// [ConfigRequirements] have not been applied yet, which risks skipping
/// required constraints.
pub async fn load_config_as_toml_with_cli_and_loader_overrides(
codex_home: &Path,
cwd: Option<&AbsolutePathBuf>,
cli_overrides: Vec<(String, TomlValue)>,
loader_overrides: LoaderOverrides,
) -> std::io::Result<ConfigToml> {
load_config_as_toml_with_cli_and_load_options(codex_home, cwd, cli_overrides, loader_overrides)
.await
}
/// DEPRECATED for most callers: prefer [Config::load_with_cli_overrides()] or
/// [ConfigBuilder] because working with [ConfigToml] directly means
/// [ConfigRequirements] have not been applied yet, which risks skipping
@@ -3676,19 +3626,6 @@ impl Config {
};
}
pub fn set_windows_elevated_sandbox_enabled(&mut self, value: bool) {
self.permissions.windows_sandbox_mode = if value {
Some(WindowsSandboxModeToml::Elevated)
} else if matches!(
self.permissions.windows_sandbox_mode,
Some(WindowsSandboxModeToml::Elevated)
) {
None
} else {
self.permissions.windows_sandbox_mode
};
}
pub fn managed_network_requirements_enabled(&self) -> bool {
!matches!(
self.permissions.permission_profile(),
@@ -209,16 +209,6 @@ impl PermissionProfileSnapshot {
self.resolved_permission_profile.permission_profile()
}
/// Return the active profile id captured in this snapshot, if any.
pub fn active_permission_profile(&self) -> Option<ActivePermissionProfile> {
self.resolved_permission_profile.active_permission_profile()
}
/// Borrow profile-declared workspace roots captured in this snapshot.
pub fn profile_workspace_roots(&self) -> &[AbsolutePathBuf] {
self.resolved_permission_profile.profile_workspace_roots()
}
pub(crate) fn into_resolved_permission_profile(self) -> ResolvedPermissionProfile {
self.resolved_permission_profile
}
-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
@@ -73,22 +73,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,
-57
View File
@@ -7,8 +7,6 @@ use std::time::Duration;
use anyhow::Result;
use base64::Engine;
use codex_protocol::models::ContentItem;
use codex_protocol::models::ResponseItem;
use codex_protocol::openai_models::ModelsResponse;
use futures::SinkExt;
use futures::StreamExt;
@@ -294,14 +292,6 @@ impl ResponsesRequest {
pub fn path(&self) -> String {
self.0.url.path().to_string()
}
pub fn query_param(&self, name: &str) -> Option<String> {
self.0
.url
.query_pairs()
.find(|(k, _)| k == name)
.map(|(_, v)| v.to_string())
}
}
pub(crate) fn output_value_to_text(value: &Value) -> Option<String> {
@@ -677,17 +667,6 @@ pub fn ev_assistant_message(id: &str, text: &str) -> Value {
})
}
pub fn user_message_item(text: &str) -> ResponseItem {
ResponseItem::Message {
id: None,
role: "user".to_string(),
content: vec![ContentItem::InputText {
text: text.to_string(),
}],
phase: None,
}
}
pub fn ev_message_item_added(id: &str, text: &str) -> Value {
serde_json::json!({
"type": "response.output_item.added",
@@ -866,21 +845,6 @@ pub fn ev_custom_tool_call(call_id: &str, name: &str, input: &str) -> Value {
})
}
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.
@@ -1001,27 +965,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,
-27
View File
@@ -275,11 +275,6 @@ impl TestCodexBuilder {
self
}
pub fn with_exec_server_url(mut self, exec_server_url: impl Into<String>) -> Self {
self.exec_server_url = Some(exec_server_url.into());
self
}
pub fn with_windows_cmd_shell(self) -> Self {
if cfg!(windows) {
self.with_user_shell(get_shell_by_model_provided_path(&PathBuf::from("cmd.exe")))
@@ -631,10 +626,6 @@ impl TestCodex {
self.cwd_path().join(rel)
}
pub fn executor_environment(&self) -> &TestEnv {
&self._test_env
}
pub fn fs(&self) -> Arc<dyn ExecutorFileSystem> {
self._test_env.environment().get_filesystem()
}
@@ -814,14 +805,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?;
@@ -930,16 +913,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,
-6
View File
@@ -230,12 +230,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
-8
View File
@@ -10,17 +10,9 @@ use serde::Serialize;
pub struct ProcessId(String);
impl ProcessId {
pub fn new(value: impl Into<String>) -> Self {
Self(value.into())
}
pub fn as_str(&self) -> &str {
&self.0
}
pub fn into_inner(self) -> String {
self.0
}
}
impl Deref for ProcessId {
-25
View File
@@ -134,10 +134,6 @@ impl Policy {
Ok(())
}
pub fn set_host_executable_paths(&mut self, name: String, paths: Vec<AbsolutePathBuf>) {
self.host_executables_by_name.insert(name, paths.into());
}
pub fn merge_overlay(&self, overlay: &Policy) -> Policy {
let mut combined_rules = self.rules_by_program.clone();
for (program, rules) in overlay.rules_by_program.iter_all() {
@@ -250,21 +246,6 @@ impl Policy {
Evaluation::from_matches(matched_rules)
}
/// Returns matching rules for the given command. If no rules match and
/// `heuristics_fallback` is provided, returns a single
/// `HeuristicsRuleMatch` with the decision rendered by
/// `heuristics_fallback`.
///
/// If `heuristics_fallback.is_some()`, then the returned vector is
/// guaranteed to be non-empty.
pub fn matches_for_command(
&self,
cmd: &[String],
heuristics_fallback: HeuristicsFallback<'_>,
) -> Vec<RuleMatch> {
self.matches_for_command_with_options(cmd, heuristics_fallback, &MatchOptions::default())
}
pub fn matches_for_command_with_options(
&self,
cmd: &[String],
@@ -355,12 +336,6 @@ pub struct Evaluation {
}
impl Evaluation {
pub fn is_match(&self) -> bool {
self.matched_rules
.iter()
.any(|rule_match| !matches!(rule_match, RuleMatch::HeuristicsRuleMatch { .. }))
}
/// Caller is responsible for ensuring that `matched_rules` is non-empty.
fn from_matches(matched_rules: Vec<RuleMatch>) -> Self {
let decision = matched_rules.iter().map(RuleMatch::decision).max();
@@ -33,11 +33,6 @@ impl PromptFragment {
Self::new(PromptSlot::DeveloperCapabilities, text)
}
/// Creates a separate top-level developer prompt fragment.
pub fn separate_developer(text: impl Into<String>) -> Self {
Self::new(PromptSlot::SeparateDeveloper, text)
}
/// Returns the target prompt slot.
pub fn slot(&self) -> PromptSlot {
self.slot
@@ -1,11 +1,8 @@
use std::sync::Arc;
use codex_protocol::protocol::ReviewDecision;
use crate::ApprovalReviewContributor;
use crate::ConfigContributor;
use crate::ContextContributor;
use crate::ExtensionData;
use crate::ExtensionEventSink;
use crate::NoopExtensionEventSink;
use crate::ThreadLifecycleContributor;
@@ -68,11 +65,6 @@ impl<C: Sync> ExtensionRegistryBuilder<C> {
Arc::clone(&self.event_sink)
}
/// Registers one approval-review contributor.
pub fn approval_review_contributor(&mut self, contributor: Arc<dyn ApprovalReviewContributor>) {
self.approval_review_contributors.push(contributor);
}
/// Registers one thread-lifecycle contributor.
pub fn thread_lifecycle_contributor(
&mut self,
@@ -155,11 +147,6 @@ pub struct ExtensionRegistry<C: Sync> {
}
impl<C: Sync> ExtensionRegistry<C> {
/// Returns the host event sink retained by this registry.
pub fn event_sink(&self) -> Arc<dyn ExtensionEventSink> {
Arc::clone(&self.event_sink)
}
/// Returns the registered thread-lifecycle contributors.
pub fn thread_lifecycle_contributors(&self) -> &[Arc<dyn ThreadLifecycleContributor<C>>] {
&self.thread_lifecycle_contributors
@@ -180,26 +167,6 @@ impl<C: Sync> ExtensionRegistry<C> {
&self.token_usage_contributors
}
/// Claims the first rendered approval-review prompt accepted by an
/// installed contributor.
pub async fn approval_review(
&self,
session_store: &ExtensionData,
thread_store: &ExtensionData,
prompt: &str,
) -> Option<ReviewDecision> {
for contributor in &self.approval_review_contributors {
if let Some(decision) = contributor
.contribute(session_store, thread_store, prompt)
.await
{
return Some(decision);
}
}
None
}
/// Returns the registered prompt contributors.
pub fn context_contributors(&self) -> &[Arc<dyn ContextContributor>] {
&self.context_contributors
-8
View File
@@ -62,14 +62,6 @@ impl ExtensionData {
.map(downcast_data)
}
/// Removes and returns the attached value of type `T`, if one exists.
pub fn remove<T>(&self) -> Option<Arc<T>>
where
T: Any + Send + Sync,
{
self.entries().remove(&TypeId::of::<T>()).map(downcast_data)
}
fn entries(&self) -> std::sync::MutexGuard<'_, HashMap<TypeId, ErasedData>> {
self.entries.lock().unwrap_or_else(PoisonError::into_inner)
}
-22
View File
@@ -1,8 +1,6 @@
use std::sync::Arc;
use codex_core::config::Config;
use codex_extension_api::AgentSpawnFuture;
use codex_extension_api::AgentSpawner;
use codex_extension_api::ExtensionRegistryBuilder;
use codex_extension_api::ThreadLifecycleContributor;
use codex_extension_api::ThreadStartInput;
@@ -19,19 +17,6 @@ impl<S> GuardianExtension<S> {
pub fn new(agent_spawner: S) -> Self {
Self { agent_spawner }
}
/// Delegates one guardian-owned subagent spawn request to the host helper.
pub fn spawn_subagent<'a, R>(
&'a self,
forked_from_thread_id: ThreadId,
request: R,
) -> AgentSpawnFuture<'a, <S as AgentSpawner<R>>::Spawned, <S as AgentSpawner<R>>::Error>
where
S: AgentSpawner<R>,
{
self.agent_spawner
.spawn_subagent(forked_from_thread_id, request)
}
}
/// Thread-local guardian state captured when the host starts a thread.
@@ -40,13 +25,6 @@ pub struct GuardianThreadContext {
forked_from_thread_id: ThreadId,
}
impl GuardianThreadContext {
/// Returns the thread that future guardian subagents should fork from by default.
pub fn forked_from_thread_id(&self) -> ThreadId {
self.forked_from_thread_id
}
}
#[async_trait::async_trait]
impl<S> ThreadLifecycleContributor<Config> for GuardianExtension<S>
where
-19
View File
@@ -16,10 +16,6 @@ pub enum SkillSourceKind {
}
impl SkillSourceKind {
pub fn custom(kind: impl Into<String>) -> Self {
Self::Custom(kind.into())
}
fn as_str(&self) -> &str {
match self {
Self::Host => "host",
@@ -97,26 +93,11 @@ impl SkillCatalogEntry {
}
}
pub fn with_short_description(mut self, short_description: Option<String>) -> Self {
self.short_description = short_description;
self
}
pub fn with_display_path(mut self, display_path: impl Into<String>) -> Self {
self.display_path = Some(display_path.into());
self
}
pub fn with_dependencies(mut self, dependencies: Option<SkillDependencies>) -> Self {
self.dependencies = dependencies;
self
}
pub fn disabled(mut self) -> Self {
self.enabled = false;
self
}
pub fn hidden_from_prompt(mut self) -> Self {
self.prompt_visible = false;
self
-42
View File
@@ -4,12 +4,10 @@ use std::sync::Arc;
use crate::catalog::SkillCatalog;
use crate::catalog::SkillProviderError;
use crate::catalog::SkillReadResult;
use crate::catalog::SkillSearchResult;
use crate::catalog::SkillSourceKind;
use crate::provider::SkillListQuery;
use crate::provider::SkillProvider;
use crate::provider::SkillReadRequest;
use crate::provider::SkillSearchRequest;
#[derive(Clone)]
pub struct SkillProviderSource {
@@ -35,10 +33,6 @@ impl SkillProviderSource {
Self::new(SkillSourceKind::Host, label, provider)
}
pub fn executor(label: impl Into<String>, provider: Arc<dyn SkillProvider>) -> Self {
Self::new(SkillSourceKind::Executor, label, provider)
}
pub fn remote(label: impl Into<String>, provider: Arc<dyn SkillProvider>) -> Self {
Self::new(SkillSourceKind::Remote, label, provider)
}
@@ -77,23 +71,12 @@ impl SkillProviders {
Self::default()
}
pub fn with_provider(mut self, source: SkillProviderSource) -> Self {
self.sources.push(source);
self
}
pub fn with_host_provider(mut self, provider: Arc<dyn SkillProvider>) -> Self {
self.sources
.push(SkillProviderSource::host("host", provider));
self
}
pub fn with_executor_provider(mut self, provider: Arc<dyn SkillProvider>) -> Self {
self.sources
.push(SkillProviderSource::executor("executor", provider));
self
}
pub fn with_remote_provider(mut self, provider: Arc<dyn SkillProvider>) -> Self {
self.sources
.push(SkillProviderSource::remote("remote", provider));
@@ -142,31 +125,6 @@ impl SkillProviders {
))),
}
}
pub async fn search(
&self,
request: SkillSearchRequest,
) -> Result<SkillSearchResult, SkillProviderError> {
let mut last_error = None;
for source in self
.sources
.iter()
.filter(|source| source.owns_kind(&request.authority.kind))
{
match source.provider.search(request.clone()).await {
Ok(result) => return Ok(result),
Err(err) => last_error = Some(err),
}
}
match last_error {
Some(err) => Err(err),
None => Err(SkillProviderError::new(format!(
"{} skill provider is not configured",
request.authority.kind
))),
}
}
}
fn extend_catalog(
@@ -83,21 +83,6 @@ pub fn build_mcp_config_from_external(
Ok(TomlValue::Table(root))
}
pub fn hooks_migration_description(
source_external_agent_dir: &Path,
target_hooks: &Path,
) -> io::Result<Option<String>> {
if hook_migration_event_names(source_external_agent_dir, target_hooks)?.is_empty() {
return Ok(None);
}
Ok(Some(format!(
"Migrate hooks from {} to {}",
source_external_agent_dir.display(),
target_hooks.display()
)))
}
pub fn hook_migration_event_names(
source_external_agent_dir: &Path,
target_hooks: &Path,
-8
View File
@@ -406,14 +406,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;
+63
View File
@@ -0,0 +1,63 @@
preserve-uniform-field-visibility = true
[[production]]
package = "codex-cli"
bin = "codex"
reason = "primary shipped Codex CLI"
[[production]]
package = "codex-app-server"
bin = "codex-app-server"
reason = "standalone app-server release"
[[production]]
package = "codex-responses-api-proxy"
bin = "codex-responses-api-proxy"
reason = "standalone responses API proxy release"
[[exclude]]
crate = "codex_backend_openapi_models"
module = "models"
reason = "generated from the backend OpenAPI schema"
[[exclude]]
crate = "codex_windows_sandbox"
file = "windows-sandbox-rs/src/lib.rs"
target = "cfg(not(windows))"
reason = "Windows sandbox APIs are consumed only by Windows products"
[[exclude]]
crate = "codex_core"
module = "windows_sandbox"
target = "cfg(not(windows))"
reason = "Windows sandbox APIs are consumed only by Windows products"
[[exclude]]
crate = "codex_utils_pty"
file = "utils/pty/src/process_group.rs"
target = "cfg(not(target_os = \"linux\"))"
reason = "parent-death signaling is consumed only by Linux products"
[[override]]
lint = "hawk::dead_public"
crate = "codex_core"
item = "spawn_command_under_linux_sandbox"
level = "expect"
target = "cfg(not(target_os = \"linux\"))"
reason = "public re-export is consumed only by Linux products"
[[override]]
lint = "hawk::dead_public"
crate = "codex_cli"
item = "run_command_under_landlock"
level = "expect"
target = "cfg(not(target_os = \"linux\"))"
reason = "public re-export is consumed only by Linux products"
[[override]]
lint = "hawk::dead_public"
crate = "codex_cli"
item = "run_command_under_windows_sandbox"
level = "expect"
target = "cfg(not(windows))"
reason = "public re-export is consumed only by Windows products"
-11
View File
@@ -1764,17 +1764,6 @@ impl AuthManager {
result
}
/// Log out by deleting the on‑disk auth.json (if present). Returns Ok(true)
/// if a file was removed, Ok(false) if no auth file existed. On success,
/// reloads the in‑memory auth cache so callers immediately observe the
/// unauthenticated state.
pub async fn logout(&self) -> std::io::Result<bool> {
let removed = logout_all_stores(&self.codex_home, self.auth_credentials_store_mode)?;
// Always reload to clear any cached auth (even if file absent).
self.reload().await;
Ok(removed)
}
pub async fn logout_with_revoke(&self) -> std::io::Result<bool> {
let auth_dot_json = self
.auth_cached()
-10
View File
@@ -10,13 +10,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)
}
-30
View File
@@ -148,14 +148,6 @@ impl NetworkProxyBuilder {
self
}
pub fn blocked_request_observer<O>(mut self, observer: O) -> Self
where
O: BlockedRequestObserver,
{
self.blocked_request_observer = Some(Arc::new(observer));
self
}
pub fn blocked_request_observer_arc(
mut self,
observer: Arc<dyn BlockedRequestObserver>,
@@ -777,28 +769,6 @@ impl NetworkProxyHandle {
completed: true,
}
}
pub async fn wait(mut self) -> Result<()> {
let http_task = self.http_task.take().context("missing http proxy task")?;
let socks_task = self.socks_task.take();
let http_result = http_task.await;
let socks_result = match socks_task {
Some(task) => Some(task.await),
None => None,
};
self.completed = true;
http_result??;
if let Some(socks_result) = socks_result {
socks_result??;
}
Ok(())
}
pub async fn shutdown(mut self) -> Result<()> {
abort_tasks(self.http_task.take(), self.socks_task.take()).await;
self.completed = true;
Ok(())
}
}
async fn abort_task(task: Option<JoinHandle<Result<()>>>) {
-41
View File
@@ -238,19 +238,6 @@ impl NetworkProxyState {
)
}
pub fn with_reloader_and_blocked_observer(
state: ConfigState,
reloader: Arc<dyn ConfigReloader>,
blocked_request_observer: Option<Arc<dyn BlockedRequestObserver>>,
) -> Self {
Self::with_reloader_and_audit_metadata_and_blocked_observer(
state,
reloader,
NetworkProxyAuditMetadata::default(),
blocked_request_observer,
)
}
pub fn with_reloader_and_audit_metadata(
state: ConfigState,
reloader: Arc<dyn ConfigReloader>,
@@ -313,34 +300,6 @@ impl NetworkProxyState {
Ok(guard.config.network.enabled)
}
pub async fn force_reload(&self) -> Result<()> {
let previous_cfg = {
let guard = self.state.read().await;
guard.config.clone()
};
match self.reloader.reload_now().await {
Ok(mut new_state) => {
// Policy changes are operationally sensitive; logging diffs makes changes traceable
// without needing to dump full config blobs (which can include unrelated settings).
log_policy_changes(&previous_cfg, &new_state.config);
{
let mut guard = self.state.write().await;
new_state.blocked = guard.blocked.clone();
*guard = new_state;
}
let source = self.reloader.source_label();
info!("reloaded config from {source}");
Ok(())
}
Err(err) => {
let source = self.reloader.source_label();
warn!("failed to reload config from {source}: {err}; keeping previous config");
Err(err)
}
}
}
pub async fn replace_config_state(&self, mut new_state: ConfigState) -> Result<()> {
self.reload_if_needed().await?;
let mut guard = self.state.write().await;
@@ -6,7 +6,6 @@ use crate::events::shared::trace_event;
use crate::metrics::API_CALL_COUNT_METRIC;
use crate::metrics::API_CALL_DURATION_METRIC;
use crate::metrics::MetricsClient;
use crate::metrics::MetricsConfig;
use crate::metrics::MetricsError;
use crate::metrics::PLUGIN_INSTALL_ELICITATION_SENT_METRIC;
use crate::metrics::PLUGIN_INSTALL_SUGGESTION_METRIC;
@@ -30,7 +29,6 @@ use crate::metrics::WEBSOCKET_REQUEST_COUNT_METRIC;
use crate::metrics::WEBSOCKET_REQUEST_DURATION_METRIC;
use crate::metrics::runtime_metrics::RuntimeMetricsSummary;
use crate::metrics::timer::Timer;
use crate::provider::OtelProvider;
use crate::sanitize_metric_tag_value;
use codex_api::ApiError;
use codex_api::ResponseEvent;
@@ -46,8 +44,6 @@ use codex_protocol::user_input::UserInput;
use eventsource_stream::Event as StreamEvent;
use eventsource_stream::EventStreamError as StreamError;
use opentelemetry_sdk::metrics::data::ResourceMetrics;
use reqwest::Error;
use reqwest::Response;
use std::borrow::Cow;
use std::future::Future;
use std::time::Duration;
@@ -135,18 +131,6 @@ impl SessionTelemetry {
self
}
pub fn with_metrics_config(self, config: MetricsConfig) -> MetricsResult<Self> {
let metrics = MetricsClient::new(config)?;
Ok(self.with_metrics(metrics))
}
pub fn with_provider_metrics(self, provider: &OtelProvider) -> Self {
match provider.metrics() {
Some(metrics) => self.with_metrics(metrics.clone()),
None => self,
}
}
pub fn counter(&self, name: &str, inc: i64, tags: &[(&str, &str)]) {
let res: MetricsResult<()> = (|| {
let Some(metrics) = &self.metrics else {
@@ -474,39 +458,6 @@ impl SessionTelemetry {
);
}
pub async fn log_request<F, Fut>(&self, attempt: u64, f: F) -> Result<Response, Error>
where
F: FnOnce() -> Fut,
Fut: Future<Output = Result<Response, Error>>,
{
let start = Instant::now();
let response = f().await;
let duration = start.elapsed();
let (status, error) = match &response {
Ok(response) => (Some(response.status().as_u16()), None),
Err(error) => (error.status().map(|s| s.as_u16()), Some(error.to_string())),
};
self.record_api_request(
attempt,
status,
error.as_deref(),
duration,
/*auth_header_attached*/ false,
/*auth_header_name*/ None,
/*retry_after_unauthorized*/ false,
/*recovery_mode*/ None,
/*recovery_phase*/ None,
"unknown",
/*request_id*/ None,
/*cf_ray*/ None,
/*auth_error*/ None,
/*auth_error_code*/ None,
);
response
}
#[allow(clippy::too_many_arguments)]
pub fn record_api_request(
&self,
@@ -1036,30 +987,6 @@ impl SessionTelemetry {
result
}
pub fn log_tool_failed(&self, tool_name: &str, error: &str) {
log_event!(
self,
event.name = "codex.tool_result",
tool_name = %tool_name,
duration_ms = %Duration::ZERO.as_millis(),
success = %false,
output = %error,
mcp_server = "",
mcp_server_origin = "",
);
trace_event!(
self,
event.name = "codex.tool_result",
tool_name = %tool_name,
duration_ms = %Duration::ZERO.as_millis(),
success = %false,
output_length = error.len() as i64,
output_line_count = error.lines().count() as i64,
tool_origin = %"builtin",
error.message = %error,
);
}
#[allow(clippy::too_many_arguments)]
pub fn tool_result_with_tags(
&self,
-6
View File
@@ -69,9 +69,3 @@ pub fn start_global_timer(name: &str, tags: &[(&str, &str)]) -> MetricsResult<Ti
};
metrics.start_timer(name, tags)
}
/// Returns the resolved Statsig metrics settings for the globally installed
/// OTEL metrics client, if the active metrics exporter is Statsig.
pub fn global_statsig_metrics_settings() -> Option<StatsigMetricsSettings> {
crate::metrics::global_statsig_settings()
}
-6
View File
@@ -59,12 +59,6 @@ impl MetricsConfig {
}
}
/// Override the interval between periodic metric exports.
pub fn with_export_interval(mut self, interval: Duration) -> Self {
self.export_interval = Some(interval);
self
}
/// Enable a manual reader for on-demand runtime snapshots.
pub fn with_runtime_reader(mut self) -> Self {
self.runtime_reader = true;
-4
View File
@@ -177,10 +177,6 @@ impl OtelProvider {
})
}
pub fn codex_export_filter(meta: &tracing::Metadata<'_>) -> bool {
Self::log_export_filter(meta)
}
pub fn log_export_filter(meta: &tracing::Metadata<'_>) -> bool {
is_log_export_target(meta.target())
}
-8
View File
@@ -342,14 +342,6 @@ pub enum ElicitationRequest {
},
}
impl ElicitationRequest {
pub fn message(&self) -> &str {
match self {
Self::Form { 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.
-7
View File
@@ -209,13 +209,6 @@ impl CodexErr {
}
}
/// Minimal shim so that existing `e.downcast_ref::<CodexErr>()` checks continue to compile
/// after replacing `anyhow::Error` in the return signature. This mirrors the behavior of
/// `anyhow::Error::downcast_ref` but works directly on our concrete enum.
pub fn downcast_ref<T: std::any::Any>(&self) -> Option<&T> {
(self as &dyn std::any::Any).downcast_ref::<T>()
}
/// Translate core error to client-facing protocol error.
pub fn to_codex_protocol_error(&self) -> CodexErrorInfo {
match self {
-9
View File
@@ -437,15 +437,6 @@ fn serialize_hook_prompt_fragment(text: &str, hook_run_id: &str) -> Option<Strin
}
impl AgentMessageItem {
pub fn new(content: &[AgentMessageContent]) -> Self {
Self {
id: uuid::Uuid::new_v4().to_string(),
content: content.to_vec(),
phase: None,
memory_citation: None,
}
}
pub fn as_legacy_events(&self) -> Vec<EventMsg> {
self.content
.iter()
-16
View File
@@ -97,15 +97,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()
.map(|legacy| (legacy.read, legacy.write))
@@ -1427,13 +1418,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,
-10
View File
@@ -66,16 +66,6 @@ fn format_si_suffix_with_formatter(n: i64, formatter: &DecimalFormatter) -> Stri
)
}
/// 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::*;
-12
View File
@@ -30,18 +30,6 @@ pub const PROTECTED_METADATA_PATH_NAMES: &[&str] = &[
PROTECTED_METADATA_CODEX_PATH_NAME,
];
/// Returns true when a path basename is one of the protected workspace metadata names.
pub fn is_protected_metadata_name(name: &OsStr) -> bool {
PROTECTED_METADATA_PATH_NAMES
.iter()
.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(
-31
View File
@@ -2071,10 +2071,6 @@ pub struct SpendControlLimitSnapshot {
const BASELINE_TOKENS: i64 = 12000;
impl TokenUsage {
pub fn is_zero(&self) -> bool {
self.total_tokens == 0
}
pub fn cached_input(&self) -> i64 {
self.cached_input_tokens.max(0)
}
@@ -2088,33 +2084,6 @@ impl TokenUsage {
(self.non_cached_input() + self.output_tokens.max(0)).max(0)
}
pub fn tokens_in_context_window(&self) -> i64 {
self.total_tokens
}
/// Estimate the remaining user-controllable percentage of the model's context window.
///
/// `context_window` is the total size of the model's context window.
/// `BASELINE_TOKENS` should capture tokens that are always present in
/// the context (e.g., system prompt and fixed tool instructions) so that
/// the percentage reflects the portion the user can influence.
///
/// This normalizes both the numerator and denominator by subtracting the
/// baseline, so immediately after the first prompt the UI shows 100% left
/// and trends toward 0% as the user fills the effective window.
pub fn percent_of_context_window_remaining(&self, context_window: i64) -> i64 {
if context_window <= BASELINE_TOKENS {
return 0;
}
let effective_window = context_window - BASELINE_TOKENS;
let used = (self.tokens_in_context_window() - BASELINE_TOKENS).max(0);
let remaining = (effective_window - used).max(0);
((remaining as f64 / effective_window as f64) * 100.0)
.clamp(0.0, 100.0)
.round() as i64
}
/// In-place element-wise sum of token counts.
pub fn add_assign(&mut self, other: &TokenUsage) {
self.input_tokens += other.input_tokens;
@@ -331,10 +331,6 @@ impl OauthLoginHandle {
&self.authorization_url
}
pub fn into_parts(self) -> (String, oneshot::Receiver<Result<()>>) {
(self.authorization_url, self.completion)
}
pub async fn wait(self) -> Result<()> {
self.completion
.await
-94
View File
@@ -22,19 +22,14 @@ use reqwest::header::AUTHORIZATION;
use reqwest::header::HeaderMap;
use rmcp::model::CallToolRequestParams;
use rmcp::model::CallToolResult;
use rmcp::model::ClientNotification;
use rmcp::model::ClientRequest;
use rmcp::model::CreateElicitationRequestParams;
use rmcp::model::CreateElicitationResult;
use rmcp::model::CustomNotification;
use rmcp::model::CustomRequest;
use rmcp::model::ElicitationAction;
use rmcp::model::Extensions;
use rmcp::model::InitializeRequestParams;
use rmcp::model::InitializeResult;
use rmcp::model::ListResourceTemplatesResult;
use rmcp::model::ListResourcesResult;
use rmcp::model::ListToolsResult;
use rmcp::model::PaginatedRequestParams;
use rmcp::model::ReadResourceRequestParams;
use rmcp::model::ReadResourceResult;
@@ -283,26 +278,6 @@ pub struct RmcpClient {
}
impl RmcpClient {
pub async fn new_in_process_client(
factory: Arc<dyn InProcessTransportFactory>,
) -> io::Result<Self> {
let transport_recipe = TransportRecipe::InProcess { factory };
let transport = Self::create_pending_transport(&transport_recipe)
.await
.map_err(io::Error::other)?;
Ok(Self {
state: Mutex::new(ClientState::Connecting {
transport: Some(transport),
}),
stdio_process: None,
transport_recipe,
initialize_context: Mutex::new(None),
session_recovery_lock: Semaphore::new(/*permits*/ 1),
elicitation_pause_state: ElicitationPauseState::new(),
})
}
pub async fn new_stdio_client(
program: OsString,
args: Vec<OsString>,
@@ -434,22 +409,6 @@ impl RmcpClient {
Ok(initialize_result)
}
pub async fn list_tools(
&self,
params: Option<PaginatedRequestParams>,
timeout: Option<Duration>,
) -> Result<ListToolsResult> {
self.refresh_oauth_if_needed().await;
let result = self
.run_service_operation("tools/list", timeout, move |service| {
let params = params.clone();
async move { service.list_tools(params).await }.boxed()
})
.await?;
self.persist_oauth_tokens().await;
Ok(result)
}
pub async fn list_tools_with_connector_ids(
&self,
params: Option<PaginatedRequestParams>,
@@ -601,59 +560,6 @@ impl RmcpClient {
Ok(result)
}
pub async fn send_custom_notification(
&self,
method: &str,
params: Option<serde_json::Value>,
) -> Result<()> {
self.refresh_oauth_if_needed().await;
self.run_service_operation(
"notifications/custom",
/*timeout*/ None,
move |service| {
let params = params.clone();
async move {
service
.send_notification(ClientNotification::CustomNotification(
CustomNotification {
method: method.to_string(),
params,
extensions: Extensions::new(),
},
))
.await
}
.boxed()
},
)
.await?;
self.persist_oauth_tokens().await;
Ok(())
}
pub async fn send_custom_request(
&self,
method: &str,
params: Option<serde_json::Value>,
) -> Result<ServerResult> {
self.refresh_oauth_if_needed().await;
let response = self
.run_service_operation("requests/custom", /*timeout*/ None, move |service| {
let params = params.clone();
async move {
service
.send_request(ClientRequest::CustomRequest(CustomRequest::new(
method, params,
)))
.await
}
.boxed()
})
.await?;
self.persist_oauth_tokens().await;
Ok(response)
}
async fn service(&self) -> Result<Arc<RunningService<RoleClient, ElicitationClientService>>> {
let guard = self.state.lock().await;
match &*guard {
-80
View File
@@ -579,86 +579,6 @@ impl RolloutRecorder {
))
}
/// Find the newest recorded thread path, optionally filtering to a matching cwd.
#[allow(clippy::too_many_arguments)]
pub async fn find_latest_thread_path(
state_db_ctx: Option<StateDbHandle>,
config: &impl RolloutConfigView,
page_size: usize,
cursor: Option<&Cursor>,
sort_key: ThreadSortKey,
allowed_sources: &[SessionSource],
model_providers: Option<&[String]>,
default_provider: &str,
filter_cwd: Option<&Path>,
) -> std::io::Result<Option<PathBuf>> {
let codex_home = config.codex_home();
let cwd_filter = filter_cwd.map(Path::to_path_buf);
let mut fallback_reason = state_db_ctx.is_none().then_some("db_unavailable");
if state_db_ctx.is_some() {
let mut db_cursor = cursor.cloned();
loop {
let Some(db_page) = state_db::list_threads_db(
state_db_ctx.as_deref(),
codex_home,
page_size,
db_cursor.as_ref(),
sort_key,
SortDirection::Desc,
allowed_sources,
model_providers,
cwd_filter.as_ref().map(std::slice::from_ref),
/*archived*/ false,
/*search_term*/ None,
)
.await
else {
fallback_reason = Some("db_error");
break;
};
if let Some(path) =
select_resume_path_from_db_page(&db_page, filter_cwd, default_provider).await
{
return Ok(Some(path));
}
db_cursor = db_page.next_anchor.map(Into::into);
if db_cursor.is_none() {
fallback_reason = Some("missing_row");
break;
}
}
}
if let Some(reason) = fallback_reason {
codex_state::record_fallback(
"find_latest_thread_path",
reason,
/*telemetry_override*/ None,
);
}
let mut cursor = cursor.cloned();
loop {
let page = get_threads(
codex_home,
page_size,
cursor.as_ref(),
sort_key,
allowed_sources,
model_providers,
cwd_filter.as_ref().map(std::slice::from_ref),
default_provider,
)
.await?;
if let Some(path) = select_resume_path(&page, filter_cwd, default_provider).await {
return Ok(Some(path));
}
cursor = page.next_cursor;
if cursor.is_none() {
return Ok(None);
}
}
}
/// Attempt to create a new [`RolloutRecorder`].
///
/// For newly created sessions, this precomputes path/metadata and defers
-90
View File
@@ -293,60 +293,6 @@ pub fn normalize_cwd_for_state_db(cwd: &Path) -> PathBuf {
normalize_for_path_comparison(cwd).unwrap_or_else(|_| cwd.to_path_buf())
}
/// List thread ids from SQLite for parity checks without rollout scanning.
#[allow(clippy::too_many_arguments)]
pub async fn list_thread_ids_db(
context: Option<&codex_state::StateRuntime>,
codex_home: &Path,
page_size: usize,
cursor: Option<&Cursor>,
sort_key: ThreadSortKey,
allowed_sources: &[SessionSource],
model_providers: Option<&[String]>,
archived_only: bool,
stage: &str,
) -> Option<Vec<ThreadId>> {
let ctx = context?;
if ctx.codex_home() != codex_home {
warn!(
"state db codex_home mismatch: expected {}, got {}",
ctx.codex_home().display(),
codex_home.display()
);
}
let anchor = cursor_to_anchor(cursor);
let allowed_sources: Vec<String> = allowed_sources
.iter()
.map(|value| match serde_json::to_value(value) {
Ok(Value::String(s)) => s,
Ok(other) => other.to_string(),
Err(_) => String::new(),
})
.collect();
let model_providers = model_providers.map(<[String]>::to_vec);
match ctx
.list_thread_ids(
page_size,
anchor.as_ref(),
match sort_key {
ThreadSortKey::CreatedAt => codex_state::SortKey::CreatedAt,
ThreadSortKey::UpdatedAt => codex_state::SortKey::UpdatedAt,
},
allowed_sources.as_slice(),
model_providers.as_deref(),
archived_only,
)
.await
{
Ok(ids) => Some(ids),
Err(err) => {
warn!("state db list_thread_ids failed during {stage}: {err}");
None
}
}
}
/// List thread metadata from SQLite without rollout directory traversal.
#[allow(clippy::too_many_arguments)]
pub async fn list_threads_db(
@@ -438,22 +384,6 @@ pub async fn list_threads_db(
}
}
/// Look up the rollout path for a thread id using SQLite.
pub async fn find_rollout_path_by_id(
context: Option<&codex_state::StateRuntime>,
thread_id: ThreadId,
archived_only: Option<bool>,
stage: &str,
) -> Option<PathBuf> {
let ctx = context?;
ctx.find_rollout_path_by_id(thread_id, archived_only)
.await
.unwrap_or_else(|err| {
warn!("state db find_rollout_path_by_id failed during {stage}: {err}");
None
})
}
pub async fn mark_thread_memory_mode_polluted(
context: Option<&codex_state::StateRuntime>,
thread_id: ThreadId,
@@ -654,26 +584,6 @@ pub async fn apply_rollout_items(
}
}
pub async fn touch_thread_updated_at(
context: Option<&codex_state::StateRuntime>,
thread_id: Option<ThreadId>,
updated_at: DateTime<Utc>,
stage: &str,
) -> bool {
let Some(ctx) = context else {
return false;
};
let Some(thread_id) = thread_id else {
return false;
};
ctx.touch_thread_updated_at(thread_id, updated_at)
.await
.unwrap_or_else(|err| {
warn!("state db touch_thread_updated_at failed during {stage} for {thread_id}: {err}");
false
})
}
#[cfg(test)]
#[path = "state_db_tests.rs"]
mod tests;
-11
View File
@@ -5,7 +5,6 @@ use std::sync::Arc;
use anyhow::Result;
use codex_git_utils::get_git_repo_root;
use codex_keyring_store::DefaultKeyringStore;
use codex_keyring_store::KeyringStore;
use schemars::JsonSchema;
use serde::Deserialize;
@@ -99,16 +98,6 @@ pub struct SecretsManager {
}
impl SecretsManager {
pub fn new(codex_home: PathBuf, backend_kind: SecretsBackendKind) -> Self {
let backend: Arc<dyn SecretsBackend> = match backend_kind {
SecretsBackendKind::Local => {
let keyring_store: Arc<dyn KeyringStore> = Arc::new(DefaultKeyringStore);
Arc::new(LocalSecretsBackend::new(codex_home, keyring_store))
}
};
Self { backend }
}
pub fn new_with_keyring_store(
codex_home: PathBuf,
backend_kind: SecretsBackendKind,
-13
View File
@@ -2,7 +2,6 @@ use std::path::PathBuf;
use codex_utils_absolute_path::AbsolutePathBuf;
use crate::command_safety::try_parse_powershell_ast_commands;
use crate::shell_detect::ShellType;
use crate::shell_detect::detect_shell_type;
@@ -70,18 +69,6 @@ pub fn extract_powershell_command(command: &[String]) -> Option<(&str, &str)> {
None
}
/// Parse the script body from a top-level PowerShell wrapper into argv-like commands.
///
/// This is intentionally narrower than the Windows safe-command parser: it only unwraps the
/// `-Command`/`-c` body from a PowerShell invocation we already recognize, then delegates the
/// script itself to the PowerShell AST parser.
pub fn parse_powershell_command_into_plain_commands(
command: &[String],
) -> Option<Vec<Vec<String>>> {
let (executable, script) = extract_powershell_command(command)?;
try_parse_powershell_ast_commands(executable, script)
}
/// This function attempts to find a powershell.exe executable on the system.
pub fn try_find_powershell_executable_blocking() -> Option<AbsolutePathBuf> {
try_find_powershellish_executable_in_path(&["powershell.exe"])
-7
View File
@@ -33,13 +33,6 @@ impl AgentJobStatus {
_ => Err(anyhow::anyhow!("invalid agent job status: {value}")),
}
}
pub fn is_final(self) -> bool {
matches!(
self,
AgentJobStatus::Completed | AgentJobStatus::Failed | AgentJobStatus::Cancelled
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
-8
View File
@@ -29,14 +29,6 @@ impl ThreadGoalStatus {
Self::Complete => "complete",
}
}
pub fn is_active(self) -> bool {
self == Self::Active
}
pub fn is_terminal(self) -> bool {
matches!(self, Self::BudgetLimited | Self::Complete)
}
}
impl TryFrom<&str> for ThreadGoalStatus {
-52
View File
@@ -311,34 +311,6 @@ WHERE id = ?
Ok(AgentJobStatus::parse(status.as_str())? == AgentJobStatus::Cancelled)
}
pub async fn mark_agent_job_item_running(
&self,
job_id: &str,
item_id: &str,
) -> anyhow::Result<bool> {
let now = Utc::now().timestamp();
let result = sqlx::query(
r#"
UPDATE agent_job_items
SET
status = ?,
assigned_thread_id = NULL,
attempt_count = attempt_count + 1,
updated_at = ?,
last_error = NULL
WHERE job_id = ? AND item_id = ? AND status = ?
"#,
)
.bind(AgentJobItemStatus::Running.as_str())
.bind(now)
.bind(job_id)
.bind(item_id)
.bind(AgentJobItemStatus::Pending.as_str())
.execute(self.pool.as_ref())
.await?;
Ok(result.rows_affected() > 0)
}
pub async fn mark_agent_job_item_running_with_thread(
&self,
job_id: &str,
@@ -398,30 +370,6 @@ WHERE job_id = ? AND item_id = ? AND status = ?
Ok(result.rows_affected() > 0)
}
pub async fn set_agent_job_item_thread(
&self,
job_id: &str,
item_id: &str,
thread_id: &str,
) -> anyhow::Result<bool> {
let now = Utc::now().timestamp();
let result = sqlx::query(
r#"
UPDATE agent_job_items
SET assigned_thread_id = ?, updated_at = ?
WHERE job_id = ? AND item_id = ? AND status = ?
"#,
)
.bind(thread_id)
.bind(now)
.bind(job_id)
.bind(item_id)
.bind(AgentJobItemStatus::Running.as_str())
.execute(self.pool.as_ref())
.await?;
Ok(result.rows_affected() > 0)
}
pub async fn report_agent_job_item_result(
&self,
job_id: &str,
-4
View File
@@ -3,10 +3,6 @@ use super::*;
const LOG_RETENTION_DAYS: i64 = 10;
impl StateRuntime {
pub async fn insert_log(&self, entry: &LogEntry) -> anyhow::Result<()> {
self.insert_logs(std::slice::from_ref(entry)).await
}
/// Insert a batch of log entries into the logs table.
pub async fn insert_logs(&self, entries: &[LogEntry]) -> anyhow::Result<()> {
if entries.is_empty() {
-91
View File
@@ -157,62 +157,6 @@ ON CONFLICT(child_thread_id) DO UPDATE SET
.await
}
/// Find a direct spawned child of `parent_thread_id` by canonical agent path.
pub async fn find_thread_spawn_child_by_path(
&self,
parent_thread_id: ThreadId,
agent_path: &str,
) -> anyhow::Result<Option<ThreadId>> {
let rows = sqlx::query(
r#"
SELECT threads.id
FROM thread_spawn_edges
JOIN threads ON threads.id = thread_spawn_edges.child_thread_id
WHERE thread_spawn_edges.parent_thread_id = ?
AND threads.agent_path = ?
ORDER BY threads.id
LIMIT 2
"#,
)
.bind(parent_thread_id.to_string())
.bind(agent_path)
.fetch_all(self.pool.as_ref())
.await?;
one_thread_id_from_rows(rows, agent_path)
}
/// Find a spawned descendant of `root_thread_id` by canonical agent path.
pub async fn find_thread_spawn_descendant_by_path(
&self,
root_thread_id: ThreadId,
agent_path: &str,
) -> anyhow::Result<Option<ThreadId>> {
let rows = sqlx::query(
r#"
WITH RECURSIVE subtree(child_thread_id) AS (
SELECT child_thread_id
FROM thread_spawn_edges
WHERE parent_thread_id = ?
UNION ALL
SELECT edge.child_thread_id
FROM thread_spawn_edges AS edge
JOIN subtree ON edge.parent_thread_id = subtree.child_thread_id
)
SELECT threads.id
FROM subtree
JOIN threads ON threads.id = subtree.child_thread_id
WHERE threads.agent_path = ?
ORDER BY threads.id
LIMIT 2
"#,
)
.bind(root_thread_id.to_string())
.bind(agent_path)
.fetch_all(self.pool.as_ref())
.await?;
one_thread_id_from_rows(rows, agent_path)
}
async fn list_thread_spawn_children_matching(
&self,
parent_thread_id: ThreadId,
@@ -429,41 +373,6 @@ ON CONFLICT(child_thread_id) DO NOTHING
})
}
/// List thread ids using the underlying database (no rollout scanning).
pub async fn list_thread_ids(
&self,
limit: usize,
anchor: Option<&crate::Anchor>,
sort_key: crate::SortKey,
allowed_sources: &[String],
model_providers: Option<&[String]>,
archived_only: bool,
) -> anyhow::Result<Vec<ThreadId>> {
let mut builder = QueryBuilder::<Sqlite>::new("SELECT threads.id FROM threads");
push_thread_filters(
&mut builder,
ThreadFilterOptions {
archived_only,
allowed_sources,
model_providers,
cwd_filters: None,
anchor,
sort_key,
sort_direction: SortDirection::Desc,
search_term: None,
},
);
push_thread_order_and_limit(&mut builder, sort_key, SortDirection::Desc, limit);
let rows = builder.build().fetch_all(self.pool.as_ref()).await?;
rows.into_iter()
.map(|row| {
let id: String = row.try_get("id")?;
Ok(ThreadId::try_from(id)?)
})
.collect()
}
/// Insert or replace thread metadata directly.
pub async fn upsert_thread(&self, metadata: &crate::ThreadMetadata) -> anyhow::Result<()> {
self.upsert_thread_with_creation_memory_mode(metadata, /*creation_memory_mode*/ None)
-4
View File
@@ -92,10 +92,6 @@ impl JsonToolOutput {
success: Some(true),
}
}
pub fn with_success(value: JsonValue, success: Option<bool>) -> Self {
Self { value, success }
}
}
impl ToolOutput for JsonToolOutput {
-20
View File
@@ -492,22 +492,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 };
@@ -542,10 +526,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
-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
@@ -47,17 +47,6 @@ impl ComposerInput {
Self { inner, _tx: tx, rx }
}
/// Returns true if the input is empty.
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
/// Clear the input text.
pub fn clear(&mut self) {
self.inner
.set_text_content(String::new(), Vec::new(), Vec::new());
}
/// Feed a key event into the composer and return a high-level action.
pub fn input(&mut self, key: KeyEvent) -> ComposerAction {
let action = match self.inner.handle_key_event(key).0 {
@@ -84,11 +73,6 @@ impl ComposerInput {
self.inner.set_footer_hint_override(Some(mapped));
}
/// Clear any previously set custom hint items and restore the default hints.
pub fn clear_hint_items(&mut self) {
self.inner.set_footer_hint_override(/*items*/ None);
}
/// Desired height (in rows) for a given width.
pub fn desired_height(&self, width: u16) -> u16 {
self.inner.desired_height(width)
-6
View File
@@ -63,12 +63,6 @@ where
value()
}
/// Builds a cache if `capacity` is non-zero, returning `None` otherwise.
#[must_use]
pub fn try_with_capacity(capacity: usize) -> Option<Self> {
NonZeroUsize::new(capacity).map(Self::new)
}
/// Returns a clone of the cached value corresponding to `key`, if present.
pub fn get<Q>(&self, key: &Q) -> Option<V>
where
-11
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 {