diff --git a/codex-rs/Cargo.lock b/codex-rs/Cargo.lock index ea74bcd3bb..296dffcebb 100644 --- a/codex-rs/Cargo.lock +++ b/codex-rs/Cargo.lock @@ -1002,7 +1002,6 @@ dependencies = [ "codex-mcp-server", "codex-process-hardening", "codex-protocol", - "codex-protocol-ts", "codex-responses-api-proxy", "codex-rmcp-client", "codex-stdio-to-uds", @@ -1387,16 +1386,6 @@ dependencies = [ "uuid", ] -[[package]] -name = "codex-protocol-ts" -version = "0.0.0" -dependencies = [ - "anyhow", - "clap", - "codex-app-server-protocol", - "ts-rs", -] - [[package]] name = "codex-responses-api-proxy" version = "0.0.0" diff --git a/codex-rs/Cargo.toml b/codex-rs/Cargo.toml index 7a24019e18..d2bc313ca1 100644 --- a/codex-rs/Cargo.toml +++ b/codex-rs/Cargo.toml @@ -26,7 +26,6 @@ members = [ "ollama", "process-hardening", "protocol", - "protocol-ts", "rmcp-client", "responses-api-proxy", "stdio-to-uds", @@ -77,7 +76,6 @@ codex-ollama = { path = "ollama" } codex-otel = { path = "otel" } codex-process-hardening = { path = "process-hardening" } codex-protocol = { path = "protocol" } -codex-protocol-ts = { path = "protocol-ts" } codex-responses-api-proxy = { path = "responses-api-proxy" } codex-rmcp-client = { path = "rmcp-client" } codex-stdio-to-uds = { path = "stdio-to-uds" } diff --git a/codex-rs/cli/Cargo.toml b/codex-rs/cli/Cargo.toml index 041644b34d..c5a55bb2e2 100644 --- a/codex-rs/cli/Cargo.toml +++ b/codex-rs/cli/Cargo.toml @@ -30,7 +30,6 @@ codex-login = { workspace = true } codex-mcp-server = { workspace = true } codex-process-hardening = { workspace = true } codex-protocol = { workspace = true } -codex-protocol-ts = { workspace = true } codex-responses-api-proxy = { workspace = true } codex-rmcp-client = { workspace = true } codex-stdio-to-uds = { workspace = true } diff --git a/codex-rs/cli/src/main.rs b/codex-rs/cli/src/main.rs index 66f551a5bc..633f2605e7 100644 --- a/codex-rs/cli/src/main.rs +++ b/codex-rs/cli/src/main.rs @@ -99,9 +99,9 @@ enum Subcommand { /// Resume a previous interactive session (picker by default; use --last to continue the most recent). Resume(ResumeCommand), - /// Internal: generate TypeScript protocol bindings. - #[clap(hide = true)] + /// [experimental] Generate TypeScript bindings for the app server protocol. GenerateTs(GenerateTsCommand), + /// [EXPERIMENTAL] Browse tasks from Codex Cloud and apply changes locally. #[clap(name = "cloud", alias = "cloud-tasks")] Cloud(CloudTasksCli), @@ -528,7 +528,7 @@ async fn cli_main(codex_linux_sandbox_exe: Option) -> anyhow::Result<() .await??; } Some(Subcommand::GenerateTs(gen_cli)) => { - codex_protocol_ts::generate_ts(&gen_cli.out_dir, gen_cli.prettier.as_deref())?; + codex_app_server_protocol::generate_ts(&gen_cli.out_dir, gen_cli.prettier.as_deref())?; } Some(Subcommand::Features(FeaturesCli { sub })) => match sub { FeaturesSubcommand::List => { diff --git a/codex-rs/core/src/codex.rs b/codex-rs/core/src/codex.rs index b6e616ded6..a9038ab91d 100644 --- a/codex-rs/core/src/codex.rs +++ b/codex-rs/core/src/codex.rs @@ -7,6 +7,7 @@ use std::sync::atomic::AtomicU64; use crate::AuthManager; use crate::ModelClient; use crate::client_common::REVIEW_PROMPT; +use crate::compact; use crate::features::Feature; use crate::function_tool::FunctionCallError; use crate::mcp::auth::McpAuthStatusEntry; @@ -66,6 +67,8 @@ use crate::error::Result as CodexResult; use crate::exec::StreamOutput; // Removed: legacy executor wiring replaced by ToolOrchestrator flows. // legacy normalize_exec_result no longer used after orchestrator migration +use crate::compact::build_compacted_history; +use crate::compact::collect_user_messages; use crate::mcp::auth::compute_auth_statuses; use crate::mcp_connection_manager::McpConnectionManager; use crate::model_family::find_family_for_model; @@ -129,10 +132,6 @@ use codex_protocol::user_input::UserInput; use codex_utils_readiness::Readiness; use codex_utils_readiness::ReadinessFlag; -pub mod compact; -use self::compact::build_compacted_history; -use self::compact::collect_user_messages; - /// The high-level interface to the Codex system. /// It operates as a queue pair where you send submissions and receive events. pub struct Codex { @@ -970,7 +969,7 @@ impl Session { } /// Append ResponseItems to the in-memory conversation history only. - async fn record_into_history(&self, items: &[ResponseItem]) { + pub(crate) async fn record_into_history(&self, items: &[ResponseItem]) { let mut state = self.state.lock().await; state.record_items(items.iter()); } @@ -1022,7 +1021,7 @@ impl Session { items } - async fn persist_rollout_items(&self, items: &[RolloutItem]) { + pub(crate) async fn persist_rollout_items(&self, items: &[RolloutItem]) { let recorder = { let guard = self.services.rollout.lock().await; guard.clone() @@ -1039,7 +1038,7 @@ impl Session { state.clone_history() } - async fn update_token_usage_info( + pub(crate) async fn update_token_usage_info( &self, turn_context: &TurnContext, token_usage: Option<&TokenUsage>, @@ -1056,7 +1055,7 @@ impl Session { self.send_token_count_event(turn_context).await; } - async fn update_rate_limits( + pub(crate) async fn update_rate_limits( &self, turn_context: &TurnContext, new_rate_limits: RateLimitSnapshot, @@ -1077,7 +1076,7 @@ impl Session { self.send_event(turn_context, event).await; } - async fn set_total_tokens_full(&self, turn_context: &TurnContext) { + pub(crate) async fn set_total_tokens_full(&self, turn_context: &TurnContext) { let context_window = turn_context.client.get_model_context_window(); if let Some(context_window) = context_window { { @@ -1120,7 +1119,11 @@ impl Session { self.send_event(turn_context, event).await; } - async fn notify_stream_error(&self, turn_context: &TurnContext, message: impl Into) { + pub(crate) async fn notify_stream_error( + &self, + turn_context: &TurnContext, + message: impl Into, + ) { let event = EventMsg::StreamError(StreamErrorEvent { message: message.into(), }); diff --git a/codex-rs/core/src/codex/compact.rs b/codex-rs/core/src/compact.rs similarity index 98% rename from codex-rs/core/src/codex/compact.rs rename to codex-rs/core/src/compact.rs index 5e84b0baa3..11a24c0742 100644 --- a/codex-rs/core/src/codex/compact.rs +++ b/codex-rs/core/src/compact.rs @@ -1,10 +1,10 @@ use std::sync::Arc; -use super::Session; -use super::TurnContext; -use super::get_last_assistant_message_from_turn; use crate::Prompt; use crate::client_common::ResponseEvent; +use crate::codex::Session; +use crate::codex::TurnContext; +use crate::codex::get_last_assistant_message_from_turn; use crate::error::CodexErr; use crate::error::Result as CodexResult; use crate::protocol::AgentMessageEvent; @@ -25,7 +25,7 @@ use codex_protocol::user_input::UserInput; use futures::prelude::*; use tracing::error; -pub const SUMMARIZATION_PROMPT: &str = include_str!("../../templates/compact/prompt.md"); +pub const SUMMARIZATION_PROMPT: &str = include_str!("../templates/compact/prompt.md"); const COMPACT_USER_MESSAGE_MAX_TOKENS: usize = 20_000; pub(crate) async fn run_inline_auto_compact_task( diff --git a/codex-rs/core/src/lib.rs b/codex-rs/core/src/lib.rs index c96d2bc1ac..e5ef6a3344 100644 --- a/codex-rs/core/src/lib.rs +++ b/codex-rs/core/src/lib.rs @@ -97,11 +97,12 @@ pub use client_common::Prompt; pub use client_common::REVIEW_PROMPT; pub use client_common::ResponseEvent; pub use client_common::ResponseStream; -pub use codex::compact::content_items_to_text; pub use codex_protocol::models::ContentItem; pub use codex_protocol::models::LocalShellAction; pub use codex_protocol::models::LocalShellExecAction; pub use codex_protocol::models::LocalShellStatus; pub use codex_protocol::models::ResponseItem; +pub use compact::content_items_to_text; pub use event_mapping::parse_turn_item; +pub mod compact; pub mod otel_init; diff --git a/codex-rs/core/src/tasks/compact.rs b/codex-rs/core/src/tasks/compact.rs index 64b2a9d2b4..4f06d68924 100644 --- a/codex-rs/core/src/tasks/compact.rs +++ b/codex-rs/core/src/tasks/compact.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use tokio_util::sync::CancellationToken; use crate::codex::TurnContext; -use crate::codex::compact; +use crate::compact; use crate::state::TaskKind; use codex_protocol::user_input::UserInput; diff --git a/codex-rs/protocol-ts/Cargo.toml b/codex-rs/protocol-ts/Cargo.toml deleted file mode 100644 index 53f314ccbe..0000000000 --- a/codex-rs/protocol-ts/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -edition = "2024" -name = "codex-protocol-ts" -version = { workspace = true } - -[lints] -workspace = true - -[lib] -name = "codex_protocol_ts" -path = "src/lib.rs" - -[[bin]] -name = "codex-protocol-ts" -path = "src/main.rs" - -[dependencies] -anyhow = { workspace = true } -clap = { workspace = true, features = ["derive"] } -codex-app-server-protocol = { workspace = true } -ts-rs = { workspace = true } diff --git a/codex-rs/protocol-ts/generate-ts b/codex-rs/protocol-ts/generate-ts deleted file mode 100755 index 8f90bced6b..0000000000 --- a/codex-rs/protocol-ts/generate-ts +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash - -set -euo pipefail - -cd "$(dirname "$0")"/.. - -tmpdir=$(mktemp -d) -just codex generate-ts --prettier ../node_modules/.bin/prettier --out "$tmpdir" - -echo "wrote output to $tmpdir" diff --git a/codex-rs/protocol-ts/src/lib.rs b/codex-rs/protocol-ts/src/lib.rs deleted file mode 100644 index c3180d9b93..0000000000 --- a/codex-rs/protocol-ts/src/lib.rs +++ /dev/null @@ -1,135 +0,0 @@ -use anyhow::Context; -use anyhow::Result; -use anyhow::anyhow; -use codex_app_server_protocol::ClientNotification; -use codex_app_server_protocol::ClientRequest; -use codex_app_server_protocol::ServerNotification; -use codex_app_server_protocol::ServerRequest; -use codex_app_server_protocol::export_client_responses; -use codex_app_server_protocol::export_server_responses; -use std::ffi::OsStr; -use std::fs; -use std::io::Read; -use std::io::Write; -use std::path::Path; -use std::path::PathBuf; -use std::process::Command; -use ts_rs::TS; - -const HEADER: &str = "// GENERATED CODE! DO NOT MODIFY BY HAND!\n\n"; - -pub fn generate_ts(out_dir: &Path, prettier: Option<&Path>) -> Result<()> { - ensure_dir(out_dir)?; - - // Generate the TS bindings client -> server messages. - ClientRequest::export_all_to(out_dir)?; - export_client_responses(out_dir)?; - ClientNotification::export_all_to(out_dir)?; - - // Generate the TS bindings server -> client messages. - ServerRequest::export_all_to(out_dir)?; - export_server_responses(out_dir)?; - ServerNotification::export_all_to(out_dir)?; - - // Generate index.ts that re-exports all types. - generate_index_ts(out_dir)?; - - // Prepend header to each generated .ts file - let ts_files = ts_files_in(out_dir)?; - for file in &ts_files { - prepend_header_if_missing(file)?; - } - - // Format with Prettier by passing individual files (no shell globbing) - if let Some(prettier_bin) = prettier - && !ts_files.is_empty() - { - let status = Command::new(prettier_bin) - .arg("--write") - .arg("--log-level") - .arg("warn") - .args(ts_files.iter().map(|p| p.as_os_str())) - .status() - .with_context(|| format!("Failed to invoke Prettier at {}", prettier_bin.display()))?; - if !status.success() { - return Err(anyhow!("Prettier failed with status {status}")); - } - } - - Ok(()) -} - -fn ensure_dir(dir: &Path) -> Result<()> { - fs::create_dir_all(dir) - .with_context(|| format!("Failed to create output directory {}", dir.display())) -} - -fn prepend_header_if_missing(path: &Path) -> Result<()> { - let mut content = String::new(); - { - let mut f = fs::File::open(path) - .with_context(|| format!("Failed to open {} for reading", path.display()))?; - f.read_to_string(&mut content) - .with_context(|| format!("Failed to read {}", path.display()))?; - } - - if content.starts_with(HEADER) { - return Ok(()); - } - - let mut f = fs::File::create(path) - .with_context(|| format!("Failed to open {} for writing", path.display()))?; - f.write_all(HEADER.as_bytes()) - .with_context(|| format!("Failed to write header to {}", path.display()))?; - f.write_all(content.as_bytes()) - .with_context(|| format!("Failed to write content to {}", path.display()))?; - Ok(()) -} - -fn ts_files_in(dir: &Path) -> Result> { - let mut files = Vec::new(); - for entry in - fs::read_dir(dir).with_context(|| format!("Failed to read dir {}", dir.display()))? - { - let entry = entry?; - let path = entry.path(); - if path.is_file() && path.extension() == Some(OsStr::new("ts")) { - files.push(path); - } - } - files.sort(); - Ok(files) -} - -/// Generate an index.ts file that re-exports all generated types. -/// This allows consumers to import all types from a single file. -fn generate_index_ts(out_dir: &Path) -> Result { - let mut entries: Vec = Vec::new(); - let mut stems: Vec = ts_files_in(out_dir)? - .into_iter() - .filter_map(|p| { - let stem = p.file_stem()?.to_string_lossy().into_owned(); - if stem == "index" { None } else { Some(stem) } - }) - .collect(); - stems.sort(); - stems.dedup(); - - for name in stems { - entries.push(format!("export type {{ {name} }} from \"./{name}\";\n")); - } - - let mut content = - String::with_capacity(HEADER.len() + entries.iter().map(String::len).sum::()); - content.push_str(HEADER); - for line in &entries { - content.push_str(line); - } - - let index_path = out_dir.join("index.ts"); - let mut f = fs::File::create(&index_path) - .with_context(|| format!("Failed to create {}", index_path.display()))?; - f.write_all(content.as_bytes()) - .with_context(|| format!("Failed to write {}", index_path.display()))?; - Ok(index_path) -} diff --git a/codex-rs/protocol-ts/src/main.rs b/codex-rs/protocol-ts/src/main.rs deleted file mode 100644 index f477b9f5a6..0000000000 --- a/codex-rs/protocol-ts/src/main.rs +++ /dev/null @@ -1,20 +0,0 @@ -use anyhow::Result; -use clap::Parser; -use std::path::PathBuf; - -#[derive(Parser, Debug)] -#[command(about = "Generate TypeScript bindings for the Codex protocol")] -struct Args { - /// Output directory where .ts files will be written - #[arg(short = 'o', long = "out", value_name = "DIR")] - out_dir: PathBuf, - - /// Optional path to the Prettier executable to format generated files - #[arg(short = 'p', long = "prettier", value_name = "PRETTIER_BIN")] - prettier: Option, -} - -fn main() -> Result<()> { - let args = Args::parse(); - codex_protocol_ts::generate_ts(&args.out_dir, args.prettier.as_deref()) -} diff --git a/docs/config.md b/docs/config.md index 1175a986c4..90671ce98d 100644 --- a/docs/config.md +++ b/docs/config.md @@ -347,11 +347,13 @@ Use the optional `[tools]` table to toggle built-in tools that the agent may cal ```toml [tools] -web_search = true # allow Codex to issue first-party web searches without prompting you +web_search = true # allow Codex to issue first-party web searches without prompting you (deprecated) view_image = false # disable image uploads (they're enabled by default) ``` -`web_search` is also recognized under the legacy name `web_search_request`. The `view_image` toggle is useful when you want to include screenshots or diagrams from your repo without pasting them manually. Codex still respects sandboxing: it can only attach files inside the workspace roots you allow. +`web_search` is deprecated; use the `web_search_request` feature flag instead. + +The `view_image` toggle is useful when you want to include screenshots or diagrams from your repo without pasting them manually. Codex still respects sandboxing: it can only attach files inside the workspace roots you allow. ### approval_presets @@ -917,6 +919,7 @@ Valid values: | `sandbox_workspace_write.exclude_slash_tmp` | boolean | Exclude `/tmp` from writable roots (default: false). | | `notify` | array | External program for notifications. | | `instructions` | string | Currently ignored; use `experimental_instructions_file` or `AGENTS.md`. | +| `features.` | boolean | See [feature flags](#feature-flags) for details | | `mcp_servers..command` | string | MCP server launcher command (stdio servers only). | | `mcp_servers..args` | array | MCP server args (stdio servers only). | | `mcp_servers..env` | map | MCP server env vars (stdio servers only). | @@ -956,7 +959,7 @@ Valid values: | `experimental_instructions_file` | string (path) | Replace built‑in instructions (experimental). | | `experimental_use_exec_command_tool` | boolean | Use experimental exec command tool. | | `projects..trust_level` | string | Mark project/worktree as trusted (only `"trusted"` is recognized). | -| `tools.web_search` | boolean | Enable web search tool (alias: `web_search_request`) (default: false). | +| `tools.web_search` | boolean | Enable web search tool (deprecated) (default: false). | | `tools.view_image` | boolean | Enable or disable the `view_image` tool so Codex can attach local image files from the workspace (default: true). | | `forced_login_method` | `chatgpt` \| `api` | Only allow Codex to be used with ChatGPT or API keys. | | `forced_chatgpt_workspace_id` | string (uuid) | Only allow Codex to be used with the specified ChatGPT workspace. |