mirror of
https://github.com/openai/codex.git
synced 2026-11-05 20:10:33 +00:00
Remove unused functions and methods
This commit is contained in:
@@ -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");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
@@ -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,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)
|
||||
}
|
||||
|
||||
@@ -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<()>>>) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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::*;
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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"])
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Vendored
-6
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user