Merge remote-tracking branch 'upstream/main' into dev/codex/add-custom-models-support-in-config.toml-r2

# Conflicts:
#	codex-rs/core/src/config/schema.rs
This commit is contained in:
Friel
2026-04-02 09:44:04 +00:00
72 changed files with 2839 additions and 5233 deletions
+6 -1
View File
@@ -1407,6 +1407,7 @@ dependencies = [
"codex-backend-client",
"codex-chatgpt",
"codex-cloud-requirements",
"codex-config",
"codex-core",
"codex-exec-server",
"codex-features",
@@ -1803,11 +1804,13 @@ dependencies = [
"serde_json",
"serde_path_to_error",
"sha2",
"tempfile",
"thiserror 2.0.18",
"tokio",
"toml 0.9.11+spec-1.1.0",
"toml_edit 0.24.0+spec-1.1.0",
"tracing",
"wildmatch",
]
[[package]]
@@ -1951,7 +1954,6 @@ dependencies = [
"uuid",
"walkdir",
"which 8.0.0",
"wildmatch",
"windows-sys 0.52.0",
"wiremock",
"zip",
@@ -2215,6 +2217,7 @@ version = "0.0.0"
dependencies = [
"cc",
"clap",
"codex-config",
"codex-core",
"codex-protocol",
"codex-sandboxing",
@@ -2318,6 +2321,7 @@ version = "0.0.0"
dependencies = [
"anyhow",
"codex-arg0",
"codex-config",
"codex-core",
"codex-exec-server",
"codex-features",
@@ -2708,6 +2712,7 @@ dependencies = [
"codex-chatgpt",
"codex-cli",
"codex-cloud-requirements",
"codex-config",
"codex-core",
"codex-features",
"codex-feedback",
+1
View File
@@ -32,6 +32,7 @@ axum = { workspace = true, default-features = false, features = [
codex-analytics = { workspace = true }
codex-arg0 = { workspace = true }
codex-cloud-requirements = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-exec-server = { workspace = true }
codex-features = { workspace = true }
@@ -181,6 +181,7 @@ use codex_arg0::Arg0DispatchPaths;
use codex_backend_client::Client as BackendClient;
use codex_chatgpt::connectors;
use codex_cloud_requirements::cloud_requirements_loader;
use codex_config::types::McpServerTransportConfig;
use codex_core::CodexThread;
use codex_core::Cursor as RolloutCursor;
use codex_core::ForkSnapshot;
@@ -196,7 +197,6 @@ use codex_core::config::ConfigOverrides;
use codex_core::config::NetworkProxyAuditMetadata;
use codex_core::config::edit::ConfigEdit;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::config_loader::CloudRequirementsLoadError;
use codex_core::config_loader::CloudRequirementsLoadErrorCode;
use codex_core::config_loader::CloudRequirementsLoader;
@@ -3,8 +3,8 @@ use std::sync::Arc;
use codex_app_server_protocol::McpServerOauthLoginCompletedNotification;
use codex_app_server_protocol::ServerNotification;
use codex_config::types::McpServerConfig;
use codex_core::config::Config;
use codex_core::config::types::McpServerConfig;
use codex_mcp::mcp::auth::McpOAuthLoginSupport;
use codex_mcp::mcp::auth::oauth_login_support;
use codex_mcp::mcp::auth::resolve_oauth_scopes;
@@ -2,9 +2,9 @@ use anyhow::Result;
use app_test_support::ChatGptAuthFixture;
use app_test_support::DEFAULT_CLIENT_NAME;
use app_test_support::write_chatgpt_auth;
use codex_config::types::OtelExporterKind;
use codex_config::types::OtelHttpProtocol;
use codex_core::config::ConfigBuilder;
use codex_core::config::types::OtelExporterKind;
use codex_core::config::types::OtelHttpProtocol;
use codex_login::AuthCredentialsStoreMode;
use pretty_assertions::assert_eq;
use serde_json::Value;
+2 -2
View File
@@ -6,12 +6,12 @@ use anyhow::Result;
use anyhow::anyhow;
use anyhow::bail;
use clap::ArgGroup;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_core::config::Config;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::find_codex_home;
use codex_core::config::load_global_mcp_servers;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_core::mcp::McpManager;
use codex_core::plugins::PluginsManager;
use codex_mcp::mcp::auth::McpOAuthLoginSupport;
+1 -1
View File
@@ -1,8 +1,8 @@
use std::path::Path;
use anyhow::Result;
use codex_config::types::McpServerTransportConfig;
use codex_core::config::load_global_mcp_servers;
use codex_core::config::types::McpServerTransportConfig;
use predicates::str::contains;
use pretty_assertions::assert_eq;
use tempfile::TempDir;
+1 -1
View File
@@ -1,9 +1,9 @@
use std::path::Path;
use anyhow::Result;
use codex_config::types::McpServerTransportConfig;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::load_global_mcp_servers;
use codex_core::config::types::McpServerTransportConfig;
use predicates::prelude::PredicateBooleanExt;
use predicates::str::contains;
use pretty_assertions::assert_eq;
+1 -1
View File
@@ -3,7 +3,7 @@ load("//:defs.bzl", "codex_rust_crate")
codex_rust_crate(
name = "config-schema",
crate_name = "codex_config_schema",
compile_data = ["src/schema_presentation_template.json"],
compile_data = ["//codex-rs/core:config.schema.json"],
rustc_env = {
"CARGO_MANIFEST_DIR": "codex-rs/config-schema",
},
+3 -3
View File
@@ -10,8 +10,6 @@ use serde_json::Map;
use serde_json::Value;
use std::path::Path;
const SCHEMA_PRESENTATION_TEMPLATE_JSON: &str = include_str!("schema_presentation_template.json");
pub use config_toml::mcp_servers_schema;
pub use features::features_schema;
@@ -61,7 +59,9 @@ pub fn write_config_schema(out_path: &Path) -> anyhow::Result<()> {
}
fn preserve_schema_presentation(value: Value) -> anyhow::Result<Value> {
let template = serde_json::from_str(SCHEMA_PRESENTATION_TEMPLATE_JSON)?;
let template_path = Path::new(env!("CARGO_MANIFEST_DIR")).join("../core/config.schema.json");
let template = std::fs::read_to_string(template_path)?;
let template = serde_json::from_str(&template)?;
Ok(preserve_schema_presentation_from_template(value, &template))
}
File diff suppressed because it is too large Load Diff
+2
View File
@@ -24,8 +24,10 @@ tokio = { workspace = true, features = ["fs"] }
toml = { workspace = true }
toml_edit = { workspace = true }
tracing = { workspace = true }
wildmatch = { workspace = true }
[dev-dependencies]
anyhow = { workspace = true }
pretty_assertions = { workspace = true }
tempfile = { workspace = true }
tokio = { workspace = true, features = ["full"] }
+1
View File
@@ -11,6 +11,7 @@ mod project_root_markers;
mod requirements_exec_policy;
mod skills_config;
mod state;
pub mod types;
pub const CONFIG_TOML_FILE: &str = "config.toml";
@@ -1,14 +1,14 @@
//! Types used to define the fields of [`crate::config::Config`].
//! Types used to define loaded and effective Codex configuration values.
// Note this file should generally be restricted to simple struct/enum
// definitions that do not contain business logic.
pub use codex_config::AppToolApproval;
pub use codex_config::McpServerConfig;
pub use codex_config::McpServerDisabledReason;
pub use codex_config::McpServerToolConfig;
pub use codex_config::McpServerTransportConfig;
pub use codex_config::RawMcpServerConfig;
pub use crate::mcp_types::AppToolApproval;
pub use crate::mcp_types::McpServerConfig;
pub use crate::mcp_types::McpServerDisabledReason;
pub use crate::mcp_types::McpServerToolConfig;
pub use crate::mcp_types::McpServerTransportConfig;
pub use crate::mcp_types::RawMcpServerConfig;
pub use codex_protocol::config_types::AltScreenMode;
pub use codex_protocol::config_types::ApprovalsReviewer;
pub use codex_protocol::config_types::ModeKind;
@@ -537,14 +537,9 @@ pub struct Notice {
pub model_migrations: BTreeMap<String, String>,
}
impl Notice {
/// referenced by config_edit helpers when writing notice flags
pub(crate) const TABLE_KEY: &'static str = "notice";
}
pub use codex_config::BundledSkillsConfig;
pub use codex_config::SkillConfig;
pub use codex_config::SkillsConfig;
pub use crate::skills_config::BundledSkillsConfig;
pub use crate::skills_config::SkillConfig;
pub use crate::skills_config::SkillsConfig;
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, JsonSchema)]
#[schemars(deny_unknown_fields)]
+1
View File
@@ -2,6 +2,7 @@ load("//:defs.bzl", "codex_rust_crate")
exports_files(
[
"config.schema.json",
"templates/collaboration_mode/default.md",
"templates/collaboration_mode/plan.md",
],
-1
View File
@@ -116,7 +116,6 @@ tracing = { workspace = true, features = ["log"] }
url = { workspace = true }
uuid = { workspace = true, features = ["serde", "v4", "v5"] }
which = { workspace = true }
wildmatch = { workspace = true }
zip = { workspace = true }
[target.'cfg(target_os = "linux")'.dependencies]
+1 -1
View File
@@ -2432,7 +2432,7 @@
"$ref": "#/definitions/Notice"
}
],
"description": "Collection of in-product notices (different from notifications) See [`crate::config::types::Notices`] for more details"
"description": "Collection of in-product notices (different from notifications) See [`codex_config::types::Notice`] for more details"
},
"notify": {
"default": null,
+1 -1
View File
@@ -1,6 +1,6 @@
use crate::config::types::Personality;
use crate::error::Result;
pub use codex_api::common::ResponseEvent;
use codex_config::types::Personality;
use codex_protocol::models::BaseInstructions;
use codex_protocol::models::FunctionCallOutputBody;
use codex_protocol::models::ResponseItem;
+2 -2
View File
@@ -181,8 +181,6 @@ use crate::config::ConstraintResult;
use crate::config::GhostSnapshotConfig;
use crate::config::StartedNetworkProxy;
use crate::config::resolve_web_search_mode_for_turn;
use crate::config::types::McpServerConfig;
use crate::config::types::ShellEnvironmentPolicy;
use crate::context_manager::ContextManager;
use crate::context_manager::TotalTokenUsageBreakdown;
use crate::environment_context::EnvironmentContext;
@@ -191,6 +189,8 @@ use crate::error::Result as CodexResult;
#[cfg(test)]
use crate::exec::StreamOutput;
use codex_config::CONFIG_TOML_FILE;
use codex_config::types::McpServerConfig;
use codex_config::types::ShellEnvironmentPolicy;
mod rollout_reconstruction;
#[cfg(test)]
+3 -3
View File
@@ -605,7 +605,7 @@ async fn reload_user_config_layer_updates_effective_apps_config() {
.and_then(|table| table.get("apps"))
.cloned()
.expect("apps table");
let apps = crate::config::types::AppsConfigToml::deserialize(apps_toml)
let apps = codex_config::types::AppsConfigToml::deserialize(apps_toml)
.expect("deserialize apps config");
let app = apps
.apps
@@ -3094,7 +3094,7 @@ async fn user_turn_updates_approvals_reviewer() {
}],
cwd: config.cwd.to_path_buf(),
approval_policy: config.permissions.approval_policy.value(),
approvals_reviewer: Some(crate::config::types::ApprovalsReviewer::GuardianSubagent),
approvals_reviewer: Some(codex_config::types::ApprovalsReviewer::GuardianSubagent),
sandbox_policy: config.permissions.sandbox_policy.get().clone(),
model: turn_context.model_info.slug.clone(),
effort: config.model_reasoning_effort,
@@ -3110,7 +3110,7 @@ async fn user_turn_updates_approvals_reviewer() {
let state = session.state.lock().await;
assert_eq!(
state.session_configuration.approvals_reviewer,
crate::config::types::ApprovalsReviewer::GuardianSubagent
codex_config::types::ApprovalsReviewer::GuardianSubagent
);
}
+13 -13
View File
@@ -1,23 +1,23 @@
use crate::config::edit::ConfigEdit;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::edit::apply_blocking;
use crate::config::types::AppToolApproval;
use crate::config::types::ApprovalsReviewer;
use crate::config::types::BundledSkillsConfig;
use crate::config::types::FeedbackConfigToml;
use crate::config::types::HistoryPersistence;
use crate::config::types::McpServerToolConfig;
use crate::config::types::McpServerTransportConfig;
use crate::config::types::MemoriesConfig;
use crate::config::types::MemoriesToml;
use crate::config::types::ModelAvailabilityNuxConfig;
use crate::config::types::NotificationMethod;
use crate::config::types::Notifications;
use crate::config::types::ToolSuggestDiscoverableType;
use crate::config_loader::RequirementSource;
use crate::plugins::PluginsManager;
use assert_matches::assert_matches;
use codex_config::CONFIG_TOML_FILE;
use codex_config::types::AppToolApproval;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::BundledSkillsConfig;
use codex_config::types::FeedbackConfigToml;
use codex_config::types::HistoryPersistence;
use codex_config::types::McpServerToolConfig;
use codex_config::types::McpServerTransportConfig;
use codex_config::types::MemoriesConfig;
use codex_config::types::MemoriesToml;
use codex_config::types::ModelAvailabilityNuxConfig;
use codex_config::types::NotificationMethod;
use codex_config::types::Notifications;
use codex_config::types::ToolSuggestDiscoverableType;
use codex_features::Feature;
use codex_features::FeaturesToml;
use codex_protocol::permissions::FileSystemAccessMode;
+12 -11
View File
@@ -1,9 +1,8 @@
use crate::config::types::McpServerConfig;
use crate::config::types::Notice;
use crate::path_utils::resolve_symlink_write_paths;
use crate::path_utils::write_atomically;
use anyhow::Context;
use codex_config::CONFIG_TOML_FILE;
use codex_config::types::McpServerConfig;
use codex_features::FEATURES;
use codex_protocol::config_types::Personality;
use codex_protocol::config_types::ServiceTier;
@@ -20,6 +19,8 @@ use toml_edit::Item as TomlItem;
use toml_edit::Table as TomlTable;
use toml_edit::value;
const NOTICE_TABLE_KEY: &str = "notice";
/// Discrete config mutations supported by the persistence engine.
#[derive(Clone, Debug)]
pub enum ConfigEdit {
@@ -125,10 +126,10 @@ pub fn model_availability_nux_count_edits(shown_count: &HashMap<String, u32>) ->
// TODO(jif) move to a dedicated file
mod document_helpers {
use crate::config::types::AppToolApproval;
use crate::config::types::McpServerConfig;
use crate::config::types::McpServerToolConfig;
use crate::config::types::McpServerTransportConfig;
use codex_config::types::AppToolApproval;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerToolConfig;
use codex_config::types::McpServerTransportConfig;
use toml_edit::Array as TomlArray;
use toml_edit::InlineTable;
use toml_edit::Item as TomlItem;
@@ -387,29 +388,29 @@ impl ConfigDocument {
)),
ConfigEdit::SetNoticeHideFullAccessWarning(acknowledged) => Ok(self.write_value(
Scope::Global,
&[Notice::TABLE_KEY, "hide_full_access_warning"],
&[NOTICE_TABLE_KEY, "hide_full_access_warning"],
value(*acknowledged),
)),
ConfigEdit::SetNoticeHideWorldWritableWarning(acknowledged) => Ok(self.write_value(
Scope::Global,
&[Notice::TABLE_KEY, "hide_world_writable_warning"],
&[NOTICE_TABLE_KEY, "hide_world_writable_warning"],
value(*acknowledged),
)),
ConfigEdit::SetNoticeHideRateLimitModelNudge(acknowledged) => Ok(self.write_value(
Scope::Global,
&[Notice::TABLE_KEY, "hide_rate_limit_model_nudge"],
&[NOTICE_TABLE_KEY, "hide_rate_limit_model_nudge"],
value(*acknowledged),
)),
ConfigEdit::SetNoticeHideModelMigrationPrompt(migration_config, acknowledged) => {
Ok(self.write_value(
Scope::Global,
&[Notice::TABLE_KEY, migration_config.as_str()],
&[NOTICE_TABLE_KEY, migration_config.as_str()],
value(*acknowledged),
))
}
ConfigEdit::RecordModelMigrationSeen { from, to } => Ok(self.write_value(
Scope::Global,
&[Notice::TABLE_KEY, "model_migrations", from.as_str()],
&[NOTICE_TABLE_KEY, "model_migrations", from.as_str()],
value(to.clone()),
)),
ConfigEdit::SetWindowsWslSetupAcknowledged(acknowledged) => Ok(self.write_value(
+3 -3
View File
@@ -1,7 +1,7 @@
use super::*;
use crate::config::types::AppToolApproval;
use crate::config::types::McpServerToolConfig;
use crate::config::types::McpServerTransportConfig;
use codex_config::types::AppToolApproval;
use codex_config::types::McpServerToolConfig;
use codex_config::types::McpServerTransportConfig;
use codex_protocol::openai_models::ReasoningEffort;
use pretty_assertions::assert_eq;
#[cfg(unix)]
+32 -33
View File
@@ -1,31 +1,5 @@
use crate::config::edit::ConfigEdit;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::types::AppsConfigToml;
use crate::config::types::DEFAULT_OTEL_ENVIRONMENT;
use crate::config::types::History;
use crate::config::types::McpServerConfig;
use crate::config::types::McpServerDisabledReason;
use crate::config::types::McpServerTransportConfig;
use crate::config::types::MemoriesConfig;
use crate::config::types::MemoriesToml;
use crate::config::types::ModelAvailabilityNuxConfig;
use crate::config::types::Notice;
use crate::config::types::NotificationMethod;
use crate::config::types::Notifications;
use crate::config::types::OtelConfig;
use crate::config::types::OtelConfigToml;
use crate::config::types::OtelExporterKind;
use crate::config::types::PluginConfig;
use crate::config::types::SandboxWorkspaceWrite;
use crate::config::types::ShellEnvironmentPolicy;
use crate::config::types::ShellEnvironmentPolicyToml;
use crate::config::types::SkillsConfig;
use crate::config::types::ToolSuggestConfig;
use crate::config::types::ToolSuggestDiscoverable;
use crate::config::types::Tui;
use crate::config::types::UriBasedFileOpener;
use crate::config::types::WindowsSandboxModeToml;
use crate::config::types::WindowsToml;
use crate::config_loader::CloudRequirementsLoader;
use crate::config_loader::ConfigLayerStack;
use crate::config_loader::ConfigLayerStackOrdering;
@@ -56,6 +30,33 @@ use crate::windows_sandbox::resolve_windows_sandbox_mode;
use crate::windows_sandbox::resolve_windows_sandbox_private_desktop;
use codex_app_server_protocol::Tools;
use codex_app_server_protocol::UserSavedConfig;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::AppsConfigToml;
use codex_config::types::DEFAULT_OTEL_ENVIRONMENT;
use codex_config::types::History;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerDisabledReason;
use codex_config::types::McpServerTransportConfig;
use codex_config::types::MemoriesConfig;
use codex_config::types::MemoriesToml;
use codex_config::types::ModelAvailabilityNuxConfig;
use codex_config::types::Notice;
use codex_config::types::NotificationMethod;
use codex_config::types::Notifications;
use codex_config::types::OtelConfig;
use codex_config::types::OtelConfigToml;
use codex_config::types::OtelExporterKind;
use codex_config::types::PluginConfig;
use codex_config::types::SandboxWorkspaceWrite;
use codex_config::types::ShellEnvironmentPolicy;
use codex_config::types::ShellEnvironmentPolicyToml;
use codex_config::types::SkillsConfig;
use codex_config::types::ToolSuggestConfig;
use codex_config::types::ToolSuggestDiscoverable;
use codex_config::types::Tui;
use codex_config::types::UriBasedFileOpener;
use codex_config::types::WindowsSandboxModeToml;
use codex_config::types::WindowsToml;
use codex_features::Feature;
use codex_features::FeatureConfigSource;
use codex_features::FeatureOverrides;
@@ -113,7 +114,6 @@ mod permissions;
pub mod profile;
pub mod schema;
pub mod service;
pub mod types;
pub use codex_config::Constrained;
pub use codex_config::ConstraintError;
pub use codex_config::ConstraintResult;
@@ -135,7 +135,6 @@ pub(crate) use permissions::overlay_network_domain_permissions;
pub(crate) use permissions::resolve_permission_profile;
pub use service::ConfigService;
pub use service::ConfigServiceError;
pub use types::ApprovalsReviewer;
pub use codex_git_utils::GhostSnapshotConfig;
@@ -591,7 +590,7 @@ pub struct Config {
pub tool_suggest: ToolSuggestConfig,
/// OTEL configuration (exporter type, endpoint, headers, etc.).
pub otel: crate::config::types::OtelConfig,
pub otel: codex_config::types::OtelConfig,
}
#[derive(Debug, Clone, Default)]
@@ -1406,18 +1405,18 @@ pub struct ConfigToml {
/// When `false`, disables analytics across Codex product surfaces in this machine.
/// Defaults to `true`.
pub analytics: Option<crate::config::types::AnalyticsConfigToml>,
pub analytics: Option<codex_config::types::AnalyticsConfigToml>,
/// When `false`, disables feedback collection across Codex product surfaces.
/// Defaults to `true`.
pub feedback: Option<crate::config::types::FeedbackConfigToml>,
pub feedback: Option<codex_config::types::FeedbackConfigToml>,
/// Settings for app-specific controls.
#[serde(default)]
pub apps: Option<AppsConfigToml>,
/// OTEL configuration.
pub otel: Option<crate::config::types::OtelConfigToml>,
pub otel: Option<codex_config::types::OtelConfigToml>,
/// Windows-specific configuration.
#[serde(default)]
@@ -1427,7 +1426,7 @@ pub struct ConfigToml {
pub windows_wsl_setup_acknowledged: Option<bool>,
/// Collection of in-product notices (different from notifications)
/// See [`crate::config::types::Notices`] for more details
/// See [`codex_config::types::Notice`] for more details
pub notice: Option<Notice>,
/// Legacy, now use features
+4 -4
View File
@@ -4,9 +4,9 @@ use serde::Deserialize;
use serde::Serialize;
use crate::config::ToolsToml;
use crate::config::types::ApprovalsReviewer;
use crate::config::types::Personality;
use crate::config::types::WindowsToml;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::Personality;
use codex_config::types::WindowsToml;
use codex_features::FeaturesToml;
use codex_protocol::config_types::ReasoningSummary;
use codex_protocol::config_types::SandboxMode;
@@ -54,7 +54,7 @@ pub struct ConfigProfile {
pub tools_view_image: Option<bool>,
pub tools: Option<ToolsToml>,
pub web_search: Option<WebSearchMode>,
pub analytics: Option<crate::config::types::AnalyticsConfigToml>,
pub analytics: Option<codex_config::types::AnalyticsConfigToml>,
#[serde(default)]
pub windows: Option<WindowsToml>,
/// Optional feature toggles scoped to this profile.
+3 -3
View File
@@ -26,14 +26,14 @@ use tracing::warn;
use crate::codex::INITIAL_SUBMIT_ID;
use crate::config::Config;
use crate::config::types::AppToolApproval;
use crate::config::types::AppsConfigToml;
use crate::config::types::ToolSuggestDiscoverableType;
use crate::config_loader::AppsRequirementsToml;
use crate::mcp::McpManager;
use crate::plugins::AppConnectorId;
use crate::plugins::PluginsManager;
use crate::plugins::list_tool_suggest_discoverable_plugins;
use codex_config::types::AppToolApproval;
use codex_config::types::AppsConfigToml;
use codex_config::types::ToolSuggestDiscoverableType;
use codex_features::Feature;
use codex_login::AuthManager;
use codex_login::CodexAuth;
+4 -4
View File
@@ -1,16 +1,16 @@
use super::*;
use crate::config::CONFIG_TOML_FILE;
use crate::config::ConfigBuilder;
use crate::config::types::AppConfig;
use crate::config::types::AppToolConfig;
use crate::config::types::AppToolsConfig;
use crate::config::types::AppsDefaultConfig;
use crate::config_loader::AppRequirementToml;
use crate::config_loader::AppsRequirementsToml;
use crate::config_loader::CloudRequirementsLoader;
use crate::config_loader::ConfigLayerStack;
use crate::config_loader::ConfigRequirements;
use crate::config_loader::ConfigRequirementsToml;
use codex_config::types::AppConfig;
use codex_config::types::AppToolConfig;
use codex_config::types::AppToolsConfig;
use codex_config::types::AppsDefaultConfig;
use codex_features::Feature;
use codex_mcp::mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_mcp::mcp_connection_manager::ToolInfo;
+3 -3
View File
@@ -1,6 +1,6 @@
use crate::config::types::EnvironmentVariablePattern;
use crate::config::types::ShellEnvironmentPolicy;
use crate::config::types::ShellEnvironmentPolicyInherit;
use codex_config::types::EnvironmentVariablePattern;
use codex_config::types::ShellEnvironmentPolicy;
use codex_config::types::ShellEnvironmentPolicyInherit;
use codex_protocol::ThreadId;
use std::collections::HashMap;
use std::collections::HashSet;
+1 -1
View File
@@ -1,5 +1,5 @@
use super::*;
use crate::config::types::ShellEnvironmentPolicyInherit;
use codex_config::types::ShellEnvironmentPolicyInherit;
use maplit::hashmap;
fn make_vars(pairs: &[(&str, &str)]) -> Vec<(String, String)> {
+1 -1
View File
@@ -34,9 +34,9 @@ use crate::config::Constrained;
use crate::config::ManagedFeatures;
use crate::config::NetworkProxySpec;
use crate::config::Permissions;
use crate::config::types::McpServerConfig;
use crate::model_provider_info::ModelProviderInfo;
use crate::rollout::recorder::RolloutRecorder;
use codex_config::types::McpServerConfig;
use codex_features::Feature;
use super::GUARDIAN_REVIEW_TIMEOUT;
+3 -4
View File
@@ -19,7 +19,6 @@ use crate::config::Config;
use crate::config::edit::ConfigEdit;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::load_global_mcp_servers;
use crate::config::types::AppToolApproval;
use crate::connectors;
use crate::guardian::GuardianApprovalRequest;
use crate::guardian::GuardianMcpAnnotations;
@@ -31,6 +30,7 @@ use crate::mcp_tool_approval_templates::render_mcp_tool_approval_template;
use codex_analytics::AppInvocation;
use codex_analytics::InvocationType;
use codex_analytics::build_track_events_context;
use codex_config::types::AppToolApproval;
use codex_features::Feature;
use codex_mcp::mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_otel::sanitize_metric_tag_value;
@@ -583,7 +583,7 @@ fn custom_mcp_tool_approval_mode(
.and_then(|table| table.get("mcp_servers"))
.cloned()
.and_then(|value| {
HashMap::<String, crate::config::types::McpServerConfig>::deserialize(value).ok()
HashMap::<String, codex_config::types::McpServerConfig>::deserialize(value).ok()
})
.and_then(|servers| servers.get(server).cloned())
.and_then(|server| server.tools.get(tool_name).cloned())
@@ -1541,8 +1541,7 @@ fn project_mcp_tool_approval_config_folder(config: &Config, server: &str) -> Opt
.and_then(|table| table.get("mcp_servers"))
.cloned()
.and_then(|value| {
HashMap::<String, crate::config::types::McpServerConfig>::deserialize(value)
.ok()
HashMap::<String, codex_config::types::McpServerConfig>::deserialize(value).ok()
})?;
if servers.contains_key(server) {
layer
+7 -7
View File
@@ -1,17 +1,17 @@
use super::*;
use crate::codex::make_session_and_context;
use crate::codex::make_session_and_context_with_rx;
use crate::config::ApprovalsReviewer;
use crate::config::ConfigBuilder;
use crate::config::ConfigToml;
use crate::config::types::AppConfig;
use crate::config::types::AppToolConfig;
use crate::config::types::AppToolsConfig;
use crate::config::types::AppsConfigToml;
use crate::config::types::McpServerConfig;
use crate::config::types::McpServerToolConfig;
use crate::state::ActiveTurn;
use codex_config::CONFIG_TOML_FILE;
use codex_config::types::AppConfig;
use codex_config::types::AppToolConfig;
use codex_config::types::AppToolsConfig;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::AppsConfigToml;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerToolConfig;
use core_test_support::responses::ev_assistant_message;
use core_test_support::responses::ev_completed;
use core_test_support::responses::ev_response_created;
+1 -1
View File
@@ -3,7 +3,6 @@ use crate::RolloutRecorder;
use crate::codex::Session;
use crate::codex::TurnContext;
use crate::config::Config;
use crate::config::types::MemoriesConfig;
use crate::contextual_user_message::is_memory_excluded_contextual_user_fragment;
use crate::error::CodexErr;
use crate::memories::metrics;
@@ -13,6 +12,7 @@ use crate::memories::prompts::build_stage_one_input_message;
use crate::rollout::INTERACTIVE_SESSION_SOURCES;
use crate::rollout::policy::should_persist_response_item_for_memories;
use codex_api::ResponseEvent;
use codex_config::types::MemoriesConfig;
use codex_otel::SessionTelemetry;
use codex_protocol::config_types::ReasoningSummary as ReasoningSummaryConfig;
use codex_protocol::config_types::ServiceTier;
+1 -1
View File
@@ -1,6 +1,5 @@
use super::storage::rebuild_raw_memories_file_from_memories;
use super::storage::sync_rollout_summaries_from_memories;
use crate::config::types::DEFAULT_MEMORIES_MAX_RAW_MEMORIES_FOR_CONSOLIDATION;
use crate::memories::clear_memory_root_contents;
use crate::memories::ensure_layout;
use crate::memories::memory_root;
@@ -8,6 +7,7 @@ use crate::memories::raw_memories_file;
use crate::memories::rollout_summaries_dir;
use chrono::TimeZone;
use chrono::Utc;
use codex_config::types::DEFAULT_MEMORIES_MAX_RAW_MEMORIES_FOR_CONSOLIDATION;
use codex_protocol::ThreadId;
use codex_state::Stage1Output;
use pretty_assertions::assert_eq;
+1 -1
View File
@@ -36,7 +36,7 @@ use tokio::fs;
use tokio::io::AsyncReadExt;
use crate::config::Config;
use crate::config::types::HistoryPersistence;
use codex_config::types::HistoryPersistence;
use codex_protocol::ThreadId;
#[cfg(unix)]
+2 -2
View File
@@ -1,6 +1,6 @@
use crate::config::Config;
use crate::config::types::OtelExporterKind as Kind;
use crate::config::types::OtelHttpProtocol as Protocol;
use codex_config::types::OtelExporterKind as Kind;
use codex_config::types::OtelHttpProtocol as Protocol;
use codex_features::Feature;
use codex_login::default_client::originator;
use codex_otel::OtelProvider;
+1 -1
View File
@@ -7,7 +7,7 @@ use super::PluginCapabilitySummary;
use super::PluginReadRequest;
use super::PluginsManager;
use crate::config::Config;
use crate::config::types::ToolSuggestDiscoverableType;
use codex_config::types::ToolSuggestDiscoverableType;
use codex_features::Feature;
use codex_tools::DiscoverablePluginInfo;
+2 -2
View File
@@ -33,8 +33,6 @@ use crate::config::ConfigService;
use crate::config::ConfigServiceError;
use crate::config::edit::ConfigEdit;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::types::McpServerConfig;
use crate::config::types::PluginConfig;
use crate::config_loader::ConfigLayerStack;
use crate::config_rules::SkillConfigRules;
use crate::config_rules::resolve_disabled_skill_paths;
@@ -44,6 +42,8 @@ use crate::loader::load_skills_from_roots;
use codex_analytics::AnalyticsEventsClient;
use codex_app_server_protocol::ConfigValueWriteParams;
use codex_app_server_protocol::MergeStrategy;
use codex_config::types::McpServerConfig;
use codex_config::types::PluginConfig;
use codex_features::Feature;
use codex_login::AuthManager;
use codex_login::CodexAuth;
+1 -1
View File
@@ -1,7 +1,6 @@
use super::*;
use crate::config::CONFIG_TOML_FILE;
use crate::config::ConfigBuilder;
use crate::config::types::McpServerTransportConfig;
use crate::config_loader::ConfigLayerEntry;
use crate::config_loader::ConfigLayerStack;
use crate::config_loader::ConfigRequirements;
@@ -14,6 +13,7 @@ use crate::plugins::test_support::write_curated_plugin_sha_with as write_curated
use crate::plugins::test_support::write_file;
use crate::plugins::test_support::write_openai_curated_marketplace;
use codex_app_server_protocol::ConfigLayerSource;
use codex_config::types::McpServerTransportConfig;
use codex_login::CodexAuth;
use codex_protocol::protocol::Product;
use pretty_assertions::assert_eq;
+1 -1
View File
@@ -1,4 +1,4 @@
use crate::config::types::McpServerConfig;
use codex_config::types::McpServerConfig;
mod discoverable;
mod injection;
@@ -3,7 +3,6 @@ use crate::ThreadManager;
use crate::built_in_model_providers;
use crate::codex::make_session_and_context;
use crate::config::DEFAULT_AGENT_MAX_DEPTH;
use crate::config::types::ShellEnvironmentPolicy;
use crate::function_tool::FunctionCallError;
use crate::session_prefix::format_subagent_notification_message;
use crate::state::TaskKind;
@@ -17,6 +16,7 @@ use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHa
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2;
use crate::turn_diff_tracker::TurnDiffTracker;
use codex_config::types::ShellEnvironmentPolicy;
use codex_features::Feature;
use codex_login::AuthManager;
use codex_login::CodexAuth;
+141 -553
View File
@@ -1,82 +1,23 @@
use crate::shell::Shell;
use crate::shell::ShellType;
use crate::tools::code_mode::PUBLIC_TOOL_NAME;
use crate::tools::code_mode::WAIT_TOOL_NAME;
use crate::tools::handlers::agent_jobs::BatchJobHandler;
use crate::tools::handlers::multi_agents_common::DEFAULT_WAIT_TIMEOUT_MS;
use crate::tools::handlers::multi_agents_common::MAX_WAIT_TIMEOUT_MS;
use crate::tools::handlers::multi_agents_common::MIN_WAIT_TIMEOUT_MS;
use crate::tools::registry::ToolRegistryBuilder;
use crate::tools::registry::tool_handler_key;
use codex_mcp::mcp::CODEX_APPS_MCP_SERVER_NAME;
use codex_mcp::mcp_connection_manager::ToolInfo;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use codex_protocol::openai_models::ApplyPatchToolType;
use codex_protocol::openai_models::ConfigShellToolType;
use codex_tools::CommandToolOptions;
use codex_tools::DiscoverableTool;
use codex_tools::REQUEST_USER_INPUT_TOOL_NAME;
use codex_tools::ShellToolOptions;
use codex_tools::SpawnAgentToolOptions;
use codex_tools::TOOL_SEARCH_DEFAULT_LIMIT;
use codex_tools::TOOL_SEARCH_TOOL_NAME;
use codex_tools::TOOL_SUGGEST_TOOL_NAME;
use codex_tools::ToolSearchAppSource;
use codex_tools::ToolSpec;
use codex_tools::ToolHandlerKind;
use codex_tools::ToolRegistryPlanAppTool;
use codex_tools::ToolRegistryPlanParams;
use codex_tools::ToolUserShellType;
use codex_tools::ToolsConfig;
use codex_tools::ViewImageToolOptions;
use codex_tools::WaitAgentTimeoutOptions;
use codex_tools::WebSearchToolOptions;
use codex_tools::augment_tool_spec_for_code_mode;
use codex_tools::collect_code_mode_tool_definitions;
use codex_tools::collect_tool_search_app_infos;
use codex_tools::collect_tool_suggest_entries;
use codex_tools::create_apply_patch_freeform_tool;
use codex_tools::create_apply_patch_json_tool;
use codex_tools::create_assign_task_tool;
use codex_tools::create_close_agent_tool_v1;
use codex_tools::create_close_agent_tool_v2;
use codex_tools::create_code_mode_tool;
use codex_tools::create_exec_command_tool;
use codex_tools::create_image_generation_tool;
use codex_tools::create_js_repl_reset_tool;
use codex_tools::create_js_repl_tool;
use codex_tools::create_list_agents_tool;
use codex_tools::create_list_dir_tool;
use codex_tools::create_list_mcp_resource_templates_tool;
use codex_tools::create_list_mcp_resources_tool;
use codex_tools::create_local_shell_tool;
use codex_tools::create_read_mcp_resource_tool;
use codex_tools::create_report_agent_job_result_tool;
use codex_tools::create_request_permissions_tool;
use codex_tools::create_request_user_input_tool;
use codex_tools::create_resume_agent_tool;
use codex_tools::create_send_input_tool_v1;
use codex_tools::create_send_message_tool;
use codex_tools::create_shell_command_tool;
use codex_tools::create_shell_tool;
use codex_tools::create_spawn_agent_tool_v1;
use codex_tools::create_spawn_agent_tool_v2;
use codex_tools::create_spawn_agents_on_csv_tool;
use codex_tools::create_test_sync_tool;
use codex_tools::create_tool_search_tool;
use codex_tools::create_tool_suggest_tool;
use codex_tools::create_update_plan_tool;
use codex_tools::create_view_image_tool;
use codex_tools::create_wait_agent_tool_v1;
use codex_tools::create_wait_agent_tool_v2;
use codex_tools::create_wait_tool;
use codex_tools::create_web_search_tool;
use codex_tools::create_write_stdin_tool;
use codex_tools::dynamic_tool_to_responses_api_tool;
use codex_tools::mcp_tool_to_responses_api_tool;
use codex_tools::request_permissions_tool_description;
use codex_tools::request_user_input_tool_description;
use codex_tools::build_tool_registry_plan;
use std::collections::HashMap;
#[cfg(test)]
pub(crate) use codex_tools::mcp_call_tool_result_output_schema;
use std::sync::Arc;
pub(crate) fn tool_user_shell_type(user_shell: &Shell) -> ToolUserShellType {
match user_shell.shell_type {
@@ -88,49 +29,6 @@ pub(crate) fn tool_user_shell_type(user_shell: &Shell) -> ToolUserShellType {
}
}
fn agent_type_description(config: &ToolsConfig) -> String {
if config.agent_type_description.is_empty() {
crate::agent::role::spawn_tool_spec::build(&std::collections::BTreeMap::new())
} else {
config.agent_type_description.clone()
}
}
fn push_tool_spec(
builder: &mut ToolRegistryBuilder,
spec: ToolSpec,
supports_parallel_tool_calls: bool,
code_mode_enabled: bool,
) {
let spec = if code_mode_enabled {
augment_tool_spec_for_code_mode(spec)
} else {
spec
};
if supports_parallel_tool_calls {
builder.push_spec_with_parallel_support(spec, /*supports_parallel_tool_calls*/ true);
} else {
builder.push_spec(spec);
}
}
/// Builds the tool registry builder while collecting tool specs for later serialization.
#[cfg(test)]
pub(crate) fn build_specs(
config: &ToolsConfig,
mcp_tools: Option<HashMap<String, rmcp::model::Tool>>,
app_tools: Option<HashMap<String, ToolInfo>>,
dynamic_tools: &[DynamicToolSpec],
) -> ToolRegistryBuilder {
build_specs_with_discoverable_tools(
config,
mcp_tools,
app_tools,
/*discoverable_tools*/ None,
dynamic_tools,
)
}
pub(crate) fn build_specs_with_discoverable_tools(
config: &ToolsConfig,
mcp_tools: Option<HashMap<String, rmcp::model::Tool>>,
@@ -168,10 +66,38 @@ pub(crate) fn build_specs_with_discoverable_tools(
use crate::tools::handlers::multi_agents_v2::SendMessageHandler as SendMessageHandlerV2;
use crate::tools::handlers::multi_agents_v2::SpawnAgentHandler as SpawnAgentHandlerV2;
use crate::tools::handlers::multi_agents_v2::WaitAgentHandler as WaitAgentHandlerV2;
use std::sync::Arc;
let mut builder = ToolRegistryBuilder::new();
let app_tool_sources = app_tools.as_ref().map(|app_tools| {
app_tools
.values()
.map(|tool| ToolRegistryPlanAppTool {
tool_name: tool.tool_name.as_str(),
tool_namespace: tool.tool_namespace.as_str(),
server_name: tool.server_name.as_str(),
connector_name: tool.connector_name.as_deref(),
connector_description: tool.connector_description.as_deref(),
})
.collect::<Vec<_>>()
});
let default_agent_type_description =
crate::agent::role::spawn_tool_spec::build(&std::collections::BTreeMap::new());
let plan = build_tool_registry_plan(
config,
ToolRegistryPlanParams {
mcp_tools: mcp_tools.as_ref(),
app_tools: app_tool_sources.as_deref(),
discoverable_tools: discoverable_tools.as_deref(),
dynamic_tools,
default_agent_type_description: &default_agent_type_description,
wait_agent_timeouts: WaitAgentTimeoutOptions {
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
},
codex_apps_mcp_server_name: CODEX_APPS_MCP_SERVER_NAME,
},
);
let shell_handler = Arc::new(ShellHandler);
let unified_exec_handler = Arc::new(UnifiedExecHandler);
let plan_handler = Arc::new(PlanHandler);
@@ -185,468 +111,130 @@ pub(crate) fn build_specs_with_discoverable_tools(
let request_user_input_handler = Arc::new(RequestUserInputHandler {
default_mode_request_user_input: config.default_mode_request_user_input,
});
let mut tool_search_handler = None;
let tool_suggest_handler = Arc::new(ToolSuggestHandler);
let code_mode_handler = Arc::new(CodeModeExecuteHandler);
let code_mode_wait_handler = Arc::new(CodeModeWaitHandler);
let js_repl_handler = Arc::new(JsReplHandler);
let js_repl_reset_handler = Arc::new(JsReplResetHandler);
let exec_permission_approvals_enabled = config.exec_permission_approvals_enabled;
if config.code_mode_enabled {
let nested_config = config.for_code_mode_nested_tools();
let (nested_specs, _) = build_specs_with_discoverable_tools(
&nested_config,
mcp_tools.clone(),
app_tools.clone(),
/*discoverable_tools*/ None,
dynamic_tools,
)
.build();
let enabled_tools = collect_code_mode_tool_definitions(
nested_specs
.iter()
.map(|configured_tool| &configured_tool.spec),
)
.into_iter()
.map(|tool| (tool.name, tool.description))
.collect::<Vec<_>>();
push_tool_spec(
&mut builder,
create_code_mode_tool(&enabled_tools, config.code_mode_only_enabled),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler(PUBLIC_TOOL_NAME, code_mode_handler);
push_tool_spec(
&mut builder,
create_wait_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler(WAIT_TOOL_NAME, code_mode_wait_handler);
}
match &config.shell_type {
ConfigShellToolType::Default => {
push_tool_spec(
&mut builder,
create_shell_tool(ShellToolOptions {
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
for spec in plan.specs {
if spec.supports_parallel_tool_calls {
builder.push_spec_with_parallel_support(
spec.spec, /*supports_parallel_tool_calls*/ true,
);
}
ConfigShellToolType::Local => {
push_tool_spec(
&mut builder,
create_local_shell_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
}
ConfigShellToolType::UnifiedExec => {
push_tool_spec(
&mut builder,
create_exec_command_tool(CommandToolOptions {
allow_login_shell: config.allow_login_shell,
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_write_stdin_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("exec_command", unified_exec_handler.clone());
builder.register_handler("write_stdin", unified_exec_handler);
}
ConfigShellToolType::Disabled => {
// Do nothing.
}
ConfigShellToolType::ShellCommand => {
push_tool_spec(
&mut builder,
create_shell_command_tool(CommandToolOptions {
allow_login_shell: config.allow_login_shell,
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
}
}
if config.shell_type != ConfigShellToolType::Disabled {
// Always register shell aliases so older prompts remain compatible.
builder.register_handler("shell", shell_handler.clone());
builder.register_handler("container.exec", shell_handler.clone());
builder.register_handler("local_shell", shell_handler);
builder.register_handler("shell_command", shell_command_handler);
}
if mcp_tools.is_some() {
push_tool_spec(
&mut builder,
create_list_mcp_resources_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_list_mcp_resource_templates_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_read_mcp_resource_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
builder.register_handler("list_mcp_resources", mcp_resource_handler.clone());
builder.register_handler("list_mcp_resource_templates", mcp_resource_handler.clone());
builder.register_handler("read_mcp_resource", mcp_resource_handler);
}
push_tool_spec(
&mut builder,
create_update_plan_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("update_plan", plan_handler);
if config.js_repl_enabled {
push_tool_spec(
&mut builder,
create_js_repl_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_js_repl_reset_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("js_repl", js_repl_handler);
builder.register_handler("js_repl_reset", js_repl_reset_handler);
}
if config.request_user_input {
push_tool_spec(
&mut builder,
create_request_user_input_tool(request_user_input_tool_description(
config.default_mode_request_user_input,
)),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler(REQUEST_USER_INPUT_TOOL_NAME, request_user_input_handler);
}
if config.request_permissions_tool_enabled {
push_tool_spec(
&mut builder,
create_request_permissions_tool(request_permissions_tool_description()),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("request_permissions", request_permissions_handler);
}
if config.search_tool
&& let Some(app_tools) = app_tools
{
let search_tool_handler = Arc::new(ToolSearchHandler::new(app_tools.clone()));
let search_app_infos = collect_tool_search_app_infos(
app_tools.values().map(|tool| ToolSearchAppSource {
server_name: &tool.server_name,
connector_name: tool.connector_name.as_deref(),
connector_description: tool.connector_description.as_deref(),
}),
CODEX_APPS_MCP_SERVER_NAME,
);
push_tool_spec(
&mut builder,
create_tool_search_tool(&search_app_infos, TOOL_SEARCH_DEFAULT_LIMIT),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
builder.register_handler(TOOL_SEARCH_TOOL_NAME, search_tool_handler);
for tool in app_tools.values() {
let alias_name =
tool_handler_key(tool.tool_name.as_str(), Some(tool.tool_namespace.as_str()));
builder.register_handler(alias_name, mcp_handler.clone());
}
}
if config.tool_suggest
&& let Some(discoverable_tools) = discoverable_tools
.as_ref()
.filter(|tools| !tools.is_empty())
{
builder.push_spec_with_parallel_support(
create_tool_suggest_tool(&collect_tool_suggest_entries(discoverable_tools)),
/*supports_parallel_tool_calls*/ true,
);
builder.register_handler(TOOL_SUGGEST_TOOL_NAME, tool_suggest_handler);
}
if let Some(apply_patch_tool_type) = &config.apply_patch_tool_type {
match apply_patch_tool_type {
ApplyPatchToolType::Freeform => {
push_tool_spec(
&mut builder,
create_apply_patch_freeform_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
ApplyPatchToolType::Function => {
push_tool_spec(
&mut builder,
create_apply_patch_json_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
}
builder.register_handler("apply_patch", apply_patch_handler);
}
if config
.experimental_supported_tools
.iter()
.any(|tool| tool == "list_dir")
{
let list_dir_handler = Arc::new(ListDirHandler);
push_tool_spec(
&mut builder,
create_list_dir_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
builder.register_handler("list_dir", list_dir_handler);
}
if config
.experimental_supported_tools
.contains(&"test_sync_tool".to_string())
{
let test_sync_handler = Arc::new(TestSyncHandler);
push_tool_spec(
&mut builder,
create_test_sync_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
builder.register_handler("test_sync_tool", test_sync_handler);
}
if let Some(web_search_tool) = create_web_search_tool(WebSearchToolOptions {
web_search_mode: config.web_search_mode,
web_search_config: config.web_search_config.as_ref(),
web_search_tool_type: config.web_search_tool_type,
}) {
push_tool_spec(
&mut builder,
web_search_tool,
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
if config.image_gen_tool {
push_tool_spec(
&mut builder,
create_image_generation_tool("png"),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
push_tool_spec(
&mut builder,
create_view_image_tool(ViewImageToolOptions {
can_request_original_image_detail: config.can_request_original_image_detail,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
builder.register_handler("view_image", view_image_handler);
if config.collab_tools {
if config.multi_agent_v2 {
let agent_type_description = agent_type_description(config);
push_tool_spec(
&mut builder,
create_spawn_agent_tool_v2(SpawnAgentToolOptions {
available_models: &config.available_models,
agent_type_description,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_send_message_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_assign_task_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_wait_agent_tool_v2(WaitAgentTimeoutOptions {
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_close_agent_tool_v2(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_list_agents_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandlerV2));
builder.register_handler("send_message", Arc::new(SendMessageHandlerV2));
builder.register_handler("assign_task", Arc::new(AssignTaskHandlerV2));
builder.register_handler("wait_agent", Arc::new(WaitAgentHandlerV2));
builder.register_handler("close_agent", Arc::new(CloseAgentHandlerV2));
builder.register_handler("list_agents", Arc::new(ListAgentsHandlerV2));
} else {
let agent_type_description = agent_type_description(config);
push_tool_spec(
&mut builder,
create_spawn_agent_tool_v1(SpawnAgentToolOptions {
available_models: &config.available_models,
agent_type_description,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_send_input_tool_v1(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_resume_agent_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("resume_agent", Arc::new(ResumeAgentHandler));
push_tool_spec(
&mut builder,
create_wait_agent_tool_v1(WaitAgentTimeoutOptions {
default_timeout_ms: DEFAULT_WAIT_TIMEOUT_MS,
min_timeout_ms: MIN_WAIT_TIMEOUT_MS,
max_timeout_ms: MAX_WAIT_TIMEOUT_MS,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
push_tool_spec(
&mut builder,
create_close_agent_tool_v1(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("spawn_agent", Arc::new(SpawnAgentHandler));
builder.register_handler("send_input", Arc::new(SendInputHandler));
builder.register_handler("wait_agent", Arc::new(WaitAgentHandler));
builder.register_handler("close_agent", Arc::new(CloseAgentHandler));
builder.push_spec(spec.spec);
}
}
if config.agent_jobs_tools {
let agent_jobs_handler = Arc::new(BatchJobHandler);
push_tool_spec(
&mut builder,
create_spawn_agents_on_csv_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("spawn_agents_on_csv", agent_jobs_handler.clone());
if config.agent_jobs_worker_tools {
push_tool_spec(
&mut builder,
create_report_agent_job_result_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler("report_agent_job_result", agent_jobs_handler);
}
}
if let Some(mcp_tools) = mcp_tools {
let mut entries: Vec<(String, rmcp::model::Tool)> = mcp_tools.into_iter().collect();
entries.sort_by(|a, b| a.0.cmp(&b.0));
for (name, tool) in entries.into_iter() {
match mcp_tool_to_responses_api_tool(name.clone(), &tool) {
Ok(converted_tool) => {
push_tool_spec(
&mut builder,
ToolSpec::Function(converted_tool),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler(name, mcp_handler.clone());
for handler in plan.handlers {
match handler.kind {
ToolHandlerKind::AgentJobs => {
builder.register_handler(handler.name, Arc::new(BatchJobHandler));
}
ToolHandlerKind::ApplyPatch => {
builder.register_handler(handler.name, apply_patch_handler.clone());
}
ToolHandlerKind::AssignTaskV2 => {
builder.register_handler(handler.name, Arc::new(AssignTaskHandlerV2));
}
ToolHandlerKind::CloseAgentV1 => {
builder.register_handler(handler.name, Arc::new(CloseAgentHandler));
}
ToolHandlerKind::CloseAgentV2 => {
builder.register_handler(handler.name, Arc::new(CloseAgentHandlerV2));
}
ToolHandlerKind::CodeModeExecute => {
builder.register_handler(handler.name, code_mode_handler.clone());
}
ToolHandlerKind::CodeModeWait => {
builder.register_handler(handler.name, code_mode_wait_handler.clone());
}
ToolHandlerKind::DynamicTool => {
builder.register_handler(handler.name, dynamic_tool_handler.clone());
}
ToolHandlerKind::JsRepl => {
builder.register_handler(handler.name, js_repl_handler.clone());
}
ToolHandlerKind::JsReplReset => {
builder.register_handler(handler.name, js_repl_reset_handler.clone());
}
ToolHandlerKind::ListAgentsV2 => {
builder.register_handler(handler.name, Arc::new(ListAgentsHandlerV2));
}
ToolHandlerKind::ListDir => {
builder.register_handler(handler.name, Arc::new(ListDirHandler));
}
ToolHandlerKind::Mcp => {
builder.register_handler(handler.name, mcp_handler.clone());
}
ToolHandlerKind::McpResource => {
builder.register_handler(handler.name, mcp_resource_handler.clone());
}
ToolHandlerKind::Plan => {
builder.register_handler(handler.name, plan_handler.clone());
}
ToolHandlerKind::RequestPermissions => {
builder.register_handler(handler.name, request_permissions_handler.clone());
}
ToolHandlerKind::RequestUserInput => {
builder.register_handler(handler.name, request_user_input_handler.clone());
}
ToolHandlerKind::ResumeAgentV1 => {
builder.register_handler(handler.name, Arc::new(ResumeAgentHandler));
}
ToolHandlerKind::SendInputV1 => {
builder.register_handler(handler.name, Arc::new(SendInputHandler));
}
ToolHandlerKind::SendMessageV2 => {
builder.register_handler(handler.name, Arc::new(SendMessageHandlerV2));
}
ToolHandlerKind::Shell => {
builder.register_handler(handler.name, shell_handler.clone());
}
ToolHandlerKind::ShellCommand => {
builder.register_handler(handler.name, shell_command_handler.clone());
}
ToolHandlerKind::SpawnAgentV1 => {
builder.register_handler(handler.name, Arc::new(SpawnAgentHandler));
}
ToolHandlerKind::SpawnAgentV2 => {
builder.register_handler(handler.name, Arc::new(SpawnAgentHandlerV2));
}
ToolHandlerKind::TestSync => {
builder.register_handler(handler.name, Arc::new(TestSyncHandler));
}
ToolHandlerKind::ToolSearch => {
if tool_search_handler.is_none() {
tool_search_handler = app_tools
.as_ref()
.map(|app_tools| Arc::new(ToolSearchHandler::new(app_tools.clone())));
}
Err(e) => {
tracing::error!("Failed to convert {name:?} MCP tool to OpenAI tool: {e:?}");
if let Some(tool_search_handler) = tool_search_handler.as_ref() {
builder.register_handler(handler.name, tool_search_handler.clone());
}
}
ToolHandlerKind::ToolSuggest => {
builder.register_handler(handler.name, tool_suggest_handler.clone());
}
ToolHandlerKind::UnifiedExec => {
builder.register_handler(handler.name, unified_exec_handler.clone());
}
ToolHandlerKind::ViewImage => {
builder.register_handler(handler.name, view_image_handler.clone());
}
ToolHandlerKind::WaitAgentV1 => {
builder.register_handler(handler.name, Arc::new(WaitAgentHandler));
}
ToolHandlerKind::WaitAgentV2 => {
builder.register_handler(handler.name, Arc::new(WaitAgentHandlerV2));
}
}
}
if !dynamic_tools.is_empty() {
for tool in dynamic_tools {
match dynamic_tool_to_responses_api_tool(tool) {
Ok(converted_tool) => {
push_tool_spec(
&mut builder,
ToolSpec::Function(converted_tool),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
builder.register_handler(tool.name.clone(), dynamic_tool_handler.clone());
}
Err(e) => {
tracing::error!(
"Failed to convert dynamic tool {:?} to OpenAI tool: {e:?}",
tool.name
);
}
}
}
}
builder
}
#[cfg(test)]
#[path = "spec_tests.rs"]
mod tests;
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -2,7 +2,7 @@ use crate::config::Config;
use crate::config::ConfigToml;
use crate::config::edit::ConfigEditsBuilder;
use crate::config::profile::ConfigProfile;
use crate::config::types::WindowsSandboxModeToml;
use codex_config::types::WindowsSandboxModeToml;
use codex_features::Feature;
use codex_features::Features;
use codex_features::FeaturesToml;
+1 -1
View File
@@ -1,5 +1,5 @@
use super::*;
use crate::config::types::WindowsToml;
use codex_config::types::WindowsToml;
use codex_features::Features;
use codex_features::FeaturesToml;
use pretty_assertions::assert_eq;
+2 -2
View File
@@ -3,8 +3,8 @@
use anyhow::Result;
use base64::Engine;
use base64::engine::general_purpose::STANDARD as BASE64_STANDARD;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_features::Feature;
use codex_protocol::dynamic_tools::DynamicToolCallOutputContentItem;
use codex_protocol::dynamic_tools::DynamicToolResponse;
+1 -1
View File
@@ -1,5 +1,5 @@
use anyhow::Result;
use codex_core::config::types::Personality;
use codex_config::types::Personality;
use codex_core::models_manager::manager::RefreshStrategy;
use codex_features::Feature;
use codex_login::CodexAuth;
@@ -4,7 +4,7 @@ use std::fs;
use std::sync::Arc;
use anyhow::Result;
use codex_core::config::types::Personality;
use codex_config::types::Personality;
use codex_features::Feature;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::EventMsg;
+1 -1
View File
@@ -1,4 +1,4 @@
use codex_core::config::types::Personality;
use codex_config::types::Personality;
use codex_core::models_manager::manager::ModelsManager;
use codex_core::models_manager::manager::RefreshStrategy;
use codex_features::Feature;
+2 -2
View File
@@ -9,8 +9,8 @@ use std::time::Duration;
use std::time::SystemTime;
use std::time::UNIX_EPOCH;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_core::models_manager::manager::RefreshStrategy;
use codex_login::CodexAuth;
+2 -2
View File
@@ -1,6 +1,6 @@
use anyhow::Result;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_features::Feature;
use codex_protocol::ThreadId;
use codex_protocol::dynamic_tools::DynamicToolSpec;
+2 -2
View File
@@ -2,9 +2,9 @@
#![allow(clippy::unwrap_used, clippy::expect_used)]
use anyhow::Result;
use codex_config::types::ToolSuggestDiscoverable;
use codex_config::types::ToolSuggestDiscoverableType;
use codex_core::config::Config;
use codex_core::config::types::ToolSuggestDiscoverable;
use codex_core::config::types::ToolSuggestDiscoverableType;
use codex_features::Feature;
use codex_login::CodexAuth;
use codex_protocol::openai_models::ModelsResponse;
+6 -6
View File
@@ -3,8 +3,8 @@
use anyhow::Context;
use anyhow::Result;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerTransportConfig;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerTransportConfig;
use codex_protocol::protocol::AskForApproval;
use codex_protocol::protocol::EventMsg;
use codex_protocol::protocol::Op;
@@ -354,8 +354,8 @@ async fn mcp_tool_call_output_exceeds_limit_truncated_for_model() -> Result<()>
let mut servers = config.mcp_servers.get().clone();
servers.insert(
server_name.to_string(),
codex_core::config::types::McpServerConfig {
transport: codex_core::config::types::McpServerTransportConfig::Stdio {
codex_config::types::McpServerConfig {
transport: codex_config::types::McpServerTransportConfig::Stdio {
command: rmcp_test_server_bin,
args: Vec::new(),
env: None,
@@ -719,8 +719,8 @@ async fn mcp_tool_call_output_not_truncated_with_custom_limit() -> Result<()> {
let mut servers = config.mcp_servers.get().clone();
servers.insert(
server_name.to_string(),
codex_core::config::types::McpServerConfig {
transport: codex_core::config::types::McpServerTransportConfig::Stdio {
codex_config::types::McpServerConfig {
transport: codex_config::types::McpServerTransportConfig::Stdio {
command: rmcp_test_server_bin,
args: Vec::new(),
env: None,
+1
View File
@@ -17,6 +17,7 @@ workspace = true
[target.'cfg(target_os = "linux")'.dependencies]
clap = { workspace = true, features = ["derive"] }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-protocol = { workspace = true }
codex-sandboxing = { workspace = true }
@@ -1,6 +1,6 @@
#![cfg(target_os = "linux")]
#![allow(clippy::unwrap_used)]
use codex_core::config::types::ShellEnvironmentPolicy;
use codex_config::types::ShellEnvironmentPolicy;
use codex_core::error::CodexErr;
use codex_core::error::Result;
use codex_core::error::SandboxErr;
@@ -1,7 +1,7 @@
#![cfg(target_os = "linux")]
#![allow(clippy::unwrap_used)]
use codex_core::config::types::ShellEnvironmentPolicy;
use codex_config::types::ShellEnvironmentPolicy;
use codex_core::exec_env::create_env;
use codex_protocol::protocol::SandboxPolicy;
use pretty_assertions::assert_eq;
+1
View File
@@ -18,6 +18,7 @@ workspace = true
[dependencies]
anyhow = { workspace = true }
codex-arg0 = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-exec-server = { workspace = true }
codex-features = { workspace = true }
+1 -1
View File
@@ -181,8 +181,8 @@ pub async fn run_main(
#[cfg(test)]
mod tests {
use super::*;
use codex_config::types::OtelExporterKind;
use codex_core::config::ConfigBuilder;
use codex_core::config::types::OtelExporterKind;
use pretty_assertions::assert_eq;
use std::collections::HashMap;
use tempfile::TempDir;
+8
View File
@@ -18,6 +18,8 @@ mod responses_api;
mod tool_config;
mod tool_definition;
mod tool_discovery;
mod tool_registry_plan;
mod tool_registry_plan_types;
mod tool_spec;
mod tool_suggest;
mod utility_tool;
@@ -107,6 +109,12 @@ pub use tool_discovery::collect_tool_suggest_entries;
pub use tool_discovery::create_tool_search_tool;
pub use tool_discovery::create_tool_suggest_tool;
pub use tool_discovery::filter_tool_suggest_discoverable_tools_for_client;
pub use tool_registry_plan::build_tool_registry_plan;
pub use tool_registry_plan_types::ToolHandlerKind;
pub use tool_registry_plan_types::ToolHandlerSpec;
pub use tool_registry_plan_types::ToolRegistryPlan;
pub use tool_registry_plan_types::ToolRegistryPlanAppTool;
pub use tool_registry_plan_types::ToolRegistryPlanParams;
pub use tool_spec::ConfiguredToolSpec;
pub use tool_spec::ResponsesApiWebSearchFilters;
pub use tool_spec::ResponsesApiWebSearchUserLocation;
+492
View File
@@ -0,0 +1,492 @@
use crate::CommandToolOptions;
use crate::REQUEST_USER_INPUT_TOOL_NAME;
use crate::ShellToolOptions;
use crate::SpawnAgentToolOptions;
use crate::TOOL_SEARCH_DEFAULT_LIMIT;
use crate::TOOL_SEARCH_TOOL_NAME;
use crate::TOOL_SUGGEST_TOOL_NAME;
use crate::ToolHandlerKind;
use crate::ToolRegistryPlan;
use crate::ToolRegistryPlanParams;
use crate::ToolSearchAppSource;
use crate::ToolSpec;
use crate::ToolsConfig;
use crate::ViewImageToolOptions;
use crate::WebSearchToolOptions;
use crate::collect_code_mode_tool_definitions;
use crate::collect_tool_search_app_infos;
use crate::collect_tool_suggest_entries;
use crate::create_apply_patch_freeform_tool;
use crate::create_apply_patch_json_tool;
use crate::create_assign_task_tool;
use crate::create_close_agent_tool_v1;
use crate::create_close_agent_tool_v2;
use crate::create_code_mode_tool;
use crate::create_exec_command_tool;
use crate::create_image_generation_tool;
use crate::create_js_repl_reset_tool;
use crate::create_js_repl_tool;
use crate::create_list_agents_tool;
use crate::create_list_dir_tool;
use crate::create_list_mcp_resource_templates_tool;
use crate::create_list_mcp_resources_tool;
use crate::create_local_shell_tool;
use crate::create_read_mcp_resource_tool;
use crate::create_report_agent_job_result_tool;
use crate::create_request_permissions_tool;
use crate::create_request_user_input_tool;
use crate::create_resume_agent_tool;
use crate::create_send_input_tool_v1;
use crate::create_send_message_tool;
use crate::create_shell_command_tool;
use crate::create_shell_tool;
use crate::create_spawn_agent_tool_v1;
use crate::create_spawn_agent_tool_v2;
use crate::create_spawn_agents_on_csv_tool;
use crate::create_test_sync_tool;
use crate::create_tool_search_tool;
use crate::create_tool_suggest_tool;
use crate::create_update_plan_tool;
use crate::create_view_image_tool;
use crate::create_wait_agent_tool_v1;
use crate::create_wait_agent_tool_v2;
use crate::create_wait_tool;
use crate::create_web_search_tool;
use crate::create_write_stdin_tool;
use crate::dynamic_tool_to_responses_api_tool;
use crate::mcp_tool_to_responses_api_tool;
use crate::request_permissions_tool_description;
use crate::request_user_input_tool_description;
use crate::tool_registry_plan_types::agent_type_description;
use codex_protocol::openai_models::ApplyPatchToolType;
use codex_protocol::openai_models::ConfigShellToolType;
use rmcp::model::Tool as McpTool;
pub fn build_tool_registry_plan(
config: &ToolsConfig,
params: ToolRegistryPlanParams<'_>,
) -> ToolRegistryPlan {
let mut plan = ToolRegistryPlan::new();
let exec_permission_approvals_enabled = config.exec_permission_approvals_enabled;
if config.code_mode_enabled {
let nested_config = config.for_code_mode_nested_tools();
let nested_plan = build_tool_registry_plan(
&nested_config,
ToolRegistryPlanParams {
discoverable_tools: None,
..params
},
);
let enabled_tools = collect_code_mode_tool_definitions(
nested_plan
.specs
.iter()
.map(|configured_tool| &configured_tool.spec),
)
.into_iter()
.map(|tool| (tool.name, tool.description))
.collect::<Vec<_>>();
plan.push_spec(
create_code_mode_tool(&enabled_tools, config.code_mode_only_enabled),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler(
codex_code_mode::PUBLIC_TOOL_NAME,
ToolHandlerKind::CodeModeExecute,
);
plan.push_spec(
create_wait_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler(
codex_code_mode::WAIT_TOOL_NAME,
ToolHandlerKind::CodeModeWait,
);
}
match &config.shell_type {
ConfigShellToolType::Default => {
plan.push_spec(
create_shell_tool(ShellToolOptions {
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
}
ConfigShellToolType::Local => {
plan.push_spec(
create_local_shell_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
}
ConfigShellToolType::UnifiedExec => {
plan.push_spec(
create_exec_command_tool(CommandToolOptions {
allow_login_shell: config.allow_login_shell,
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.push_spec(
create_write_stdin_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("exec_command", ToolHandlerKind::UnifiedExec);
plan.register_handler("write_stdin", ToolHandlerKind::UnifiedExec);
}
ConfigShellToolType::Disabled => {}
ConfigShellToolType::ShellCommand => {
plan.push_spec(
create_shell_command_tool(CommandToolOptions {
allow_login_shell: config.allow_login_shell,
exec_permission_approvals_enabled,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
}
}
if config.shell_type != ConfigShellToolType::Disabled {
plan.register_handler("shell", ToolHandlerKind::Shell);
plan.register_handler("container.exec", ToolHandlerKind::Shell);
plan.register_handler("local_shell", ToolHandlerKind::Shell);
plan.register_handler("shell_command", ToolHandlerKind::ShellCommand);
}
if params.mcp_tools.is_some() {
plan.push_spec(
create_list_mcp_resources_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.push_spec(
create_list_mcp_resource_templates_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.push_spec(
create_read_mcp_resource_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.register_handler("list_mcp_resources", ToolHandlerKind::McpResource);
plan.register_handler("list_mcp_resource_templates", ToolHandlerKind::McpResource);
plan.register_handler("read_mcp_resource", ToolHandlerKind::McpResource);
}
plan.push_spec(
create_update_plan_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("update_plan", ToolHandlerKind::Plan);
if config.js_repl_enabled {
plan.push_spec(
create_js_repl_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_js_repl_reset_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("js_repl", ToolHandlerKind::JsRepl);
plan.register_handler("js_repl_reset", ToolHandlerKind::JsReplReset);
}
if config.request_user_input {
plan.push_spec(
create_request_user_input_tool(request_user_input_tool_description(
config.default_mode_request_user_input,
)),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler(
REQUEST_USER_INPUT_TOOL_NAME,
ToolHandlerKind::RequestUserInput,
);
}
if config.request_permissions_tool_enabled {
plan.push_spec(
create_request_permissions_tool(request_permissions_tool_description()),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("request_permissions", ToolHandlerKind::RequestPermissions);
}
if config.search_tool
&& let Some(app_tools) = params.app_tools
{
let search_app_infos = collect_tool_search_app_infos(
app_tools.iter().map(|tool| ToolSearchAppSource {
server_name: tool.server_name,
connector_name: tool.connector_name,
connector_description: tool.connector_description,
}),
params.codex_apps_mcp_server_name,
);
plan.push_spec(
create_tool_search_tool(&search_app_infos, TOOL_SEARCH_DEFAULT_LIMIT),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.register_handler(TOOL_SEARCH_TOOL_NAME, ToolHandlerKind::ToolSearch);
for tool in app_tools {
plan.register_handler(
format!("{}:{}", tool.tool_namespace, tool.tool_name),
ToolHandlerKind::Mcp,
);
}
}
if config.tool_suggest
&& let Some(discoverable_tools) =
params.discoverable_tools.filter(|tools| !tools.is_empty())
{
plan.push_spec(
create_tool_suggest_tool(&collect_tool_suggest_entries(discoverable_tools)),
/*supports_parallel_tool_calls*/ true,
/*code_mode_enabled*/ false,
);
plan.register_handler(TOOL_SUGGEST_TOOL_NAME, ToolHandlerKind::ToolSuggest);
}
if let Some(apply_patch_tool_type) = &config.apply_patch_tool_type {
match apply_patch_tool_type {
ApplyPatchToolType::Freeform => {
plan.push_spec(
create_apply_patch_freeform_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
ApplyPatchToolType::Function => {
plan.push_spec(
create_apply_patch_json_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
}
plan.register_handler("apply_patch", ToolHandlerKind::ApplyPatch);
}
if config
.experimental_supported_tools
.iter()
.any(|tool| tool == "list_dir")
{
plan.push_spec(
create_list_dir_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.register_handler("list_dir", ToolHandlerKind::ListDir);
}
if config
.experimental_supported_tools
.iter()
.any(|tool| tool == "test_sync_tool")
{
plan.push_spec(
create_test_sync_tool(),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.register_handler("test_sync_tool", ToolHandlerKind::TestSync);
}
if let Some(web_search_tool) = create_web_search_tool(WebSearchToolOptions {
web_search_mode: config.web_search_mode,
web_search_config: config.web_search_config.as_ref(),
web_search_tool_type: config.web_search_tool_type,
}) {
plan.push_spec(
web_search_tool,
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
if config.image_gen_tool {
plan.push_spec(
create_image_generation_tool("png"),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
}
plan.push_spec(
create_view_image_tool(ViewImageToolOptions {
can_request_original_image_detail: config.can_request_original_image_detail,
}),
/*supports_parallel_tool_calls*/ true,
config.code_mode_enabled,
);
plan.register_handler("view_image", ToolHandlerKind::ViewImage);
if config.collab_tools {
if config.multi_agent_v2 {
let agent_type_description =
agent_type_description(config, params.default_agent_type_description);
plan.push_spec(
create_spawn_agent_tool_v2(SpawnAgentToolOptions {
available_models: &config.available_models,
agent_type_description,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_send_message_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_assign_task_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_wait_agent_tool_v2(params.wait_agent_timeouts),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_close_agent_tool_v2(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_list_agents_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("spawn_agent", ToolHandlerKind::SpawnAgentV2);
plan.register_handler("send_message", ToolHandlerKind::SendMessageV2);
plan.register_handler("assign_task", ToolHandlerKind::AssignTaskV2);
plan.register_handler("wait_agent", ToolHandlerKind::WaitAgentV2);
plan.register_handler("close_agent", ToolHandlerKind::CloseAgentV2);
plan.register_handler("list_agents", ToolHandlerKind::ListAgentsV2);
} else {
let agent_type_description =
agent_type_description(config, params.default_agent_type_description);
plan.push_spec(
create_spawn_agent_tool_v1(SpawnAgentToolOptions {
available_models: &config.available_models,
agent_type_description,
}),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_send_input_tool_v1(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_resume_agent_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("resume_agent", ToolHandlerKind::ResumeAgentV1);
plan.push_spec(
create_wait_agent_tool_v1(params.wait_agent_timeouts),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.push_spec(
create_close_agent_tool_v1(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("spawn_agent", ToolHandlerKind::SpawnAgentV1);
plan.register_handler("send_input", ToolHandlerKind::SendInputV1);
plan.register_handler("wait_agent", ToolHandlerKind::WaitAgentV1);
plan.register_handler("close_agent", ToolHandlerKind::CloseAgentV1);
}
}
if config.agent_jobs_tools {
plan.push_spec(
create_spawn_agents_on_csv_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("spawn_agents_on_csv", ToolHandlerKind::AgentJobs);
if config.agent_jobs_worker_tools {
plan.push_spec(
create_report_agent_job_result_tool(),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler("report_agent_job_result", ToolHandlerKind::AgentJobs);
}
}
if let Some(mcp_tools) = params.mcp_tools {
let mut entries: Vec<(String, &McpTool)> = mcp_tools
.iter()
.map(|(name, tool)| (name.clone(), tool))
.collect();
entries.sort_by(|left, right| left.0.cmp(&right.0));
for (name, tool) in entries {
match mcp_tool_to_responses_api_tool(name.clone(), tool) {
Ok(converted_tool) => {
plan.push_spec(
ToolSpec::Function(converted_tool),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler(name, ToolHandlerKind::Mcp);
}
Err(error) => {
tracing::error!(
"Failed to convert {name:?} MCP tool to OpenAI tool: {error:?}"
);
}
}
}
}
for tool in params.dynamic_tools {
match dynamic_tool_to_responses_api_tool(tool) {
Ok(converted_tool) => {
plan.push_spec(
ToolSpec::Function(converted_tool),
/*supports_parallel_tool_calls*/ false,
config.code_mode_enabled,
);
plan.register_handler(tool.name.clone(), ToolHandlerKind::DynamicTool);
}
Err(error) => {
tracing::error!(
"Failed to convert dynamic tool {:?} to OpenAI tool: {error:?}",
tool.name
);
}
}
}
plan
}
#[cfg(test)]
#[path = "tool_registry_plan_tests.rs"]
mod tests;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,118 @@
use crate::ConfiguredToolSpec;
use crate::DiscoverableTool;
use crate::ToolSpec;
use crate::ToolsConfig;
use crate::WaitAgentTimeoutOptions;
use crate::augment_tool_spec_for_code_mode;
use codex_protocol::dynamic_tools::DynamicToolSpec;
use rmcp::model::Tool as McpTool;
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ToolHandlerKind {
AgentJobs,
ApplyPatch,
AssignTaskV2,
CloseAgentV1,
CloseAgentV2,
CodeModeExecute,
CodeModeWait,
DynamicTool,
JsRepl,
JsReplReset,
ListAgentsV2,
ListDir,
Mcp,
McpResource,
Plan,
RequestPermissions,
RequestUserInput,
ResumeAgentV1,
SendInputV1,
SendMessageV2,
Shell,
ShellCommand,
SpawnAgentV1,
SpawnAgentV2,
TestSync,
ToolSearch,
ToolSuggest,
UnifiedExec,
ViewImage,
WaitAgentV1,
WaitAgentV2,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ToolHandlerSpec {
pub name: String,
pub kind: ToolHandlerKind,
}
#[derive(Debug, Clone, PartialEq)]
pub struct ToolRegistryPlan {
pub specs: Vec<ConfiguredToolSpec>,
pub handlers: Vec<ToolHandlerSpec>,
}
#[derive(Debug, Clone, Copy)]
pub struct ToolRegistryPlanParams<'a> {
pub mcp_tools: Option<&'a HashMap<String, McpTool>>,
pub app_tools: Option<&'a [ToolRegistryPlanAppTool<'a>]>,
pub discoverable_tools: Option<&'a [DiscoverableTool]>,
pub dynamic_tools: &'a [DynamicToolSpec],
pub default_agent_type_description: &'a str,
pub wait_agent_timeouts: WaitAgentTimeoutOptions,
pub codex_apps_mcp_server_name: &'a str,
}
#[derive(Debug, Clone, Copy)]
pub struct ToolRegistryPlanAppTool<'a> {
pub tool_name: &'a str,
pub tool_namespace: &'a str,
pub server_name: &'a str,
pub connector_name: Option<&'a str>,
pub connector_description: Option<&'a str>,
}
impl ToolRegistryPlan {
pub(crate) fn new() -> Self {
Self {
specs: Vec::new(),
handlers: Vec::new(),
}
}
pub(crate) fn push_spec(
&mut self,
spec: ToolSpec,
supports_parallel_tool_calls: bool,
code_mode_enabled: bool,
) {
let spec = if code_mode_enabled {
augment_tool_spec_for_code_mode(spec)
} else {
spec
};
self.specs
.push(ConfiguredToolSpec::new(spec, supports_parallel_tool_calls));
}
pub(crate) fn register_handler(&mut self, name: impl Into<String>, kind: ToolHandlerKind) {
self.handlers.push(ToolHandlerSpec {
name: name.into(),
kind,
});
}
}
pub(crate) fn agent_type_description(
config: &ToolsConfig,
default_agent_type_description: &str,
) -> String {
if config.agent_type_description.is_empty() {
default_agent_type_description.to_string()
} else {
config.agent_type_description.clone()
}
}
+1
View File
@@ -31,6 +31,7 @@ codex-app-server-protocol = { workspace = true }
codex-arg0 = { workspace = true }
codex-chatgpt = { workspace = true }
codex-cloud-requirements = { workspace = true }
codex-config = { workspace = true }
codex-core = { workspace = true }
codex-features = { workspace = true }
codex-feedback = { workspace = true }
+3 -3
View File
@@ -82,13 +82,13 @@ use codex_app_server_protocol::ThreadRollbackResponse;
use codex_app_server_protocol::Turn;
use codex_app_server_protocol::TurnError as AppServerTurnError;
use codex_app_server_protocol::TurnStatus;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::ModelAvailabilityNuxConfig;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
use codex_core::config::edit::ConfigEdit;
use codex_core::config::edit::ConfigEditsBuilder;
use codex_core::config::types::ApprovalsReviewer;
use codex_core::config::types::ModelAvailabilityNuxConfig;
use codex_core::config_loader::ConfigLayerStackOrdering;
use codex_core::message_history;
use codex_core::models_manager::collaboration_mode_presets::CollaborationModesConfig;
@@ -6188,9 +6188,9 @@ mod tests {
use codex_app_server_protocol::TurnStartedNotification;
use codex_app_server_protocol::TurnStatus;
use codex_app_server_protocol::UserInput as AppServerUserInput;
use codex_config::types::ModelAvailabilityNuxConfig;
use codex_core::config::ConfigBuilder;
use codex_core::config::ConfigOverrides;
use codex_core::config::types::ModelAvailabilityNuxConfig;
use codex_otel::SessionTelemetry;
use codex_protocol::ThreadId;
use codex_protocol::config_types::CollaborationMode;
+1 -1
View File
@@ -1,6 +1,6 @@
use std::path::PathBuf;
use codex_core::config::types::ApprovalsReviewer;
use codex_config::types::ApprovalsReviewer;
use codex_protocol::approvals::ElicitationAction;
use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::Personality;
+1 -1
View File
@@ -31,7 +31,7 @@ use crate::bottom_pane::StatusLineItem;
use crate::bottom_pane::TerminalTitleItem;
use crate::history_cell::HistoryCell;
use codex_core::config::types::ApprovalsReviewer;
use codex_config::types::ApprovalsReviewer;
use codex_features::Feature;
use codex_protocol::config_types::CollaborationModeMask;
use codex_protocol::config_types::Personality;
+3 -3
View File
@@ -92,12 +92,12 @@ use codex_app_server_protocol::TurnCompletedNotification;
use codex_app_server_protocol::TurnPlanStepStatus;
use codex_app_server_protocol::TurnStatus;
use codex_chatgpt::connectors;
use codex_config::types::ApprovalsReviewer;
use codex_config::types::Notifications;
use codex_config::types::WindowsSandboxModeToml;
use codex_core::config::Config;
use codex_core::config::Constrained;
use codex_core::config::ConstraintResult;
use codex_core::config::types::ApprovalsReviewer;
use codex_core::config::types::Notifications;
use codex_core::config::types::WindowsSandboxModeToml;
use codex_core::config_loader::ConfigLayerStackOrdering;
use codex_core::find_thread_name_by_id;
use codex_core::plugins::PluginsManager;
+4 -4
View File
@@ -79,14 +79,14 @@ pub(super) use codex_app_server_protocol::TurnError as AppServerTurnError;
pub(super) use codex_app_server_protocol::TurnStartedNotification;
pub(super) use codex_app_server_protocol::TurnStatus as AppServerTurnStatus;
pub(super) use codex_app_server_protocol::UserInput as AppServerUserInput;
pub(super) use codex_core::config::ApprovalsReviewer;
pub(super) use codex_config::types::ApprovalsReviewer;
pub(super) use codex_config::types::Notifications;
#[cfg(target_os = "windows")]
pub(super) use codex_config::types::WindowsSandboxModeToml;
pub(super) use codex_core::config::Config;
pub(super) use codex_core::config::ConfigBuilder;
pub(super) use codex_core::config::Constrained;
pub(super) use codex_core::config::ConstraintError;
pub(super) use codex_core::config::types::Notifications;
#[cfg(target_os = "windows")]
pub(super) use codex_core::config::types::WindowsSandboxModeToml;
pub(super) use codex_core::config_loader::AppRequirementToml;
pub(super) use codex_core::config_loader::AppsRequirementsToml;
pub(super) use codex_core::config_loader::ConfigLayerStack;
+3 -3
View File
@@ -40,8 +40,8 @@ use crate::wrapping::adaptive_wrap_line;
use crate::wrapping::adaptive_wrap_lines;
use base64::Engine;
use codex_app_server_protocol::McpServerStatus;
use codex_config::types::McpServerTransportConfig;
use codex_core::config::Config;
use codex_core::config::types::McpServerTransportConfig;
#[cfg(test)]
use codex_core::mcp::McpManager;
#[cfg(test)]
@@ -2768,10 +2768,10 @@ mod tests {
use crate::exec_cell::CommandOutput;
use crate::exec_cell::ExecCall;
use crate::exec_cell::ExecCell;
use codex_config::types::McpServerConfig;
use codex_config::types::McpServerDisabledReason;
use codex_core::config::Config;
use codex_core::config::ConfigBuilder;
use codex_core::config::types::McpServerConfig;
use codex_core::config::types::McpServerDisabledReason;
use codex_otel::RuntimeMetricTotals;
use codex_otel::RuntimeMetricsSummary;
use codex_protocol::ThreadId;
+2 -2
View File
@@ -5,7 +5,7 @@ use std::env;
use std::io;
use bel::BelBackend;
use codex_core::config::types::NotificationMethod;
use codex_config::types::NotificationMethod;
use osc9::Osc9Backend;
#[derive(Debug)]
@@ -74,7 +74,7 @@ fn supports_osc9() -> bool {
#[cfg(test)]
mod tests {
use super::detect_backend;
use codex_core::config::types::NotificationMethod;
use codex_config::types::NotificationMethod;
use serial_test::serial;
use std::ffi::OsString;
+1 -1
View File
@@ -45,7 +45,7 @@ use crate::tui::event_stream::EventBroker;
use crate::tui::event_stream::TuiEventStream;
#[cfg(unix)]
use crate::tui::job_control::SuspendContext;
use codex_core::config::types::NotificationMethod;
use codex_config::types::NotificationMethod;
mod event_stream;
mod frame_rate_limiter;