From a101766ff4c248f3793acfe82cbf60016f5e2d75 Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 6 May 2026 18:34:46 -0700 Subject: [PATCH 1/6] Remove string-keyed MCP tool maps --- codex-rs/codex-mcp/src/codex_apps.rs | 11 - codex-rs/codex-mcp/src/connection_manager.rs | 17 +- .../codex-mcp/src/connection_manager_tests.rs | 140 ++++---- codex-rs/codex-mcp/src/lib.rs | 1 - codex-rs/codex-mcp/src/mcp/mod.rs | 2 +- codex-rs/codex-mcp/src/tools.rs | 30 +- codex-rs/core/src/connectors.rs | 8 +- codex-rs/core/src/connectors_tests.rs | 124 +++---- codex-rs/core/src/mcp_tool_call.rs | 4 +- codex-rs/core/src/mcp_tool_exposure.rs | 32 +- codex-rs/core/src/mcp_tool_exposure_test.rs | 129 ++++---- codex-rs/core/src/plugins/injection.rs | 5 +- codex-rs/core/src/session/turn.rs | 6 +- .../core/src/tools/handlers/tool_search.rs | 31 +- codex-rs/core/src/tools/router.rs | 5 +- codex-rs/core/src/tools/spec.rs | 27 +- codex-rs/core/src/tools/spec_tests.rs | 305 ++++++++---------- codex-rs/core/src/tools/tool_search_entry.rs | 7 +- codex-rs/core/src/unavailable_tool.rs | 11 +- 19 files changed, 434 insertions(+), 461 deletions(-) diff --git a/codex-rs/codex-mcp/src/codex_apps.rs b/codex-rs/codex-mcp/src/codex_apps.rs index 0a7981fb0d5f..81643e666560 100644 --- a/codex-rs/codex-mcp/src/codex_apps.rs +++ b/codex-rs/codex-mcp/src/codex_apps.rs @@ -5,7 +5,6 @@ //! connector allow-list filtering, and the normalization that turns app //! connector/tool metadata into model-visible MCP callable names. -use std::collections::HashMap; use std::path::PathBuf; use std::time::Instant; @@ -38,16 +37,6 @@ pub fn codex_apps_tools_cache_key(auth: Option<&CodexAuth>) -> CodexAppsToolsCac } } -pub fn filter_non_codex_apps_mcp_tools_only( - mcp_tools: &HashMap, -) -> HashMap { - mcp_tools - .iter() - .filter(|(_, tool)| tool.server_name != CODEX_APPS_MCP_SERVER_NAME) - .map(|(name, tool)| (name.clone(), tool.clone())) - .collect() -} - #[derive(Clone)] pub(crate) struct CodexAppsToolsCacheContext { pub(crate) codex_home: PathBuf, diff --git a/codex-rs/codex-mcp/src/connection_manager.rs b/codex-rs/codex-mcp/src/connection_manager.rs index f93ac5e089fd..5a05092522c3 100644 --- a/codex-rs/codex-mcp/src/connection_manager.rs +++ b/codex-rs/codex-mcp/src/connection_manager.rs @@ -31,7 +31,7 @@ use crate::runtime::McpRuntimeEnvironment; use crate::runtime::emit_duration; use crate::tools::ToolInfo; use crate::tools::filter_tools; -use crate::tools::qualify_tools; +use crate::tools::normalize_tools_for_model; use crate::tools::tool_with_model_visible_input_schema; use anyhow::Context; use anyhow::Result; @@ -337,10 +337,9 @@ impl McpConnectionManager { failures } - /// Returns a single map that contains all tools. Each key is the - /// fully-qualified name for the tool. + /// Returns all tools with model-visible names normalized. #[instrument(level = "trace", skip_all)] - pub async fn list_all_tools(&self) -> HashMap { + pub async fn list_all_tools(&self) -> Vec { let mut tools = Vec::new(); for managed_client in self.clients.values() { let Some(server_tools) = managed_client.listed_tools().await else { @@ -348,15 +347,15 @@ impl McpConnectionManager { }; tools.extend(server_tools); } - qualify_tools(tools) + normalize_tools_for_model(tools) } /// Force-refresh codex apps tools by bypassing the in-process cache. /// /// On success, the refreshed tools replace the cache contents and the - /// latest filtered tool map is returned directly to the caller. On + /// latest filtered tools are returned directly to the caller. On /// failure, the existing cache remains unchanged. - pub async fn hard_refresh_codex_apps_tools_cache(&self) -> Result> { + pub async fn hard_refresh_codex_apps_tools_cache(&self) -> Result> { let managed_client = self .clients .get(CODEX_APPS_MCP_SERVER_NAME) @@ -399,7 +398,7 @@ impl McpConnectionManager { tool.tool = tool_with_model_visible_input_schema(&tool.tool); tool }); - Ok(qualify_tools(tools)) + Ok(normalize_tools_for_model(tools)) } /// Returns a single map that contains all resources. Each key is the @@ -638,7 +637,7 @@ impl McpConnectionManager { pub async fn resolve_tool_info(&self, tool_name: &ToolName) -> Option { let all_tools = self.list_all_tools().await; all_tools - .into_values() + .into_iter() .find(|tool| tool.canonical_tool_name() == *tool_name) } diff --git a/codex-rs/codex-mcp/src/connection_manager_tests.rs b/codex-rs/codex-mcp/src/connection_manager_tests.rs index f2dc85cde043..5c430bd8e56d 100644 --- a/codex-rs/codex-mcp/src/connection_manager_tests.rs +++ b/codex-rs/codex-mcp/src/connection_manager_tests.rs @@ -14,7 +14,7 @@ use crate::rmcp_client::elicitation_capability_for_server; use crate::tools::ToolFilter; use crate::tools::ToolInfo; use crate::tools::filter_tools; -use crate::tools::qualify_tools; +use crate::tools::normalize_tools_for_model; use crate::tools::tool_with_model_visible_input_schema; use codex_config::Constrained; use codex_protocol::ToolName; @@ -85,6 +85,15 @@ fn create_codex_apps_tools_cache_context( } } +fn sorted_model_tool_names(tools: &[ToolInfo]) -> Vec { + let mut names = tools + .iter() + .map(|tool| tool.canonical_tool_name().display()) + .collect::>(); + names.sort(); + names +} + #[test] fn declared_openai_file_fields_treat_names_literally() { let meta = serde_json::json!({ @@ -272,35 +281,41 @@ async fn disabled_permissions_do_not_auto_accept_elicitation_with_requested_fiel } #[test] -fn test_qualify_tools_short_non_duplicated_names() { +fn test_normalize_tools_short_non_duplicated_names() { let tools = vec![ create_test_tool("server1", "tool1"), create_test_tool("server1", "tool2"), ]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 2); - assert!(qualified_tools.contains_key("mcp__server1__tool1")); - assert!(qualified_tools.contains_key("mcp__server1__tool2")); + assert_eq!( + sorted_model_tool_names(&model_tools), + vec![ + "mcp__server1__tool1".to_string(), + "mcp__server1__tool2".to_string() + ] + ); } #[test] -fn test_qualify_tools_duplicated_names_skipped() { +fn test_normalize_tools_duplicated_names_skipped() { let tools = vec![ create_test_tool("server1", "duplicate_tool"), create_test_tool("server1", "duplicate_tool"), ]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); // Only the first tool should remain, the second is skipped - assert_eq!(qualified_tools.len(), 1); - assert!(qualified_tools.contains_key("mcp__server1__duplicate_tool")); + assert_eq!( + sorted_model_tool_names(&model_tools), + vec!["mcp__server1__duplicate_tool".to_string()] + ); } #[test] -fn test_qualify_tools_long_names_same_server() { +fn test_normalize_tools_long_names_same_server() { let server_name = "my_server"; let tools = vec![ @@ -314,116 +329,125 @@ fn test_qualify_tools_long_names_same_server() { ), ]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 2); + assert_eq!(model_tools.len(), 2); - let mut keys: Vec<_> = qualified_tools.keys().cloned().collect(); - keys.sort(); + let names = sorted_model_tool_names(&model_tools); - assert!(keys.iter().all(|key| key.len() == 64)); - assert!(keys.iter().all(|key| key.starts_with("mcp__my_server__"))); + assert!(names.iter().all(|name| name.len() == 64)); + assert!( + names + .iter() + .all(|name| name.starts_with("mcp__my_server__")) + ); assert!( - keys.iter() - .all(|key| key.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), - "qualified names must be code-mode compatible: {keys:?}" + names + .iter() + .all(|name| name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), + "model-visible names must be code-mode compatible: {names:?}" ); } #[test] -fn test_qualify_tools_sanitizes_invalid_characters() { +fn test_normalize_tools_sanitizes_invalid_characters() { let tools = vec![create_test_tool("server.one", "tool.two-three")]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 1); - let (qualified_name, tool) = qualified_tools.into_iter().next().expect("one tool"); - assert_eq!(qualified_name, "mcp__server_one__tool_two_three"); + assert_eq!(model_tools.len(), 1); + let tool = model_tools.into_iter().next().expect("one tool"); + let model_name = tool.canonical_tool_name().display(); + assert_eq!(model_name, "mcp__server_one__tool_two_three"); assert_eq!( format!("{}{}", tool.callable_namespace, tool.callable_name), - qualified_name + model_name ); - // The key and callable parts are sanitized for model-visible tool calls, but - // the raw MCP name is preserved for the actual MCP call. + // The callable parts are sanitized for model-visible tool calls, but the raw + // MCP name is preserved for the actual MCP call. assert_eq!(tool.server_name, "server.one"); assert_eq!(tool.callable_namespace, "mcp__server_one__"); assert_eq!(tool.callable_name, "tool_two_three"); assert_eq!(tool.tool.name, "tool.two-three"); assert!( - qualified_name + model_name .chars() .all(|c| c.is_ascii_alphanumeric() || c == '_'), - "qualified name must be code-mode compatible: {qualified_name:?}" + "model-visible name must be code-mode compatible: {model_name:?}" ); } #[test] -fn test_qualify_tools_keeps_hyphenated_mcp_tools_callable() { +fn test_normalize_tools_keeps_hyphenated_mcp_tools_callable() { let tools = vec![create_test_tool("music-studio", "get-strudel-guide")]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 1); - let (qualified_name, tool) = qualified_tools.into_iter().next().expect("one tool"); - assert_eq!(qualified_name, "mcp__music_studio__get_strudel_guide"); + assert_eq!(model_tools.len(), 1); + let tool = model_tools.into_iter().next().expect("one tool"); + assert_eq!( + tool.canonical_tool_name().display(), + "mcp__music_studio__get_strudel_guide" + ); assert_eq!(tool.callable_namespace, "mcp__music_studio__"); assert_eq!(tool.callable_name, "get_strudel_guide"); assert_eq!(tool.tool.name, "get-strudel-guide"); } #[test] -fn test_qualify_tools_disambiguates_sanitized_namespace_collisions() { +fn test_normalize_tools_disambiguates_sanitized_namespace_collisions() { let tools = vec![ create_test_tool("basic-server", "lookup"), create_test_tool("basic_server", "query"), ]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 2); - let mut namespaces = qualified_tools - .values() + assert_eq!(model_tools.len(), 2); + let mut namespaces = model_tools + .iter() .map(|tool| tool.callable_namespace.as_str()) .collect::>(); namespaces.sort(); namespaces.dedup(); assert_eq!(namespaces.len(), 2); - let raw_servers = qualified_tools - .values() + let raw_servers = model_tools + .iter() .map(|tool| tool.server_name.as_str()) .collect::>(); assert_eq!(raw_servers, HashSet::from(["basic-server", "basic_server"])); + let model_names = sorted_model_tool_names(&model_tools); assert!( - qualified_tools - .keys() - .all(|key| key.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), - "qualified names must be code-mode compatible: {qualified_tools:?}" + model_names + .iter() + .all(|name| name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), + "model-visible names must be code-mode compatible: {model_names:?}" ); } #[test] -fn test_qualify_tools_disambiguates_sanitized_tool_name_collisions() { +fn test_normalize_tools_disambiguates_sanitized_tool_name_collisions() { let tools = vec![ create_test_tool("server", "tool-name"), create_test_tool("server", "tool_name"), ]; - let qualified_tools = qualify_tools(tools); + let model_tools = normalize_tools_for_model(tools); - assert_eq!(qualified_tools.len(), 2); - let raw_tool_names = qualified_tools - .values() + assert_eq!(model_tools.len(), 2); + let raw_tool_names = model_tools + .iter() .map(|tool| tool.tool.name.to_string()) .collect::>(); assert_eq!( raw_tool_names, HashSet::from(["tool-name".to_string(), "tool_name".to_string()]) ); - let callable_tool_names = qualified_tools - .values() + let callable_tool_names = model_tools + .iter() .map(|tool| tool.callable_name.as_str()) .collect::>(); assert_eq!(callable_tool_names.len(), 2); @@ -672,7 +696,10 @@ async fn list_all_tools_uses_startup_snapshot_while_client_is_pending() { let tools = manager.list_all_tools().await; let tool = tools - .get("mcp__codex_apps__calendar_create_event") + .iter() + .find(|tool| { + tool.canonical_tool_name().display() == "mcp__codex_apps__calendar_create_event" + }) .expect("tool from startup cache"); assert_eq!(tool.server_name, CODEX_APPS_MCP_SERVER_NAME); assert_eq!(tool.callable_name, "calendar_create_event"); @@ -798,7 +825,10 @@ async fn list_all_tools_uses_startup_snapshot_when_client_startup_fails() { let tools = manager.list_all_tools().await; let tool = tools - .get("mcp__codex_apps__calendar_create_event") + .iter() + .find(|tool| { + tool.canonical_tool_name().display() == "mcp__codex_apps__calendar_create_event" + }) .expect("tool from startup cache"); assert_eq!(tool.server_name, CODEX_APPS_MCP_SERVER_NAME); assert_eq!(tool.callable_name, "calendar_create_event"); diff --git a/codex-rs/codex-mcp/src/lib.rs b/codex-rs/codex-mcp/src/lib.rs index 83dc65dd0698..d0c3e52f8cc6 100644 --- a/codex-rs/codex-mcp/src/lib.rs +++ b/codex-rs/codex-mcp/src/lib.rs @@ -48,7 +48,6 @@ pub use mcp::oauth_login_support; pub use mcp::resolve_oauth_scopes; pub use mcp::should_retry_without_scopes; -pub use codex_apps::filter_non_codex_apps_mcp_tools_only; pub use mcp::McpPermissionPromptAutoApproveContext; pub use mcp::mcp_permission_prompt_is_auto_approved; pub use mcp::qualified_mcp_tool_name_prefix; diff --git a/codex-rs/codex-mcp/src/mcp/mod.rs b/codex-rs/codex-mcp/src/mcp/mod.rs index ae667c698a16..118c4c048473 100644 --- a/codex-rs/codex-mcp/src/mcp/mod.rs +++ b/codex-rs/codex-mcp/src/mcp/mod.rs @@ -564,7 +564,7 @@ async fn collect_mcp_server_status_snapshot_from_manager( ); let mut tools_by_server = HashMap::>::new(); - for (_qualified_name, tool_info) in tools { + for tool_info in tools { let raw_tool_name = tool_info.tool.name.to_string(); let Some(tool) = protocol_tool_from_rmcp_tool(&raw_tool_name, &tool_info.tool) else { continue; diff --git a/codex-rs/codex-mcp/src/tools.rs b/codex-rs/codex-mcp/src/tools.rs index 1a3e1a6bc230..cb3d8babae6a 100644 --- a/codex-rs/codex-mcp/src/tools.rs +++ b/codex-rs/codex-mcp/src/tools.rs @@ -1,4 +1,4 @@ -//! MCP tool metadata, filtering, schema shaping, and name qualification. +//! MCP tool metadata, filtering, schema shaping, and name normalization. //! //! Raw MCP tool identities must be preserved for protocol calls, while //! model-visible tool names must be sanitized, deduplicated, and kept within API @@ -130,12 +130,12 @@ pub(crate) fn filter_tools(tools: Vec, filter: &ToolFilter) -> Vec(tools: I) -> HashMap +/// every model-visible name is unique and <= 64 bytes. +pub(crate) fn normalize_tools_for_model(tools: I) -> Vec where I: IntoIterator, { @@ -213,9 +213,9 @@ where candidates.sort_by(|left, right| left.raw_tool_identity.cmp(&right.raw_tool_identity)); let mut used_names = HashSet::new(); - let mut qualified_tools = HashMap::new(); + let mut model_tools = Vec::new(); for mut candidate in candidates { - let (callable_namespace, callable_name, qualified_name) = unique_callable_parts( + let (callable_namespace, callable_name) = unique_callable_parts( &candidate.callable_namespace, &candidate.callable_name, &candidate.raw_tool_identity, @@ -223,9 +223,9 @@ where ); candidate.tool.callable_namespace = callable_namespace; candidate.tool.callable_name = callable_name; - qualified_tools.insert(qualified_name, candidate.tool); + model_tools.push(candidate.tool); } - qualified_tools + model_tools } #[derive(Debug)] @@ -345,10 +345,10 @@ fn unique_callable_parts( tool_name: &str, raw_identity: &str, used_names: &mut HashSet, -) -> (String, String, String) { - let qualified_name = format!("{namespace}{tool_name}"); - if qualified_name.len() <= MAX_TOOL_NAME_LENGTH && used_names.insert(qualified_name.clone()) { - return (namespace.to_string(), tool_name.to_string(), qualified_name); +) -> (String, String) { + let model_name = format!("{namespace}{tool_name}"); + if model_name.len() <= MAX_TOOL_NAME_LENGTH && used_names.insert(model_name) { + return (namespace.to_string(), tool_name.to_string()); } let mut attempt = 0_u32; @@ -360,9 +360,9 @@ fn unique_callable_parts( }; let (namespace, tool_name) = fit_callable_parts_with_hash(namespace, tool_name, &hash_input); - let qualified_name = format!("{namespace}{tool_name}"); - if used_names.insert(qualified_name.clone()) { - return (namespace, tool_name, qualified_name); + let model_name = format!("{namespace}{tool_name}"); + if used_names.insert(model_name) { + return (namespace, tool_name); } attempt = attempt.saturating_add(1); } diff --git a/codex-rs/core/src/connectors.rs b/codex-rs/core/src/connectors.rs index 0bd53a50eed0..d9d713e3e226 100644 --- a/codex-rs/core/src/connectors.rs +++ b/codex-rs/core/src/connectors.rs @@ -165,7 +165,7 @@ pub async fn list_cached_accessible_connectors_from_mcp_tools( pub(crate) fn refresh_accessible_connectors_cache_from_mcp_tools( config: &Config, auth: Option<&CodexAuth>, - mcp_tools: &HashMap, + mcp_tools: &[ToolInfo], ) { if !config.features.enabled(Feature::Apps) { return; @@ -516,12 +516,10 @@ async fn chatgpt_get_request_with_auth_provider( } } -pub(crate) fn accessible_connectors_from_mcp_tools( - mcp_tools: &HashMap, -) -> Vec { +pub(crate) fn accessible_connectors_from_mcp_tools(mcp_tools: &[ToolInfo]) -> Vec { // ToolInfo already carries plugin provenance, so app-level plugin sources // can be derived here instead of requiring a separate enrichment pass. - let tools = mcp_tools.values().filter_map(|tool| { + let tools = mcp_tools.iter().filter_map(|tool| { if tool.server_name != CODEX_APPS_MCP_SERVER_NAME { return None; } diff --git a/codex-rs/core/src/connectors_tests.rs b/codex-rs/core/src/connectors_tests.rs index 513f677e9b92..014ab1cad8d6 100644 --- a/codex-rs/core/src/connectors_tests.rs +++ b/codex-rs/core/src/connectors_tests.rs @@ -172,39 +172,30 @@ fn merge_connectors_replaces_plugin_placeholder_name_with_accessible_name() { #[test] fn accessible_connectors_from_mcp_tools_carries_plugin_display_names() { - let tools = HashMap::from([ - ( - "mcp__codex_apps__calendar_list_events".to_string(), - codex_app_tool( - "calendar_list_events", - "calendar", - /*connector_name*/ None, - &["sample", "sample"], - ), - ), - ( - "mcp__codex_apps__calendar_create_event".to_string(), - codex_app_tool( - "calendar_create_event", - "calendar", - Some("Google Calendar"), - &["beta", "sample"], - ), + let tools = vec![ + codex_app_tool( + "calendar_list_events", + "calendar", + /*connector_name*/ None, + &["sample", "sample"], ), - ( - "mcp__sample__echo".to_string(), - ToolInfo { - server_name: "sample".to_string(), - callable_name: "echo".to_string(), - callable_namespace: "sample".to_string(), - namespace_description: None, - tool: test_tool_definition("echo"), - connector_id: None, - connector_name: None, - plugin_display_names: plugin_names(&["ignored"]), - }, + codex_app_tool( + "calendar_create_event", + "calendar", + Some("Google Calendar"), + &["beta", "sample"], ), - ]); + ToolInfo { + server_name: "sample".to_string(), + callable_name: "echo".to_string(), + callable_namespace: "sample".to_string(), + namespace_description: None, + tool: test_tool_definition("echo"), + connector_id: None, + connector_name: None, + plugin_display_names: plugin_names(&["ignored"]), + }, + ]; let connectors = accessible_connectors_from_mcp_tools(&tools); @@ -238,26 +229,20 @@ async fn refresh_accessible_connectors_cache_from_mcp_tools_writes_latest_instal .expect("config should load"); let _ = config.features.set_enabled(Feature::Apps, /*enabled*/ true); let cache_key = accessible_connectors_cache_key(&config, /*auth*/ None); - let tools = HashMap::from([ - ( - "mcp__codex_apps__calendar_list_events".to_string(), - codex_app_tool( - "calendar_list_events", - "calendar", - Some("Google Calendar"), - &["calendar-plugin"], - ), + let tools = vec![ + codex_app_tool( + "calendar_list_events", + "calendar", + Some("Google Calendar"), + &["calendar-plugin"], ), - ( - "mcp__codex_apps__openai_hidden".to_string(), - codex_app_tool( - "openai_hidden", - "connector_openai_hidden", - Some("Hidden"), - &[], - ), + codex_app_tool( + "openai_hidden", + "connector_openai_hidden", + Some("Hidden"), + &[], ), - ]); + ]; let cached = with_accessible_connectors_cache_cleared(|| { refresh_accessible_connectors_cache_from_mcp_tools(&config, /*auth*/ None, &tools); @@ -315,29 +300,26 @@ fn merge_connectors_unions_and_dedupes_plugin_display_names() { #[test] fn accessible_connectors_from_mcp_tools_preserves_description() { - let mcp_tools = HashMap::from([( - "mcp__codex_apps__calendar_create_event".to_string(), - ToolInfo { - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - callable_name: "calendar_create_event".to_string(), - callable_namespace: "mcp__codex_apps__calendar".to_string(), - namespace_description: Some("Plan events".to_string()), - tool: Tool { - name: "calendar_create_event".to_string().into(), - title: None, - description: Some("Create a calendar event".into()), - input_schema: Arc::new(JsonObject::default()), - output_schema: None, - annotations: None, - execution: None, - icons: None, - meta: None, - }, - connector_id: Some("calendar".to_string()), - connector_name: Some("Calendar".to_string()), - plugin_display_names: Vec::new(), + let mcp_tools = vec![ToolInfo { + server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), + callable_name: "calendar_create_event".to_string(), + callable_namespace: "mcp__codex_apps__calendar".to_string(), + namespace_description: Some("Plan events".to_string()), + tool: Tool { + name: "calendar_create_event".to_string().into(), + title: None, + description: Some("Create a calendar event".into()), + input_schema: Arc::new(JsonObject::default()), + output_schema: None, + annotations: None, + execution: None, + icons: None, + meta: None, }, - )]); + connector_id: Some("calendar".to_string()), + connector_name: Some("Calendar".to_string()), + plugin_display_names: Vec::new(), + }]; assert_eq!( accessible_connectors_from_mcp_tools(&mcp_tools), diff --git a/codex-rs/core/src/mcp_tool_call.rs b/codex-rs/core/src/mcp_tool_call.rs index c7e665cb02ab..74acdc330f98 100644 --- a/codex-rs/core/src/mcp_tool_call.rs +++ b/codex-rs/core/src/mcp_tool_call.rs @@ -1477,7 +1477,7 @@ pub(crate) async fn lookup_mcp_tool_metadata( .list_all_tools() .await; let tool_info = tools - .into_values() + .into_iter() .find(|tool_info| tool_info.server_name == server && tool_info.tool.name == tool_name)?; let connector_description = if server == CODEX_APPS_MCP_SERVER_NAME { let connectors = match connectors::list_cached_accessible_connectors_from_mcp_tools( @@ -1572,7 +1572,7 @@ async fn lookup_mcp_app_usage_metadata( .list_all_tools() .await; - tools.into_values().find_map(|tool_info| { + tools.into_iter().find_map(|tool_info| { if tool_info.server_name == server && tool_info.tool.name == tool_name { Some(McpAppUsageMetadata { connector_id: tool_info.connector_id, diff --git a/codex-rs/core/src/mcp_tool_exposure.rs b/codex-rs/core/src/mcp_tool_exposure.rs index 3917a1d5e768..0bf696acdfc6 100644 --- a/codex-rs/core/src/mcp_tool_exposure.rs +++ b/codex-rs/core/src/mcp_tool_exposure.rs @@ -1,10 +1,8 @@ -use std::collections::HashMap; use std::collections::HashSet; use codex_features::Feature; use codex_mcp::CODEX_APPS_MCP_SERVER_NAME; use codex_mcp::ToolInfo as McpToolInfo; -use codex_mcp::filter_non_codex_apps_mcp_tools_only; use codex_tools::ToolsConfig; use crate::config::Config; @@ -13,12 +11,12 @@ use crate::connectors; pub(crate) const DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD: usize = 100; pub(crate) struct McpToolExposure { - pub(crate) direct_tools: HashMap, - pub(crate) deferred_tools: Option>, + pub(crate) direct_tools: Vec, + pub(crate) deferred_tools: Option>, } pub(crate) fn build_mcp_tool_exposure( - all_mcp_tools: &HashMap, + all_mcp_tools: &[McpToolInfo], connectors: Option<&[connectors::AppInfo]>, explicitly_enabled_connectors: &[connectors::AppInfo], config: &Config, @@ -48,9 +46,11 @@ pub(crate) fn build_mcp_tool_exposure( let direct_tools = filter_codex_apps_mcp_tools(all_mcp_tools, explicitly_enabled_connectors, config); - for direct_tool_name in direct_tools.keys() { - deferred_tools.remove(direct_tool_name); - } + let direct_tool_names = direct_tools + .iter() + .map(McpToolInfo::canonical_tool_name) + .collect::>(); + deferred_tools.retain(|tool| !direct_tool_names.contains(&tool.canonical_tool_name())); McpToolExposure { direct_tools, @@ -58,11 +58,19 @@ pub(crate) fn build_mcp_tool_exposure( } } +fn filter_non_codex_apps_mcp_tools_only(mcp_tools: &[McpToolInfo]) -> Vec { + mcp_tools + .iter() + .filter(|tool| tool.server_name != CODEX_APPS_MCP_SERVER_NAME) + .cloned() + .collect() +} + fn filter_codex_apps_mcp_tools( - mcp_tools: &HashMap, + mcp_tools: &[McpToolInfo], connectors: &[connectors::AppInfo], config: &Config, -) -> HashMap { +) -> Vec { let allowed: HashSet<&str> = connectors .iter() .map(|connector| connector.id.as_str()) @@ -70,7 +78,7 @@ fn filter_codex_apps_mcp_tools( mcp_tools .iter() - .filter(|(_, tool)| { + .filter(|tool| { if tool.server_name != CODEX_APPS_MCP_SERVER_NAME { return false; } @@ -79,7 +87,7 @@ fn filter_codex_apps_mcp_tools( }; allowed.contains(connector_id) && connectors::codex_app_tool_is_enabled(config, tool) }) - .map(|(name, tool)| (name.clone(), tool.clone())) + .cloned() .collect() } diff --git a/codex-rs/core/src/mcp_tool_exposure_test.rs b/codex-rs/core/src/mcp_tool_exposure_test.rs index 32707e4f8ba3..0116a62e9612 100644 --- a/codex-rs/core/src/mcp_tool_exposure_test.rs +++ b/codex-rs/core/src/mcp_tool_exposure_test.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::HashSet; use std::sync::Arc; use codex_connectors::metadata::sanitize_name; @@ -11,6 +11,7 @@ use codex_protocol::config_types::WebSearchMode; use codex_protocol::config_types::WindowsSandboxLevel; use codex_protocol::models::PermissionProfile; use codex_protocol::protocol::SessionSource; +use codex_tools::ToolName; use codex_tools::ToolsConfig; use codex_tools::ToolsConfigParams; use pretty_assertions::assert_eq; @@ -53,10 +54,25 @@ fn make_mcp_tool( } else { format!("mcp__{server_name}__") }; + let callable_name = if server_name == CODEX_APPS_MCP_SERVER_NAME { + let tool_name = sanitize_name(tool_name); + if let Some(connector_name) = connector_name + .map(sanitize_name) + .filter(|name| !name.is_empty()) + && let Some(stripped) = tool_name.strip_prefix(&connector_name) + && !stripped.is_empty() + { + stripped.to_string() + } else { + tool_name + } + } else { + tool_name.to_string() + }; ToolInfo { server_name: server_name.to_string(), - callable_name: tool_name.to_string(), + callable_name, callable_namespace: tool_namespace, namespace_description: None, tool: Tool { @@ -76,20 +92,24 @@ fn make_mcp_tool( } } -fn numbered_mcp_tools(count: usize) -> HashMap { +fn numbered_mcp_tools(count: usize) -> Vec { (0..count) .map(|index| { let tool_name = format!("tool_{index}"); - ( - format!("mcp__rmcp__{tool_name}"), - make_mcp_tool( - "rmcp", &tool_name, /*connector_id*/ None, /*connector_name*/ None, - ), + make_mcp_tool( + "rmcp", &tool_name, /*connector_id*/ None, /*connector_name*/ None, ) }) .collect() } +fn tool_names(tools: &[ToolInfo]) -> HashSet { + tools + .iter() + .map(codex_mcp::ToolInfo::canonical_tool_name) + .collect() +} + async fn tools_config_for_mcp_tool_exposure(search_tool: bool) -> ToolsConfig { let config = test_config().await; let model_info = @@ -124,11 +144,7 @@ async fn directly_exposes_small_effective_tool_sets() { &tools_config, ); - let mut direct_tool_names: Vec<_> = exposure.direct_tools.keys().cloned().collect(); - direct_tool_names.sort(); - let mut expected_tool_names: Vec<_> = mcp_tools.keys().cloned().collect(); - expected_tool_names.sort(); - assert_eq!(direct_tool_names, expected_tool_names); + assert_eq!(tool_names(&exposure.direct_tools), tool_names(&mcp_tools)); assert!(exposure.deferred_tools.is_none()); } @@ -151,11 +167,7 @@ async fn searches_large_effective_tool_sets() { .deferred_tools .as_ref() .expect("large tool sets should be discoverable through tool_search"); - let mut deferred_tool_names: Vec<_> = deferred_tools.keys().cloned().collect(); - deferred_tool_names.sort(); - let mut expected_tool_names: Vec<_> = mcp_tools.keys().cloned().collect(); - expected_tool_names.sort(); - assert_eq!(deferred_tool_names, expected_tool_names); + assert_eq!(tool_names(deferred_tools), tool_names(&mcp_tools)); } #[tokio::test] @@ -163,15 +175,12 @@ async fn directly_exposes_explicit_apps_without_deferred_overlap() { let config = test_config().await; let tools_config = tools_config_for_mcp_tool_exposure(/*search_tool*/ true).await; let mut mcp_tools = numbered_mcp_tools(DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD - 1); - mcp_tools.extend([( - "mcp__codex_apps__calendar_create_event".to_string(), - make_mcp_tool( - CODEX_APPS_MCP_SERVER_NAME, - "calendar_create_event", - Some("calendar"), - Some("Calendar"), - ), - )]); + mcp_tools.push(make_mcp_tool( + CODEX_APPS_MCP_SERVER_NAME, + "calendar_create_event", + Some("calendar"), + Some("Calendar"), + )); let connectors = vec![make_connector("calendar", "Calendar")]; let exposure = build_mcp_tool_exposure( @@ -182,28 +191,32 @@ async fn directly_exposes_explicit_apps_without_deferred_overlap() { &tools_config, ); - let mut tool_names: Vec = exposure.direct_tools.into_keys().collect(); - tool_names.sort(); + let direct_tool_names = tool_names(&exposure.direct_tools); assert_eq!( - tool_names, - vec!["mcp__codex_apps__calendar_create_event".to_string()] + direct_tool_names, + HashSet::from([ToolName::namespaced( + "mcp__codex_apps__calendar", + "_create_event" + )]) ); assert_eq!( - exposure.deferred_tools.as_ref().map(HashMap::len), + exposure.deferred_tools.as_ref().map(Vec::len), Some(DIRECT_MCP_TOOL_EXPOSURE_THRESHOLD - 1) ); let deferred_tools = exposure .deferred_tools .as_ref() .expect("large tool sets should be discoverable through tool_search"); + let deferred_tool_names = tool_names(deferred_tools); assert!( - tool_names - .iter() - .all(|direct_tool_name| !deferred_tools.contains_key(direct_tool_name)), - "direct tools should not also be deferred: {tool_names:?}" + direct_tool_names.is_disjoint(&deferred_tool_names), + "direct tools should not also be deferred: {direct_tool_names:?}" ); - assert!(!deferred_tools.contains_key("mcp__codex_apps__calendar_create_event")); - assert!(deferred_tools.contains_key("mcp__rmcp__tool_0")); + assert!(!deferred_tool_names.contains(&ToolName::namespaced( + "mcp__codex_apps__calendar", + "_create_event" + ))); + assert!(deferred_tool_names.contains(&ToolName::namespaced("mcp__rmcp__", "tool_0"))); } #[tokio::test] @@ -214,23 +227,17 @@ async fn always_defer_feature_preserves_explicit_apps() { .enable(Feature::ToolSearchAlwaysDeferMcpTools) .expect("test config should allow feature update"); let tools_config = tools_config_for_mcp_tool_exposure(/*search_tool*/ true).await; - let mcp_tools = HashMap::from([ - ( - "mcp__rmcp__tool".to_string(), - make_mcp_tool( - "rmcp", "tool", /*connector_id*/ None, /*connector_name*/ None, - ), + let mcp_tools = vec![ + make_mcp_tool( + "rmcp", "tool", /*connector_id*/ None, /*connector_name*/ None, ), - ( - "mcp__codex_apps__calendar_create_event".to_string(), - make_mcp_tool( - CODEX_APPS_MCP_SERVER_NAME, - "calendar_create_event", - Some("calendar"), - Some("Calendar"), - ), + make_mcp_tool( + CODEX_APPS_MCP_SERVER_NAME, + "calendar_create_event", + Some("calendar"), + Some("Calendar"), ), - ]); + ]; let connectors = vec![make_connector("calendar", "Calendar")]; let exposure = build_mcp_tool_exposure( @@ -241,16 +248,22 @@ async fn always_defer_feature_preserves_explicit_apps() { &tools_config, ); - let mut direct_tool_names: Vec = exposure.direct_tools.into_keys().collect(); - direct_tool_names.sort(); + let direct_tool_names = tool_names(&exposure.direct_tools); assert_eq!( direct_tool_names, - vec!["mcp__codex_apps__calendar_create_event".to_string()] + HashSet::from([ToolName::namespaced( + "mcp__codex_apps__calendar", + "_create_event" + )]) ); let deferred_tools = exposure .deferred_tools .as_ref() .expect("MCP tools should be discoverable through tool_search"); - assert!(deferred_tools.contains_key("mcp__rmcp__tool")); - assert!(!deferred_tools.contains_key("mcp__codex_apps__calendar_create_event")); + let deferred_tool_names = tool_names(deferred_tools); + assert!(deferred_tool_names.contains(&ToolName::namespaced("mcp__rmcp__", "tool"))); + assert!(!deferred_tool_names.contains(&ToolName::namespaced( + "mcp__codex_apps__calendar", + "_create_event" + ))); } diff --git a/codex-rs/core/src/plugins/injection.rs b/codex-rs/core/src/plugins/injection.rs index 4ce50631fb0d..48e15247b5c4 100644 --- a/codex-rs/core/src/plugins/injection.rs +++ b/codex-rs/core/src/plugins/injection.rs @@ -1,5 +1,4 @@ use std::collections::BTreeSet; -use std::collections::HashMap; use codex_connectors::metadata::connector_display_label; use codex_protocol::models::ResponseItem; @@ -14,7 +13,7 @@ use codex_mcp::ToolInfo; pub(crate) fn build_plugin_injections( mentioned_plugins: &[PluginCapabilitySummary], - mcp_tools: &HashMap, + mcp_tools: &[ToolInfo], available_connectors: &[connectors::AppInfo], ) -> Vec { if mentioned_plugins.is_empty() { @@ -27,7 +26,7 @@ pub(crate) fn build_plugin_injections( .iter() .filter_map(|plugin| { let available_mcp_servers = mcp_tools - .values() + .iter() .filter(|tool| { tool.server_name != CODEX_APPS_MCP_SERVER_NAME && tool diff --git a/codex-rs/core/src/session/turn.rs b/codex-rs/core/src/session/turn.rs index 4579a4147af3..bdbd7a279324 100644 --- a/codex-rs/core/src/session/turn.rs +++ b/codex-rs/core/src/session/turn.rs @@ -195,10 +195,10 @@ pub(crate) async fn run_turn( { Ok(mcp_tools) => mcp_tools, Err(_) if turn_context.apps_enabled() => return None, - Err(_) => HashMap::new(), + Err(_) => Vec::new(), } } else { - HashMap::new() + Vec::new() }; let available_connectors = if turn_context.apps_enabled() { let connectors = codex_connectors::merge::merge_plugin_connectors_with_accessible( @@ -1247,7 +1247,7 @@ pub(crate) async fn built_tools( let exposed_tool_names = mcp_tools .iter() .chain(deferred_mcp_tools.iter()) - .flat_map(|tools| tools.keys().map(String::as_str)) + .flat_map(|tools| tools.iter().map(codex_mcp::ToolInfo::canonical_tool_name)) .collect::>(); collect_unavailable_called_tools(input, &exposed_tool_names) } else { diff --git a/codex-rs/core/src/tools/handlers/tool_search.rs b/codex-rs/core/src/tools/handlers/tool_search.rs index 59deb541169f..bc2e727dfbb0 100644 --- a/codex-rs/core/src/tools/handlers/tool_search.rs +++ b/codex-rs/core/src/tools/handlers/tool_search.rs @@ -204,19 +204,11 @@ mod tests { }), defer_loading: true, }]; - let handler = handler_from_tools( - Some(&std::collections::HashMap::from([ - ( - "mcp__calendar__create_event".to_string(), - tool_info("calendar", "create_event", "Create events"), - ), - ( - "mcp__calendar__list_events".to_string(), - tool_info("calendar", "list_events", "List events"), - ), - ])), - &dynamic_tools, - ); + let mcp_tools = vec![ + tool_info("calendar", "create_event", "Create events"), + tool_info("calendar", "list_events", "List events"), + ]; + let handler = handler_from_tools(Some(&mcp_tools), &dynamic_tools); let results = [ &handler.entries[0], &handler.entries[2], @@ -376,18 +368,11 @@ mod tests { assert!(count_results_for_server(&results, "other-server") <= TOOL_SEARCH_DEFAULT_LIMIT); } - fn numbered_tools( - server_name: &str, - description_prefix: &str, - count: usize, - ) -> std::collections::HashMap { + fn numbered_tools(server_name: &str, description_prefix: &str, count: usize) -> Vec { (0..count) .map(|index| { let tool_name = format!("tool_{index:03}"); - ( - format!("mcp__{server_name}__{tool_name}"), - tool_info(server_name, &tool_name, description_prefix), - ) + tool_info(server_name, &tool_name, description_prefix) }) .collect() } @@ -427,7 +412,7 @@ mod tests { } fn handler_from_tools( - mcp_tools: Option<&std::collections::HashMap>, + mcp_tools: Option<&[ToolInfo]>, dynamic_tools: &[DynamicToolSpec], ) -> ToolSearchHandler { ToolSearchHandler::new(build_tool_search_entries(mcp_tools, dynamic_tools)) diff --git a/codex-rs/core/src/tools/router.rs b/codex-rs/core/src/tools/router.rs index aeba3b0556ee..609fedf964bc 100644 --- a/codex-rs/core/src/tools/router.rs +++ b/codex-rs/core/src/tools/router.rs @@ -21,7 +21,6 @@ use codex_tools::ResponsesApiNamespaceTool; use codex_tools::ToolName; use codex_tools::ToolSpec; use codex_tools::ToolsConfig; -use std::collections::HashMap; use std::collections::HashSet; use std::sync::Arc; use tokio_util::sync::CancellationToken; @@ -44,8 +43,8 @@ pub struct ToolRouter { } pub(crate) struct ToolRouterParams<'a> { - pub(crate) mcp_tools: Option>, - pub(crate) deferred_mcp_tools: Option>, + pub(crate) mcp_tools: Option>, + pub(crate) deferred_mcp_tools: Option>, pub(crate) unavailable_called_tools: Vec, pub(crate) parallel_mcp_server_names: HashSet, pub(crate) discoverable_tools: Option>, diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index b13345f33387..aa504fe70f8a 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -42,17 +42,17 @@ struct McpToolPlanInputs<'a> { tool_namespaces: HashMap, } -fn map_mcp_tools_for_plan(mcp_tools: &HashMap) -> McpToolPlanInputs<'_> { +fn map_mcp_tools_for_plan(mcp_tools: &[ToolInfo]) -> McpToolPlanInputs<'_> { McpToolPlanInputs { mcp_tools: mcp_tools - .values() + .iter() .map(|tool| ToolRegistryPlanMcpTool { name: tool.canonical_tool_name(), tool: &tool.tool, }) .collect(), tool_namespaces: mcp_tools - .values() + .iter() .map(|tool| { ( tool.callable_namespace.clone(), @@ -68,8 +68,8 @@ fn map_mcp_tools_for_plan(mcp_tools: &HashMap) -> McpToolPlanI pub(crate) fn build_specs_with_discoverable_tools( config: &ToolsConfig, - mcp_tools: Option>, - deferred_mcp_tools: Option>, + mcp_tools: Option>, + deferred_mcp_tools: Option>, unavailable_called_tools: Vec, discoverable_tools: Option>, dynamic_tools: &[DynamicToolSpec], @@ -114,10 +114,10 @@ pub(crate) fn build_specs_with_discoverable_tools( use crate::tools::tool_search_entry::build_tool_search_entries_for_config; let mut builder = ToolRegistryBuilder::new(); - let mcp_tool_plan_inputs = mcp_tools.as_ref().map(map_mcp_tools_for_plan); + let mcp_tool_plan_inputs = mcp_tools.as_deref().map(map_mcp_tools_for_plan); let deferred_mcp_tool_sources = deferred_mcp_tools.as_ref().map(|tools| { tools - .values() + .iter() .map(|tool| ToolRegistryPlanDeferredTool { name: tool.canonical_tool_name(), server_name: tool.server_name.as_str(), @@ -279,7 +279,7 @@ pub(crate) fn build_specs_with_discoverable_tools( ToolHandlerKind::ToolSearch => { let entries = build_tool_search_entries_for_config( config, - deferred_mcp_tools.as_ref(), + deferred_mcp_tools.as_deref(), &deferred_dynamic_tools, ); builder.register_handler(Arc::new(ToolSearchHandler::new(entries))); @@ -305,10 +305,13 @@ pub(crate) fn build_specs_with_discoverable_tools( } } if let Some(deferred_mcp_tools) = deferred_mcp_tools.as_ref() { - for (_, tool) in deferred_mcp_tools.iter().filter(|(name, _)| { - !mcp_tools - .as_ref() - .is_some_and(|tools| tools.contains_key(*name)) + for tool in deferred_mcp_tools.iter().filter(|tool| { + let tool_name = tool.canonical_tool_name(); + !mcp_tools.as_ref().is_some_and(|direct_tools| { + direct_tools + .iter() + .any(|direct_tool| direct_tool.canonical_tool_name() == tool_name) + }) }) { builder.register_handler(Arc::new(McpHandler::new(tool.canonical_tool_name()))); } diff --git a/codex-rs/core/src/tools/spec_tests.rs b/codex-rs/core/src/tools/spec_tests.rs index 6bd796508dec..24e03fbf8a9d 100644 --- a/codex-rs/core/src/tools/spec_tests.rs +++ b/codex-rs/core/src/tools/spec_tests.rs @@ -266,8 +266,8 @@ async fn model_info_from_models_json(slug: &str) -> ModelInfo { /// Builds the tool registry builder while collecting tool specs for later serialization. fn build_specs( config: &ToolsConfig, - mcp_tools: Option>, - deferred_mcp_tools: Option>, + mcp_tools: Option>, + deferred_mcp_tools: Option>, dynamic_tools: &[DynamicToolSpec], ) -> ToolRegistryBuilder { build_specs_with_unavailable_tools( @@ -281,8 +281,8 @@ fn build_specs( fn build_specs_with_unavailable_tools( config: &ToolsConfig, - mcp_tools: Option>, - deferred_mcp_tools: Option>, + mcp_tools: Option>, + deferred_mcp_tools: Option>, unavailable_called_tools: Vec, dynamic_tools: &[DynamicToolSpec], ) -> ToolRegistryBuilder { @@ -630,7 +630,7 @@ async fn test_build_specs_default_shell_present() { }); let (tools, _) = build_specs( &tools_config, - Some(HashMap::new()), + Some(Vec::new()), /*deferred_mcp_tools*/ None, &[], ) @@ -856,7 +856,7 @@ async fn search_tool_description_handles_no_enabled_mcp_tools() { let (tools, _) = build_specs( &tools_config, /*mcp_tools*/ None, - Some(HashMap::new()), + Some(Vec::new()), &[], ) .build(); @@ -890,23 +890,20 @@ async fn search_tool_description_falls_back_to_connector_name_without_descriptio let (tools, _) = build_specs( &tools_config, /*mcp_tools*/ None, - Some(HashMap::from([( - "mcp__codex_apps__calendar_create_event".to_string(), - ToolInfo { - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - callable_name: "_create_event".to_string(), - callable_namespace: "mcp__codex_apps__calendar".to_string(), - namespace_description: None, - tool: mcp_tool( - "calendar_create_event", - "Create calendar event", - serde_json::json!({"type": "object"}), - ), - connector_id: Some("calendar".to_string()), - connector_name: Some("Calendar".to_string()), - plugin_display_names: Vec::new(), - }, - )])), + Some(vec![ToolInfo { + server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), + callable_name: "_create_event".to_string(), + callable_namespace: "mcp__codex_apps__calendar".to_string(), + namespace_description: None, + tool: mcp_tool( + "calendar_create_event", + "Create calendar event", + serde_json::json!({"type": "object"}), + ), + connector_id: Some("calendar".to_string()), + connector_name: Some("Calendar".to_string()), + plugin_display_names: Vec::new(), + }]), &[], ) .build(); @@ -940,55 +937,46 @@ async fn search_tool_registers_namespaced_mcp_tool_aliases() { let (_, registry) = build_specs( &tools_config, /*mcp_tools*/ None, - Some(HashMap::from([ - ( - "mcp__codex_apps__calendar_create_event".to_string(), - ToolInfo { - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - callable_name: "_create_event".to_string(), - callable_namespace: "mcp__codex_apps__calendar".to_string(), - namespace_description: None, - tool: mcp_tool( - "calendar-create-event", - "Create calendar event", - serde_json::json!({"type": "object"}), - ), - connector_id: Some("calendar".to_string()), - connector_name: Some("Calendar".to_string()), - plugin_display_names: Vec::new(), - }, - ), - ( - "mcp__codex_apps__calendar_list_events".to_string(), - ToolInfo { - server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), - callable_name: "_list_events".to_string(), - callable_namespace: "mcp__codex_apps__calendar".to_string(), - namespace_description: None, - tool: mcp_tool( - "calendar-list-events", - "List calendar events", - serde_json::json!({"type": "object"}), - ), - connector_id: Some("calendar".to_string()), - connector_name: Some("Calendar".to_string()), - plugin_display_names: Vec::new(), - }, - ), - ( - "mcp__rmcp__echo".to_string(), - ToolInfo { - server_name: "rmcp".to_string(), - callable_name: "echo".to_string(), - callable_namespace: "mcp__rmcp__".to_string(), - namespace_description: None, - tool: mcp_tool("echo", "Echo", serde_json::json!({"type": "object"})), - connector_id: None, - connector_name: None, - plugin_display_names: Vec::new(), - }, - ), - ])), + Some(vec![ + ToolInfo { + server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), + callable_name: "_create_event".to_string(), + callable_namespace: "mcp__codex_apps__calendar".to_string(), + namespace_description: None, + tool: mcp_tool( + "calendar-create-event", + "Create calendar event", + serde_json::json!({"type": "object"}), + ), + connector_id: Some("calendar".to_string()), + connector_name: Some("Calendar".to_string()), + plugin_display_names: Vec::new(), + }, + ToolInfo { + server_name: CODEX_APPS_MCP_SERVER_NAME.to_string(), + callable_name: "_list_events".to_string(), + callable_namespace: "mcp__codex_apps__calendar".to_string(), + namespace_description: None, + tool: mcp_tool( + "calendar-list-events", + "List calendar events", + serde_json::json!({"type": "object"}), + ), + connector_id: Some("calendar".to_string()), + connector_name: Some("Calendar".to_string()), + plugin_display_names: Vec::new(), + }, + ToolInfo { + server_name: "rmcp".to_string(), + callable_name: "echo".to_string(), + callable_namespace: "mcp__rmcp__".to_string(), + namespace_description: None, + tool: mcp_tool("echo", "Echo", serde_json::json!({"type": "object"})), + connector_id: None, + connector_name: None, + plugin_display_names: Vec::new(), + }, + ]), &[], ) .build(); @@ -1018,14 +1006,11 @@ async fn tool_search_entries_skip_namespace_outputs_when_namespace_tools_are_dis windows_sandbox_level: WindowsSandboxLevel::Disabled, }); tools_config.namespace_tools = false; - let mcp_tools = HashMap::from([( - "mcp__test_server__echo".to_string(), - mcp_tool_info(mcp_tool( - "echo", - "Echo", - serde_json::json!({"type": "object"}), - )), - )]); + let mcp_tools = vec![mcp_tool_info(mcp_tool( + "echo", + "Echo", + serde_json::json!({"type": "object"}), + ))]; let dynamic_tools = vec![ DynamicToolSpec { namespace: Some("codex_app".to_string()), @@ -1077,14 +1062,11 @@ async fn direct_mcp_tools_register_namespaced_handlers() { let (_, registry) = build_specs( &tools_config, - Some(HashMap::from([( - "mcp__test_server__echo".to_string(), - mcp_tool_info(mcp_tool( - "echo", - "Echo", - serde_json::json!({"type": "object"}), - )), - )])), + Some(vec![mcp_tool_info(mcp_tool( + "echo", + "Echo", + serde_json::json!({"type": "object"}), + ))]), /*deferred_mcp_tools*/ None, &[], ) @@ -1163,22 +1145,19 @@ async fn test_mcp_tool_property_missing_type_defaults_to_string() { let (tools, _) = build_specs( &tools_config, - Some(HashMap::from([( - "dash/search".to_string(), - mcp_tool_info_with_display_name( - "dash/search", - mcp_tool( - "search", - "Search docs", - serde_json::json!({ - "type": "object", - "properties": { - "query": {"description": "search query"} - } - }), - ), + Some(vec![mcp_tool_info_with_display_name( + "dash/search", + mcp_tool( + "search", + "Search docs", + serde_json::json!({ + "type": "object", + "properties": { + "query": {"description": "search query"} + } + }), ), - )])), + )]), /*deferred_mcp_tools*/ None, &[], ) @@ -1226,20 +1205,17 @@ async fn test_mcp_tool_preserves_integer_schema() { let (tools, _) = build_specs( &tools_config, - Some(HashMap::from([( - "dash/paginate".to_string(), - mcp_tool_info_with_display_name( - "dash/paginate", - mcp_tool( - "paginate", - "Pagination", - serde_json::json!({ - "type": "object", - "properties": {"page": {"type": "integer"}} - }), - ), + Some(vec![mcp_tool_info_with_display_name( + "dash/paginate", + mcp_tool( + "paginate", + "Pagination", + serde_json::json!({ + "type": "object", + "properties": {"page": {"type": "integer"}} + }), ), - )])), + )]), /*deferred_mcp_tools*/ None, &[], ) @@ -1288,20 +1264,17 @@ async fn test_mcp_tool_array_without_items_gets_default_string_items() { let (tools, _) = build_specs( &tools_config, - Some(HashMap::from([( - "dash/tags".to_string(), - mcp_tool_info_with_display_name( - "dash/tags", - mcp_tool( - "tags", - "Tags", - serde_json::json!({ - "type": "object", - "properties": {"tags": {"type": "array"}} - }), - ), + Some(vec![mcp_tool_info_with_display_name( + "dash/tags", + mcp_tool( + "tags", + "Tags", + serde_json::json!({ + "type": "object", + "properties": {"tags": {"type": "array"}} + }), ), - )])), + )]), /*deferred_mcp_tools*/ None, &[], ) @@ -1352,22 +1325,19 @@ async fn test_mcp_tool_anyof_defaults_to_string() { let (tools, _) = build_specs( &tools_config, - Some(HashMap::from([( - "dash/value".to_string(), - mcp_tool_info_with_display_name( - "dash/value", - mcp_tool( - "value", - "AnyOf Value", - serde_json::json!({ - "type": "object", - "properties": { - "value": {"anyOf": [{"type": "string"}, {"type": "number"}]} - } - }), - ), + Some(vec![mcp_tool_info_with_display_name( + "dash/value", + mcp_tool( + "value", + "AnyOf Value", + serde_json::json!({ + "type": "object", + "properties": { + "value": {"anyOf": [{"type": "string"}, {"type": "number"}]} + } + }), ), - )])), + )]), /*deferred_mcp_tools*/ None, &[], ) @@ -1420,39 +1390,36 @@ async fn test_get_openai_tools_mcp_tools_with_additional_properties_schema() { }); let (tools, _) = build_specs( &tools_config, - Some(HashMap::from([( - "test_server/do_something_cool".to_string(), - mcp_tool_info_with_display_name( - "test_server/do_something_cool", - mcp_tool( - "do_something_cool", - "Do something cool", - serde_json::json!({ + Some(vec![mcp_tool_info_with_display_name( + "test_server/do_something_cool", + mcp_tool( + "do_something_cool", + "Do something cool", + serde_json::json!({ + "type": "object", + "properties": { + "string_argument": {"type": "string"}, + "number_argument": {"type": "number"}, + "object_argument": { "type": "object", "properties": { - "string_argument": {"type": "string"}, - "number_argument": {"type": "number"}, - "object_argument": { + "string_property": {"type": "string"}, + "number_property": {"type": "number"} + }, + "required": ["string_property", "number_property"], + "additionalProperties": { "type": "object", "properties": { - "string_property": {"type": "string"}, - "number_property": {"type": "number"} + "addtl_prop": {"type": "string"} }, - "required": ["string_property", "number_property"], - "additionalProperties": { - "type": "object", - "properties": { - "addtl_prop": {"type": "string"} - }, - "required": ["addtl_prop"], - "additionalProperties": false - } + "required": ["addtl_prop"], + "additionalProperties": false } } - }), - ), + } + }), ), - )])), + )]), /*deferred_mcp_tools*/ None, &[], ) diff --git a/codex-rs/core/src/tools/tool_search_entry.rs b/codex-rs/core/src/tools/tool_search_entry.rs index 06b7efcd0603..a0e9a726b954 100644 --- a/codex-rs/core/src/tools/tool_search_entry.rs +++ b/codex-rs/core/src/tools/tool_search_entry.rs @@ -5,7 +5,6 @@ use codex_tools::ToolSearchResultSource; use codex_tools::ToolsConfig; use codex_tools::dynamic_tool_to_loadable_tool_spec; use codex_tools::tool_search_result_source_to_loadable_tool_spec; -use std::collections::HashMap; #[derive(Clone)] pub(crate) struct ToolSearchEntry { @@ -15,13 +14,13 @@ pub(crate) struct ToolSearchEntry { } pub(crate) fn build_tool_search_entries( - mcp_tools: Option<&HashMap>, + mcp_tools: Option<&[ToolInfo]>, dynamic_tools: &[DynamicToolSpec], ) -> Vec { let mut entries = Vec::new(); let mut mcp_tools = mcp_tools - .map(|tools| tools.values().collect::>()) + .map(|tools| tools.iter().collect::>()) .unwrap_or_default(); mcp_tools.sort_by_key(|info| info.canonical_tool_name().display()); for info in mcp_tools { @@ -55,7 +54,7 @@ pub(crate) fn build_tool_search_entries( pub(crate) fn build_tool_search_entries_for_config( config: &ToolsConfig, - mcp_tools: Option<&HashMap>, + mcp_tools: Option<&[ToolInfo]>, dynamic_tools: &[DynamicToolSpec], ) -> Vec { let mcp_tools = if config.namespace_tools { diff --git a/codex-rs/core/src/unavailable_tool.rs b/codex-rs/core/src/unavailable_tool.rs index 39ba21f9b86a..e25e47a30e11 100644 --- a/codex-rs/core/src/unavailable_tool.rs +++ b/codex-rs/core/src/unavailable_tool.rs @@ -6,7 +6,7 @@ use codex_tools::ToolName; pub(crate) fn collect_unavailable_called_tools( input: &[ResponseItem], - exposed_tool_names: &HashSet<&str>, + exposed_tool_names: &HashSet, ) -> Vec { let mut unavailable_tools = BTreeMap::new(); @@ -25,11 +25,11 @@ pub(crate) fn collect_unavailable_called_tools( Some(namespace) => ToolName::namespaced(namespace.clone(), name.clone()), None => ToolName::plain(name.clone()), }; - let display_name = tool_name.display(); - if exposed_tool_names.contains(display_name.as_str()) { + if exposed_tool_names.contains(&tool_name) { continue; } + let display_name = tool_name.display(); unavailable_tools .entry(display_name) .or_insert_with(|| tool_name); @@ -78,7 +78,10 @@ mod tests { #[test] fn collect_unavailable_called_tools_skips_currently_available_tools() { - let exposed_tool_names = HashSet::from(["mcp__server__lookup", "mcp__server__search"]); + let exposed_tool_names = HashSet::from([ + ToolName::plain("mcp__server__lookup"), + ToolName::plain("mcp__server__search"), + ]); let input = vec![ function_call("mcp__server__lookup", /*namespace*/ None), function_call("mcp__server__search", /*namespace*/ None), From 496d9d0d8d6ed763e286b11cedd64db51a34bf8f Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 6 May 2026 18:39:37 -0700 Subject: [PATCH 2/6] Compare MCP normalized tool names structurally --- .../codex-mcp/src/connection_manager_tests.rs | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/codex-rs/codex-mcp/src/connection_manager_tests.rs b/codex-rs/codex-mcp/src/connection_manager_tests.rs index 5c430bd8e56d..9ff5fdcfe648 100644 --- a/codex-rs/codex-mcp/src/connection_manager_tests.rs +++ b/codex-rs/codex-mcp/src/connection_manager_tests.rs @@ -85,13 +85,11 @@ fn create_codex_apps_tools_cache_context( } } -fn sorted_model_tool_names(tools: &[ToolInfo]) -> Vec { - let mut names = tools +fn model_tool_names(tools: &[ToolInfo]) -> HashSet { + tools .iter() - .map(|tool| tool.canonical_tool_name().display()) - .collect::>(); - names.sort(); - names + .map(ToolInfo::canonical_tool_name) + .collect::>() } #[test] @@ -290,11 +288,11 @@ fn test_normalize_tools_short_non_duplicated_names() { let model_tools = normalize_tools_for_model(tools); assert_eq!( - sorted_model_tool_names(&model_tools), - vec![ - "mcp__server1__tool1".to_string(), - "mcp__server1__tool2".to_string() - ] + model_tool_names(&model_tools), + HashSet::from([ + ToolName::namespaced("mcp__server1__", "tool1"), + ToolName::namespaced("mcp__server1__", "tool2") + ]) ); } @@ -309,8 +307,8 @@ fn test_normalize_tools_duplicated_names_skipped() { // Only the first tool should remain, the second is skipped assert_eq!( - sorted_model_tool_names(&model_tools), - vec!["mcp__server1__duplicate_tool".to_string()] + model_tool_names(&model_tools), + HashSet::from([ToolName::namespaced("mcp__server1__", "duplicate_tool")]) ); } @@ -333,18 +331,19 @@ fn test_normalize_tools_long_names_same_server() { assert_eq!(model_tools.len(), 2); - let names = sorted_model_tool_names(&model_tools); + let names = model_tool_names(&model_tools); - assert!(names.iter().all(|name| name.len() == 64)); + assert!(names.iter().all(|name| name.display().len() == 64)); assert!( names .iter() - .all(|name| name.starts_with("mcp__my_server__")) + .all(|name| name.namespace.as_deref() == Some("mcp__my_server__")) ); assert!( - names - .iter() - .all(|name| name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), + names.iter().all(|name| name + .display() + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_')), "model-visible names must be code-mode compatible: {names:?}" ); } @@ -357,11 +356,14 @@ fn test_normalize_tools_sanitizes_invalid_characters() { assert_eq!(model_tools.len(), 1); let tool = model_tools.into_iter().next().expect("one tool"); - let model_name = tool.canonical_tool_name().display(); - assert_eq!(model_name, "mcp__server_one__tool_two_three"); + let model_name = tool.canonical_tool_name(); + assert_eq!( + model_name, + ToolName::namespaced("mcp__server_one__", "tool_two_three") + ); assert_eq!( format!("{}{}", tool.callable_namespace, tool.callable_name), - model_name + model_name.display() ); // The callable parts are sanitized for model-visible tool calls, but the raw @@ -373,6 +375,7 @@ fn test_normalize_tools_sanitizes_invalid_characters() { assert!( model_name + .display() .chars() .all(|c| c.is_ascii_alphanumeric() || c == '_'), "model-visible name must be code-mode compatible: {model_name:?}" @@ -388,8 +391,8 @@ fn test_normalize_tools_keeps_hyphenated_mcp_tools_callable() { assert_eq!(model_tools.len(), 1); let tool = model_tools.into_iter().next().expect("one tool"); assert_eq!( - tool.canonical_tool_name().display(), - "mcp__music_studio__get_strudel_guide" + tool.canonical_tool_name(), + ToolName::namespaced("mcp__music_studio__", "get_strudel_guide") ); assert_eq!(tool.callable_namespace, "mcp__music_studio__"); assert_eq!(tool.callable_name, "get_strudel_guide"); @@ -419,11 +422,12 @@ fn test_normalize_tools_disambiguates_sanitized_namespace_collisions() { .map(|tool| tool.server_name.as_str()) .collect::>(); assert_eq!(raw_servers, HashSet::from(["basic-server", "basic_server"])); - let model_names = sorted_model_tool_names(&model_tools); + let model_names = model_tool_names(&model_tools); assert!( - model_names - .iter() - .all(|name| name.chars().all(|c| c.is_ascii_alphanumeric() || c == '_')), + model_names.iter().all(|name| name + .display() + .chars() + .all(|c| c.is_ascii_alphanumeric() || c == '_')), "model-visible names must be code-mode compatible: {model_names:?}" ); } @@ -698,7 +702,8 @@ async fn list_all_tools_uses_startup_snapshot_while_client_is_pending() { let tool = tools .iter() .find(|tool| { - tool.canonical_tool_name().display() == "mcp__codex_apps__calendar_create_event" + tool.canonical_tool_name() + == ToolName::namespaced("mcp__codex_apps__", "calendar_create_event") }) .expect("tool from startup cache"); assert_eq!(tool.server_name, CODEX_APPS_MCP_SERVER_NAME); @@ -827,7 +832,8 @@ async fn list_all_tools_uses_startup_snapshot_when_client_startup_fails() { let tool = tools .iter() .find(|tool| { - tool.canonical_tool_name().display() == "mcp__codex_apps__calendar_create_event" + tool.canonical_tool_name() + == ToolName::namespaced("mcp__codex_apps__", "calendar_create_event") }) .expect("tool from startup cache"); assert_eq!(tool.server_name, CODEX_APPS_MCP_SERVER_NAME); From 0c1c82874c152b12fad0af3aa8309be6ac091ac3 Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 6 May 2026 18:47:53 -0700 Subject: [PATCH 3/6] Simplify MCP exposure test fixtures --- codex-rs/core/src/mcp_tool_exposure_test.rs | 49 +++++++++------------ 1 file changed, 20 insertions(+), 29 deletions(-) diff --git a/codex-rs/core/src/mcp_tool_exposure_test.rs b/codex-rs/core/src/mcp_tool_exposure_test.rs index 0116a62e9612..c3f467800a82 100644 --- a/codex-rs/core/src/mcp_tool_exposure_test.rs +++ b/codex-rs/core/src/mcp_tool_exposure_test.rs @@ -1,7 +1,6 @@ use std::collections::HashSet; use std::sync::Arc; -use codex_connectors::metadata::sanitize_name; use codex_features::Feature; use codex_features::Features; use codex_mcp::CODEX_APPS_MCP_SERVER_NAME; @@ -43,37 +42,15 @@ fn make_connector(id: &str, name: &str) -> AppInfo { fn make_mcp_tool( server_name: &str, tool_name: &str, + callable_namespace: &str, + callable_name: &str, connector_id: Option<&str>, connector_name: Option<&str>, ) -> ToolInfo { - let tool_namespace = if server_name == CODEX_APPS_MCP_SERVER_NAME { - connector_name - .map(sanitize_name) - .map(|connector_name| format!("mcp__{server_name}__{connector_name}")) - .unwrap_or_else(|| server_name.to_string()) - } else { - format!("mcp__{server_name}__") - }; - let callable_name = if server_name == CODEX_APPS_MCP_SERVER_NAME { - let tool_name = sanitize_name(tool_name); - if let Some(connector_name) = connector_name - .map(sanitize_name) - .filter(|name| !name.is_empty()) - && let Some(stripped) = tool_name.strip_prefix(&connector_name) - && !stripped.is_empty() - { - stripped.to_string() - } else { - tool_name - } - } else { - tool_name.to_string() - }; - ToolInfo { server_name: server_name.to_string(), - callable_name, - callable_namespace: tool_namespace, + callable_name: callable_name.to_string(), + callable_namespace: callable_namespace.to_string(), namespace_description: None, tool: Tool { name: tool_name.to_string().into(), @@ -97,7 +74,12 @@ fn numbered_mcp_tools(count: usize) -> Vec { .map(|index| { let tool_name = format!("tool_{index}"); make_mcp_tool( - "rmcp", &tool_name, /*connector_id*/ None, /*connector_name*/ None, + "rmcp", + &tool_name, + "mcp__rmcp__", + &tool_name, + /*connector_id*/ None, + /*connector_name*/ None, ) }) .collect() @@ -178,6 +160,8 @@ async fn directly_exposes_explicit_apps_without_deferred_overlap() { mcp_tools.push(make_mcp_tool( CODEX_APPS_MCP_SERVER_NAME, "calendar_create_event", + "mcp__codex_apps__calendar", + "_create_event", Some("calendar"), Some("Calendar"), )); @@ -229,11 +213,18 @@ async fn always_defer_feature_preserves_explicit_apps() { let tools_config = tools_config_for_mcp_tool_exposure(/*search_tool*/ true).await; let mcp_tools = vec![ make_mcp_tool( - "rmcp", "tool", /*connector_id*/ None, /*connector_name*/ None, + "rmcp", + "tool", + "mcp__rmcp__", + "tool", + /*connector_id*/ None, + /*connector_name*/ None, ), make_mcp_tool( CODEX_APPS_MCP_SERVER_NAME, "calendar_create_event", + "mcp__codex_apps__calendar", + "_create_event", Some("calendar"), Some("Calendar"), ), From d33d9a912a27de96a61f556698e97282c643901e Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 6 May 2026 19:57:58 -0700 Subject: [PATCH 4/6] Preserve MCP display name matching --- codex-rs/core/src/unavailable_tool.rs | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/codex-rs/core/src/unavailable_tool.rs b/codex-rs/core/src/unavailable_tool.rs index e25e47a30e11..aabf1f605834 100644 --- a/codex-rs/core/src/unavailable_tool.rs +++ b/codex-rs/core/src/unavailable_tool.rs @@ -9,6 +9,10 @@ pub(crate) fn collect_unavailable_called_tools( exposed_tool_names: &HashSet, ) -> Vec { let mut unavailable_tools = BTreeMap::new(); + let exposed_display_names = exposed_tool_names + .iter() + .map(ToolName::display) + .collect::>(); for item in input { let ResponseItem::FunctionCall { @@ -25,11 +29,11 @@ pub(crate) fn collect_unavailable_called_tools( Some(namespace) => ToolName::namespaced(namespace.clone(), name.clone()), None => ToolName::plain(name.clone()), }; - if exposed_tool_names.contains(&tool_name) { + let display_name = tool_name.display(); + if exposed_display_names.contains(&display_name) { continue; } - let display_name = tool_name.display(); unavailable_tools .entry(display_name) .or_insert_with(|| tool_name); @@ -92,4 +96,17 @@ mod tests { assert_eq!(tools, vec![ToolName::plain("mcp__server__missing")]); } + + #[test] + fn collect_unavailable_called_tools_matches_exposed_display_names() { + let exposed_tool_names = HashSet::from([ToolName::namespaced("mcp__server__", "lookup")]); + let input = vec![function_call( + "mcp__server__lookup", + /*namespace*/ None, + )]; + + let tools = collect_unavailable_called_tools(&input, &exposed_tool_names); + + assert_eq!(tools, Vec::new()); + } } From f459c8360d904130568bf41dd33e7f08e881cb5d Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Wed, 6 May 2026 19:34:14 -0700 Subject: [PATCH 5/6] Remove ToolName display helper --- .../codex-mcp/src/connection_manager_tests.rs | 35 ++++++++++--------- codex-rs/core/src/memory_usage.rs | 5 +-- codex-rs/core/src/session/tests.rs | 2 +- codex-rs/core/src/stream_events_utils.rs | 2 +- .../core/src/tools/handlers/apply_patch.rs | 4 +-- codex-rs/core/src/tools/handlers/mcp.rs | 10 ++++-- codex-rs/core/src/tools/handlers/shell.rs | 5 +-- .../tools/handlers/shell/container_exec.rs | 2 +- .../src/tools/handlers/shell/local_shell.rs | 2 +- .../src/tools/handlers/shell/shell_command.rs | 6 ++-- .../src/tools/handlers/shell/shell_handler.rs | 2 +- .../src/tools/handlers/unavailable_tool.rs | 2 +- codex-rs/core/src/tools/mod.rs | 18 ++++++++++ codex-rs/core/src/tools/orchestrator.rs | 13 ++++--- codex-rs/core/src/tools/parallel.rs | 5 ++- codex-rs/core/src/tools/registry.rs | 24 +++++++------ codex-rs/core/src/tools/runtimes/shell.rs | 3 +- .../core/src/tools/runtimes/unified_exec.rs | 3 +- codex-rs/core/src/tools/sandboxing.rs | 3 +- codex-rs/core/src/tools/spec.rs | 3 +- codex-rs/core/src/tools/spec_plan.rs | 2 +- codex-rs/core/src/tools/tool_search_entry.rs | 6 ++-- codex-rs/core/src/unavailable_tool.rs | 2 +- .../core/src/unified_exec/process_manager.rs | 3 +- codex-rs/protocol/src/tool_name.rs | 28 +++++++++++---- 25 files changed, 121 insertions(+), 69 deletions(-) diff --git a/codex-rs/codex-mcp/src/connection_manager_tests.rs b/codex-rs/codex-mcp/src/connection_manager_tests.rs index 9ff5fdcfe648..93193e5bc89b 100644 --- a/codex-rs/codex-mcp/src/connection_manager_tests.rs +++ b/codex-rs/codex-mcp/src/connection_manager_tests.rs @@ -92,6 +92,19 @@ fn model_tool_names(tools: &[ToolInfo]) -> HashSet { .collect::>() } +fn model_tool_name_len(name: &ToolName) -> usize { + name.namespace.as_deref().map_or(0, str::len) + name.name.len() +} + +fn is_code_mode_compatible_tool_name(name: &ToolName) -> bool { + name.namespace + .as_deref() + .into_iter() + .chain(std::iter::once(name.name.as_str())) + .flat_map(str::chars) + .all(|c| c.is_ascii_alphanumeric() || c == '_') +} + #[test] fn declared_openai_file_fields_treat_names_literally() { let meta = serde_json::json!({ @@ -333,17 +346,14 @@ fn test_normalize_tools_long_names_same_server() { let names = model_tool_names(&model_tools); - assert!(names.iter().all(|name| name.display().len() == 64)); + assert!(names.iter().all(|name| model_tool_name_len(name) == 64)); assert!( names .iter() .all(|name| name.namespace.as_deref() == Some("mcp__my_server__")) ); assert!( - names.iter().all(|name| name - .display() - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '_')), + names.iter().all(is_code_mode_compatible_tool_name), "model-visible names must be code-mode compatible: {names:?}" ); } @@ -362,10 +372,9 @@ fn test_normalize_tools_sanitizes_invalid_characters() { ToolName::namespaced("mcp__server_one__", "tool_two_three") ); assert_eq!( - format!("{}{}", tool.callable_namespace, tool.callable_name), - model_name.display() + ToolName::namespaced(tool.callable_namespace.clone(), tool.callable_name.clone()), + model_name ); - // The callable parts are sanitized for model-visible tool calls, but the raw // MCP name is preserved for the actual MCP call. assert_eq!(tool.server_name, "server.one"); @@ -374,10 +383,7 @@ fn test_normalize_tools_sanitizes_invalid_characters() { assert_eq!(tool.tool.name, "tool.two-three"); assert!( - model_name - .display() - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '_'), + is_code_mode_compatible_tool_name(&model_name), "model-visible name must be code-mode compatible: {model_name:?}" ); } @@ -424,10 +430,7 @@ fn test_normalize_tools_disambiguates_sanitized_namespace_collisions() { assert_eq!(raw_servers, HashSet::from(["basic-server", "basic_server"])); let model_names = model_tool_names(&model_tools); assert!( - model_names.iter().all(|name| name - .display() - .chars() - .all(|c| c.is_ascii_alphanumeric() || c == '_')), + model_names.iter().all(is_code_mode_compatible_tool_name), "model-visible names must be code-mode compatible: {model_names:?}" ); } diff --git a/codex-rs/core/src/memory_usage.rs b/codex-rs/core/src/memory_usage.rs index 02f74ea593d0..fd54044f21b5 100644 --- a/codex-rs/core/src/memory_usage.rs +++ b/codex-rs/core/src/memory_usage.rs @@ -1,5 +1,6 @@ use crate::tools::context::ToolInvocation; use crate::tools::context::ToolPayload; +use crate::tools::flat_tool_name; use crate::tools::handlers::unified_exec::ExecCommandArgs; use codex_memories_read::usage::MEMORIES_USAGE_METRIC; use codex_memories_read::usage::memories_usage_kinds_from_command; @@ -17,14 +18,14 @@ pub(crate) async fn emit_metric_for_tool_read(invocation: &ToolInvocation, succe } let success = if success { "true" } else { "false" }; - let tool_name = invocation.tool_name.display(); + let tool_name = flat_tool_name(&invocation.tool_name); for kind in kinds { invocation.turn.session_telemetry.counter( MEMORIES_USAGE_METRIC, /*inc*/ 1, &[ ("kind", kind.as_tag()), - ("tool", &tool_name), + ("tool", tool_name.as_ref()), ("success", success), ], ); diff --git a/codex-rs/core/src/session/tests.rs b/codex-rs/core/src/session/tests.rs index 72ce91c7a91f..388b5c819b83 100644 --- a/codex-rs/core/src/session/tests.rs +++ b/codex-rs/core/src/session/tests.rs @@ -1025,7 +1025,7 @@ async fn danger_full_access_tool_attempts_do_not_enforce_managed_network() -> an session: Arc::clone(&session), turn: Arc::clone(&turn), call_id: "probe-call".to_string(), - tool_name: "probe".to_string(), + tool_name: codex_tools::ToolName::plain("probe"), }; orchestrator diff --git a/codex-rs/core/src/stream_events_utils.rs b/codex-rs/core/src/stream_events_utils.rs index fc608aed93e4..17518446851b 100644 --- a/codex-rs/core/src/stream_events_utils.rs +++ b/codex-rs/core/src/stream_events_utils.rs @@ -236,7 +236,7 @@ pub(crate) async fn handle_output_item_done( tracing::info!( thread_id = %ctx.sess.conversation_id, "ToolCall: {} {}", - call.tool_name.display(), + call.tool_name, payload_preview ); diff --git a/codex-rs/core/src/tools/handlers/apply_patch.rs b/codex-rs/core/src/tools/handlers/apply_patch.rs index 75a92953c622..abdf16abbe3c 100644 --- a/codex-rs/core/src/tools/handlers/apply_patch.rs +++ b/codex-rs/core/src/tools/handlers/apply_patch.rs @@ -425,7 +425,7 @@ impl ToolHandler for ApplyPatchHandler { session: session.clone(), turn: turn.clone(), call_id: call_id.clone(), - tool_name: tool_name.display(), + tool_name: tool_name.clone(), }; let out = orchestrator .run( @@ -533,7 +533,7 @@ pub(crate) async fn intercept_apply_patch( session: session.clone(), turn: turn.clone(), call_id: call_id.to_string(), - tool_name: tool_name.to_string(), + tool_name: ToolName::plain(tool_name), }; let out = orchestrator .run( diff --git a/codex-rs/core/src/tools/handlers/mcp.rs b/codex-rs/core/src/tools/handlers/mcp.rs index 4dfcb44b1ff7..35dbc3bc01a3 100644 --- a/codex-rs/core/src/tools/handlers/mcp.rs +++ b/codex-rs/core/src/tools/handlers/mcp.rs @@ -8,6 +8,7 @@ use crate::tools::context::McpToolOutput; use crate::tools::context::ToolInvocation; use crate::tools::context::ToolOutput; use crate::tools::context::ToolPayload; +use crate::tools::flat_tool_name; use crate::tools::hook_names::HookToolName; use crate::tools::registry::PostToolUsePayload; use crate::tools::registry::PreToolUsePayload; @@ -42,8 +43,9 @@ impl ToolHandler for McpHandler { return None; }; + let tool_name = &self.tool_name; Some(PreToolUsePayload { - tool_name: HookToolName::new(self.tool_name.display()), + tool_name: HookToolName::new(flat_tool_name(tool_name).into_owned()), tool_input: mcp_hook_tool_input(raw_arguments), }) } @@ -59,8 +61,9 @@ impl ToolHandler for McpHandler { let tool_response = result.post_tool_use_response(&invocation.call_id, &invocation.payload)?; + let tool_name = &self.tool_name; Some(PostToolUsePayload { - tool_name: HookToolName::new(self.tool_name.display()), + tool_name: HookToolName::new(flat_tool_name(tool_name).into_owned()), tool_use_id: invocation.call_id.clone(), tool_input: result.tool_input.clone(), tool_response, @@ -93,13 +96,14 @@ impl ToolHandler for McpHandler { let arguments_str = raw_arguments; let started = Instant::now(); + let hook_tool_name = flat_tool_name(&self.tool_name); let result = handle_mcp_tool_call( Arc::clone(&session), &turn, call_id.clone(), server, tool, - self.tool_name.display(), + hook_tool_name.into_owned(), arguments_str, ) .await; diff --git a/codex-rs/core/src/tools/handlers/shell.rs b/codex-rs/core/src/tools/handlers/shell.rs index 469c0a0799f0..2d27759501e1 100644 --- a/codex-rs/core/src/tools/handlers/shell.rs +++ b/codex-rs/core/src/tools/handlers/shell.rs @@ -29,6 +29,7 @@ use crate::tools::runtimes::shell::ShellRuntimeBackend; use crate::tools::sandboxing::ToolCtx; use codex_protocol::models::AdditionalPermissionProfile; use codex_protocol::protocol::ExecCommandSource; +use codex_tools::ToolName; mod container_exec; mod local_shell; @@ -71,7 +72,7 @@ fn shell_command_payload_command(payload: &ToolPayload) -> Option { } struct RunExecLikeArgs { - tool_name: String, + tool_name: ToolName, exec_params: ExecParams, hook_command: String, additional_permissions: Option, @@ -200,7 +201,7 @@ async fn run_exec_like(args: RunExecLikeArgs) -> Result Ok(FunctionToolOutput::from_text( unavailable_tool_message( - self.tool_name.display(), + &self.tool_name, "Retry after the tool becomes available or ask the user to re-enable it.", ), Some(false), diff --git a/codex-rs/core/src/tools/mod.rs b/codex-rs/core/src/tools/mod.rs index 812c36511340..3073d9f9da60 100644 --- a/codex-rs/core/src/tools/mod.rs +++ b/codex-rs/core/src/tools/mod.rs @@ -17,7 +17,10 @@ pub(crate) mod spec_plan_types; pub(crate) mod tool_dispatch_trace; pub(crate) mod tool_search_entry; +use std::borrow::Cow; + use codex_protocol::exec_output::ExecToolCallOutput; +use codex_tools::ToolName; use codex_utils_output_truncation::TruncationPolicy; use codex_utils_output_truncation::formatted_truncate_text; use codex_utils_output_truncation::truncate_text; @@ -30,6 +33,21 @@ pub(crate) const TELEMETRY_PREVIEW_MAX_LINES: usize = 64; // lines pub(crate) const TELEMETRY_PREVIEW_TRUNCATION_NOTICE: &str = "[... telemetry preview truncated ...]"; +/// Legacy boundaries such as hook payloads, telemetry tags, and Responses tool +/// names still require a single flattened string. Keep comparisons and sorting +/// on `ToolName` itself; use this only when crossing those boundaries. +pub(crate) fn flat_tool_name(tool_name: &ToolName) -> Cow<'_, str> { + match tool_name.namespace.as_deref() { + Some(namespace) => { + let mut name = String::with_capacity(namespace.len() + tool_name.name.len()); + name.push_str(namespace); + name.push_str(&tool_name.name); + Cow::Owned(name) + } + None => Cow::Borrowed(tool_name.name.as_str()), + } +} + /// Format the combined exec output for sending back to the model. /// Includes exit code and duration metadata; truncates large bodies safely. pub fn format_exec_output_for_model_structured( diff --git a/codex-rs/core/src/tools/orchestrator.rs b/codex-rs/core/src/tools/orchestrator.rs index c618d778d6ee..4fd1ea17f483 100644 --- a/codex-rs/core/src/tools/orchestrator.rs +++ b/codex-rs/core/src/tools/orchestrator.rs @@ -12,6 +12,7 @@ use crate::guardian::new_guardian_review_id; use crate::guardian::routes_approval_to_guardian; use crate::hook_runtime::run_permission_request_hooks; use crate::network_policy_decision::network_approval_context_from_payload; +use crate::tools::flat_tool_name; use crate::tools::network_approval::ActiveNetworkApproval; use crate::tools::network_approval::DeferredNetworkApproval; use crate::tools::network_approval::NetworkApprovalMode; @@ -135,7 +136,7 @@ impl ToolOrchestrator { T: ToolRuntime, { let otel = turn_ctx.session_telemetry.clone(); - let otel_tn = &tool_ctx.tool_name; + let otel_tn = flat_tool_name(&tool_ctx.tool_name).into_owned(); let otel_ci = &tool_ctx.call_id; let strict_auto_review = tool_ctx.session.strict_auto_review_enabled_for_turn().await; let use_guardian = routes_approval_to_guardian(turn_ctx) || strict_auto_review; @@ -175,7 +176,7 @@ impl ToolOrchestrator { already_approved = true; } else { otel.tool_decision( - otel_tn, + &otel_tn, otel_ci, &ReviewDecision::Approved, ToolDecisionSource::Config, @@ -398,6 +399,7 @@ impl ToolOrchestrator { if evaluate_permission_request_hooks && let Some(permission_request) = tool.permission_request_payload(req) { + let tool_name = flat_tool_name(&tool_ctx.tool_name); match run_permission_request_hooks( approval_ctx.session, approval_ctx.turn, @@ -409,7 +411,7 @@ impl ToolOrchestrator { Some(PermissionRequestDecision::Allow) => { let decision = ReviewDecision::Approved; otel.tool_decision( - &tool_ctx.tool_name, + tool_name.as_ref(), &tool_ctx.call_id, &decision, ToolDecisionSource::Config, @@ -419,7 +421,7 @@ impl ToolOrchestrator { Some(PermissionRequestDecision::Deny { message }) => { let decision = ReviewDecision::Denied; otel.tool_decision( - &tool_ctx.tool_name, + tool_name.as_ref(), &tool_ctx.call_id, &decision, ToolDecisionSource::Config, @@ -436,8 +438,9 @@ impl ToolOrchestrator { ToolDecisionSource::User }; let decision = tool.start_approval_async(req, approval_ctx).await; + let tool_name = flat_tool_name(&tool_ctx.tool_name); otel.tool_decision( - &tool_ctx.tool_name, + tool_name.as_ref(), &tool_ctx.call_id, &decision, otel_source, diff --git a/codex-rs/core/src/tools/parallel.rs b/codex-rs/core/src/tools/parallel.rs index 384a800b4b11..d7fe22e4f4fd 100644 --- a/codex-rs/core/src/tools/parallel.rs +++ b/codex-rs/core/src/tools/parallel.rs @@ -94,12 +94,11 @@ impl ToolCallRuntime { let lock = Arc::clone(&self.parallel_execution); let invocation_cancellation_token = cancellation_token.clone(); let started = Instant::now(); - let display_name = call.tool_name.display(); let dispatch_span = trace_span!( "dispatch_tool_call_with_code_mode_result", - otel.name = display_name.as_str(), - tool_name = display_name.as_str(), + otel.name = %call.tool_name, + tool_name = %call.tool_name, call_id = call.call_id.as_str(), aborted = false, ); diff --git a/codex-rs/core/src/tools/registry.rs b/codex-rs/core/src/tools/registry.rs index bdf18cf2fe09..0b734ecdb9bb 100644 --- a/codex-rs/core/src/tools/registry.rs +++ b/codex-rs/core/src/tools/registry.rs @@ -16,6 +16,7 @@ use crate::tools::context::FunctionToolOutput; use crate::tools::context::ToolInvocation; use crate::tools::context::ToolOutput; use crate::tools::context::ToolPayload; +use crate::tools::flat_tool_name; use crate::tools::hook_names::HookToolName; use crate::tools::tool_dispatch_trace::ToolDispatchTrace; use codex_hooks::HookEvent; @@ -263,7 +264,7 @@ impl ToolRegistry { invocation: ToolInvocation, ) -> Result { let tool_name = invocation.tool_name.clone(); - let display_name = tool_name.display(); + let tool_name_flat = flat_tool_name(&tool_name); let call_id_owned = invocation.call_id.clone(); let otel = invocation.turn.session_telemetry.clone(); let payload_for_response = invocation.payload.clone(); @@ -316,7 +317,7 @@ impl ToolRegistry { None => { let message = unsupported_tool_call_message(&invocation.payload, &tool_name); otel.tool_result_with_tags( - &display_name, + tool_name_flat.as_ref(), &call_id_owned, log_payload.as_ref(), Duration::ZERO, @@ -333,9 +334,9 @@ impl ToolRegistry { }; if !handler.matches_kind(&invocation.payload) { - let message = format!("tool {display_name} invoked with incompatible payload"); + let message = format!("tool {tool_name} invoked with incompatible payload"); otel.tool_result_with_tags( - &display_name, + tool_name_flat.as_ref(), &call_id_owned, log_payload.as_ref(), Duration::ZERO, @@ -372,7 +373,7 @@ impl ToolRegistry { let started = Instant::now(); let result = otel .log_tool_result_with_tags( - &display_name, + tool_name_flat.as_ref(), &call_id_owned, log_payload.as_ref(), &metric_tags, @@ -540,10 +541,10 @@ impl ToolRegistryBuilder { H: ToolHandler + 'static, { let name = handler.tool_name(); - let display_name = name.display(); + let duplicate_name = name.clone(); let handler: Arc = handler; if self.handlers.insert(name, handler).is_some() { - warn!("overwriting handler for tool {display_name}"); + warn!("overwriting handler for tool {duplicate_name}"); } } @@ -554,7 +555,6 @@ impl ToolRegistryBuilder { } fn unsupported_tool_call_message(payload: &ToolPayload, tool_name: &ToolName) -> String { - let tool_name = tool_name.display(); match payload { ToolPayload::Custom { .. } => format!("unsupported custom tool call: {tool_name}"), _ => format!("unsupported call: {tool_name}"), @@ -627,6 +627,8 @@ async fn dispatch_after_tool_use_hook( let session = invocation.session.as_ref(); let turn = invocation.turn.as_ref(); let tool_input = HookToolInput::from(&invocation.payload); + let tool_name = &invocation.tool_name; + let hook_tool_name = flat_tool_name(tool_name); let hook_outcomes = session .hooks() .dispatch(HookPayload { @@ -638,7 +640,7 @@ async fn dispatch_after_tool_use_hook( event: HookEventAfterToolUse { turn_id: turn.sub_id.clone(), call_id: invocation.call_id.clone(), - tool_name: invocation.tool_name.display(), + tool_name: hook_tool_name.into_owned(), tool_kind: hook_tool_kind(&tool_input), tool_input, executed: dispatch.executed, @@ -669,7 +671,7 @@ async fn dispatch_after_tool_use_hook( HookResult::FailedContinue(error) => { warn!( call_id = %invocation.call_id, - tool_name = %invocation.tool_name.display(), + tool_name = %invocation.tool_name, hook_name = %hook_name, error = %error, "after_tool_use hook failed; continuing" @@ -678,7 +680,7 @@ async fn dispatch_after_tool_use_hook( HookResult::FailedAbort(error) => { warn!( call_id = %invocation.call_id, - tool_name = %invocation.tool_name.display(), + tool_name = %invocation.tool_name, hook_name = %hook_name, error = %error, "after_tool_use hook failed; aborting operation" diff --git a/codex-rs/core/src/tools/runtimes/shell.rs b/codex-rs/core/src/tools/runtimes/shell.rs index 7f17285db9d9..4aa58552a42b 100644 --- a/codex-rs/core/src/tools/runtimes/shell.rs +++ b/codex-rs/core/src/tools/runtimes/shell.rs @@ -17,6 +17,7 @@ use crate::sandboxing::ExecOptions; use crate::sandboxing::SandboxPermissions; use crate::sandboxing::execute_env; use crate::shell::ShellType; +use crate::tools::flat_tool_name; use crate::tools::network_approval::NetworkApprovalMode; use crate::tools::network_approval::NetworkApprovalSpec; use crate::tools::runtimes::build_sandbox_command; @@ -227,7 +228,7 @@ impl ToolRuntime for ShellRuntime { mode: NetworkApprovalMode::Immediate, trigger: GuardianNetworkAccessTrigger { call_id: ctx.call_id.clone(), - tool_name: ctx.tool_name.clone(), + tool_name: flat_tool_name(&ctx.tool_name).into_owned(), command: req.command.clone(), cwd: req.cwd.clone(), sandbox_permissions: req.sandbox_permissions, diff --git a/codex-rs/core/src/tools/runtimes/unified_exec.rs b/codex-rs/core/src/tools/runtimes/unified_exec.rs index 42f311bfcb68..ae080e0388ca 100644 --- a/codex-rs/core/src/tools/runtimes/unified_exec.rs +++ b/codex-rs/core/src/tools/runtimes/unified_exec.rs @@ -14,6 +14,7 @@ use crate::sandboxing::ExecOptions; use crate::sandboxing::ExecServerEnvConfig; use crate::sandboxing::SandboxPermissions; use crate::shell::ShellType; +use crate::tools::flat_tool_name; use crate::tools::network_approval::NetworkApprovalMode; use crate::tools::network_approval::NetworkApprovalSpec; use crate::tools::runtimes::build_sandbox_command; @@ -233,7 +234,7 @@ impl<'a> ToolRuntime for UnifiedExecRunt mode: NetworkApprovalMode::Deferred, trigger: GuardianNetworkAccessTrigger { call_id: ctx.call_id.clone(), - tool_name: ctx.tool_name.clone(), + tool_name: flat_tool_name(&ctx.tool_name).into_owned(), command: req.command.clone(), cwd: req.cwd.clone(), sandbox_permissions: req.sandbox_permissions, diff --git a/codex-rs/core/src/tools/sandboxing.rs b/codex-rs/core/src/tools/sandboxing.rs index c17247beb47c..6bb78632f7cc 100644 --- a/codex-rs/core/src/tools/sandboxing.rs +++ b/codex-rs/core/src/tools/sandboxing.rs @@ -27,6 +27,7 @@ use codex_sandboxing::SandboxTransformError; use codex_sandboxing::SandboxTransformRequest; use codex_sandboxing::SandboxType; use codex_sandboxing::SandboxablePreference; +use codex_tools::ToolName; use codex_utils_absolute_path::AbsolutePathBuf; use futures::Future; use futures::future::BoxFuture; @@ -344,7 +345,7 @@ pub(crate) struct ToolCtx { pub session: Arc, pub turn: Arc, pub call_id: String, - pub tool_name: String, + pub tool_name: ToolName, } #[derive(Debug)] diff --git a/codex-rs/core/src/tools/spec.rs b/codex-rs/core/src/tools/spec.rs index aa504fe70f8a..72b42a0ac79c 100644 --- a/codex-rs/core/src/tools/spec.rs +++ b/codex-rs/core/src/tools/spec.rs @@ -1,5 +1,6 @@ use crate::shell::Shell; use crate::shell::ShellType; +use crate::tools::flat_tool_name; use crate::tools::handlers::agent_jobs::ReportAgentJobResultHandler; use crate::tools::handlers::agent_jobs::SpawnAgentsOnCsvHandler; use crate::tools::handlers::multi_agents_common::DEFAULT_WAIT_TIMEOUT_MS; @@ -318,7 +319,7 @@ pub(crate) fn build_specs_with_discoverable_tools( } for unavailable_tool in unavailable_called_tools { - let tool_name = unavailable_tool.display(); + let tool_name = flat_tool_name(&unavailable_tool).into_owned(); if existing_spec_names.insert(tool_name.clone()) { let spec = codex_tools::ToolSpec::Function(ResponsesApiTool { name: tool_name.clone(), diff --git a/codex-rs/core/src/tools/spec_plan.rs b/codex-rs/core/src/tools/spec_plan.rs index e323bce741d6..2d23e6c4f5f7 100644 --- a/codex-rs/core/src/tools/spec_plan.rs +++ b/codex-rs/core/src/tools/spec_plan.rs @@ -512,7 +512,7 @@ pub fn build_tool_registry_plan( if let Some(mcp_tools) = params.mcp_tools { let mut entries = mcp_tools.to_vec(); - entries.sort_by_key(|tool| tool.name.display()); + entries.sort_by(|a, b| a.name.cmp(&b.name)); let mut namespace_entries = BTreeMap::new(); for tool in entries { diff --git a/codex-rs/core/src/tools/tool_search_entry.rs b/codex-rs/core/src/tools/tool_search_entry.rs index a0e9a726b954..6a8ccd640213 100644 --- a/codex-rs/core/src/tools/tool_search_entry.rs +++ b/codex-rs/core/src/tools/tool_search_entry.rs @@ -1,3 +1,4 @@ +use crate::tools::flat_tool_name; use codex_mcp::ToolInfo; use codex_protocol::dynamic_tools::DynamicToolSpec; use codex_tools::LoadableToolSpec; @@ -22,7 +23,7 @@ pub(crate) fn build_tool_search_entries( let mut mcp_tools = mcp_tools .map(|tools| tools.iter().collect::>()) .unwrap_or_default(); - mcp_tools.sort_by_key(|info| info.canonical_tool_name().display()); + mcp_tools.sort_by_key(|info| info.canonical_tool_name()); for info in mcp_tools { match mcp_tool_search_entry(info) { Ok(entry) => entries.push(entry), @@ -94,8 +95,9 @@ fn dynamic_tool_search_entry(tool: &DynamicToolSpec) -> Result String { + let tool_name = info.canonical_tool_name(); let mut parts = vec![ - info.canonical_tool_name().display(), + flat_tool_name(&tool_name).into_owned(), info.callable_name.clone(), info.tool.name.to_string(), info.server_name.clone(), diff --git a/codex-rs/core/src/unavailable_tool.rs b/codex-rs/core/src/unavailable_tool.rs index aabf1f605834..2c4c1feadff4 100644 --- a/codex-rs/core/src/unavailable_tool.rs +++ b/codex-rs/core/src/unavailable_tool.rs @@ -35,7 +35,7 @@ pub(crate) fn collect_unavailable_called_tools( } unavailable_tools - .entry(display_name) + .entry(tool_name.clone()) .or_insert_with(|| tool_name); } diff --git a/codex-rs/core/src/unified_exec/process_manager.rs b/codex-rs/core/src/unified_exec/process_manager.rs index 4f85b1ddf7c7..73afca2da8b2 100644 --- a/codex-rs/core/src/unified_exec/process_manager.rs +++ b/codex-rs/core/src/unified_exec/process_manager.rs @@ -54,6 +54,7 @@ use codex_protocol::config_types::ShellEnvironmentPolicy; use codex_protocol::error::CodexErr; use codex_protocol::error::SandboxErr; use codex_protocol::protocol::ExecCommandSource; +use codex_tools::ToolName; use codex_utils_absolute_path::AbsolutePathBuf; use codex_utils_output_truncation::approx_token_count; @@ -1040,7 +1041,7 @@ impl UnifiedExecProcessManager { session: context.session.clone(), turn: context.turn.clone(), call_id: context.call_id.clone(), - tool_name: "exec_command".to_string(), + tool_name: ToolName::plain("exec_command"), }; orchestrator .run( diff --git a/codex-rs/protocol/src/tool_name.rs b/codex-rs/protocol/src/tool_name.rs index d09bc1ce72d4..3d7219abe890 100644 --- a/codex-rs/protocol/src/tool_name.rs +++ b/codex-rs/protocol/src/tool_name.rs @@ -1,5 +1,6 @@ use serde::Deserialize; use serde::Serialize; +use std::cmp::Ordering; use std::fmt; /// Identifies a callable tool, preserving the namespace split when the model @@ -31,13 +32,6 @@ impl ToolName { namespace: Some(namespace.into()), } } - - pub fn display(&self) -> String { - match &self.namespace { - Some(namespace) => format!("{namespace}{}", self.name), - None => self.name.clone(), - } - } } impl fmt::Display for ToolName { @@ -49,6 +43,26 @@ impl fmt::Display for ToolName { } } +impl Ord for ToolName { + fn cmp(&self, other: &Self) -> Ordering { + let lhs = match &self.namespace { + Some(namespace) => (namespace.as_str(), Some(self.name.as_str())), + None => (self.name.as_str(), None), + }; + let rhs = match &other.namespace { + Some(namespace) => (namespace.as_str(), Some(other.name.as_str())), + None => (other.name.as_str(), None), + }; + lhs.cmp(&rhs) + } +} + +impl PartialOrd for ToolName { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + impl From for ToolName { fn from(name: String) -> Self { Self::plain(name) From a2e454a131d6cc19fc9bb381c407275954e950c2 Mon Sep 17 00:00:00 2001 From: pakrym-oai Date: Thu, 7 May 2026 15:06:53 -0700 Subject: [PATCH 6/6] Update stale Bazel lockfile --- MODULE.bazel.lock | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index e079e3af0e0a..56d2b3a04b38 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -686,7 +686,6 @@ "axum_0.7.9": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.67\"},{\"name\":\"axum-core\",\"req\":\"^0.4.5\"},{\"name\":\"axum-macros\",\"optional\":true,\"req\":\"^0.4.2\"},{\"features\":[\"__private\"],\"kind\":\"dev\",\"name\":\"axum-macros\",\"req\":\"^0.4.1\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.1.0\"},{\"features\":[\"tokio\",\"server\",\"service\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.3\"},{\"name\":\"itoa\",\"req\":\"^1.0.5\"},{\"name\":\"matchit\",\"req\":\"^0.7\"},{\"name\":\"memchr\",\"req\":\"^2.4.1\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"multer\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"rustversion\",\"req\":\"^1.0.9\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"serde-human-readable\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1.25.0\"},{\"features\":[\"macros\",\"rt\",\"rt-multi-thread\",\"net\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"package\":\"tokio\",\"req\":\"^1.25.0\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"name\":\"tokio-tungstenite\",\"optional\":true,\"req\":\"^0.24.0\"},{\"kind\":\"dev\",\"name\":\"tokio-tungstenite\",\"req\":\"^0.24.0\"},{\"default_features\":false,\"features\":[\"util\"],\"name\":\"tower\",\"req\":\"^0.5.1\"},{\"features\":[\"util\",\"timeout\",\"limit\",\"load-shed\",\"steer\",\"filter\"],\"kind\":\"dev\",\"name\":\"tower\",\"package\":\"tower\",\"req\":\"^0.5.1\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.2\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"features\":[\"serde\",\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"__private_docs\":[\"axum-core/__private_docs\",\"tower/full\",\"dep:tower-http\"],\"default\":[\"form\",\"http1\",\"json\",\"matched-path\",\"original-uri\",\"query\",\"tokio\",\"tower-log\",\"tracing\"],\"form\":[\"dep:serde_urlencoded\"],\"http1\":[\"dep:hyper\",\"hyper?/http1\",\"hyper-util?/http1\"],\"http2\":[\"dep:hyper\",\"hyper?/http2\",\"hyper-util?/http2\"],\"json\":[\"dep:serde_json\",\"dep:serde_path_to_error\"],\"macros\":[\"dep:axum-macros\"],\"matched-path\":[],\"multipart\":[\"dep:multer\"],\"original-uri\":[],\"query\":[\"dep:serde_urlencoded\"],\"tokio\":[\"dep:hyper-util\",\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tower/make\",\"tokio/macros\"],\"tower-log\":[\"tower/log\"],\"tracing\":[\"dep:tracing\",\"axum-core/tracing\"],\"ws\":[\"dep:hyper\",\"tokio\",\"dep:tokio-tungstenite\",\"dep:sha1\",\"dep:base64\"]}}", "axum_0.8.8": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"axum-core\",\"req\":\"^0.5.5\"},{\"name\":\"axum-macros\",\"optional\":true,\"req\":\"^0.5.0\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22.1\"},{\"name\":\"bytes\",\"req\":\"^1.0\"},{\"name\":\"form_urlencoded\",\"optional\":true,\"req\":\"^1.1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"http\",\"req\":\"^1.0.0\"},{\"name\":\"http-body\",\"req\":\"^1.0.0\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.0\"},{\"name\":\"hyper\",\"optional\":true,\"req\":\"^1.1.0\"},{\"features\":[\"client\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\"},{\"features\":[\"tokio\",\"server\",\"service\"],\"name\":\"hyper-util\",\"optional\":true,\"req\":\"^0.1.3\"},{\"name\":\"itoa\",\"req\":\"^1.0.5\"},{\"name\":\"matchit\",\"req\":\"=0.8.4\"},{\"name\":\"memchr\",\"req\":\"^2.4.1\"},{\"name\":\"mime\",\"req\":\"^0.3.16\"},{\"name\":\"multer\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"percent-encoding\",\"req\":\"^2.1\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.7\"},{\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"quickcheck_macros\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"default_features\":false,\"features\":[\"json\",\"stream\",\"multipart\"],\"kind\":\"dev\",\"name\":\"reqwest\",\"req\":\"^0.12\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.211\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.221\"},{\"name\":\"serde_core\",\"req\":\"^1.0.221\"},{\"features\":[\"raw_value\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"raw_value\"],\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"serde_path_to_error\",\"optional\":true,\"req\":\"^0.1.8\"},{\"name\":\"serde_urlencoded\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"sha1\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"sync_wrapper\",\"req\":\"^1.0.0\"},{\"features\":[\"serde-human-readable\"],\"kind\":\"dev\",\"name\":\"time\",\"req\":\"^0.3\"},{\"features\":[\"time\"],\"name\":\"tokio\",\"optional\":true,\"package\":\"tokio\",\"req\":\"^1.44\"},{\"features\":[\"macros\",\"rt\",\"rt-multi-thread\",\"net\",\"test-util\"],\"kind\":\"dev\",\"name\":\"tokio\",\"package\":\"tokio\",\"req\":\"^1.44.2\"},{\"kind\":\"dev\",\"name\":\"tokio-stream\",\"req\":\"^0.1\"},{\"name\":\"tokio-tungstenite\",\"optional\":true,\"req\":\"^0.28.0\"},{\"kind\":\"dev\",\"name\":\"tokio-tungstenite\",\"req\":\"^0.28.0\"},{\"default_features\":false,\"features\":[\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"util\",\"timeout\",\"limit\",\"load-shed\",\"steer\",\"filter\"],\"kind\":\"dev\",\"name\":\"tower\",\"package\":\"tower\",\"req\":\"^0.5.2\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"name\":\"tower-http\",\"optional\":true,\"req\":\"^0.6.0\"},{\"features\":[\"add-extension\",\"auth\",\"catch-panic\",\"compression-br\",\"compression-deflate\",\"compression-gzip\",\"cors\",\"decompression-br\",\"decompression-deflate\",\"decompression-gzip\",\"follow-redirect\",\"fs\",\"limit\",\"map-request-body\",\"map-response-body\",\"metrics\",\"normalize-path\",\"propagate-header\",\"redirect\",\"request-id\",\"sensitive-headers\",\"set-header\",\"set-status\",\"timeout\",\"trace\",\"util\",\"validate-request\"],\"kind\":\"dev\",\"name\":\"tower-http\",\"req\":\"^0.6.0\"},{\"name\":\"tower-layer\",\"req\":\"^0.3.2\"},{\"name\":\"tower-service\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"tracing\",\"optional\":true,\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"json\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"features\":[\"serde\",\"v4\"],\"kind\":\"dev\",\"name\":\"uuid\",\"req\":\"^1.0\"}],\"features\":{\"__private\":[\"tokio\",\"http1\",\"dep:reqwest\"],\"__private_docs\":[\"axum-core/__private_docs\",\"tower/full\",\"dep:serde\",\"dep:tower-http\"],\"default\":[\"form\",\"http1\",\"json\",\"matched-path\",\"original-uri\",\"query\",\"tokio\",\"tower-log\",\"tracing\"],\"form\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"http1\":[\"dep:hyper\",\"hyper?/http1\",\"hyper-util?/http1\"],\"http2\":[\"dep:hyper\",\"hyper?/http2\",\"hyper-util?/http2\"],\"json\":[\"dep:serde_json\",\"dep:serde_path_to_error\"],\"macros\":[\"dep:axum-macros\"],\"matched-path\":[],\"multipart\":[\"dep:multer\"],\"original-uri\":[],\"query\":[\"dep:form_urlencoded\",\"dep:serde_urlencoded\",\"dep:serde_path_to_error\"],\"tokio\":[\"dep:hyper-util\",\"dep:tokio\",\"tokio/net\",\"tokio/rt\",\"tower/make\",\"tokio/macros\"],\"tower-log\":[\"tower/log\"],\"tracing\":[\"dep:tracing\",\"axum-core/tracing\"],\"ws\":[\"dep:hyper\",\"tokio\",\"dep:tokio-tungstenite\",\"dep:sha1\",\"dep:base64\"]}}", "backtrace_0.3.76": "{\"dependencies\":[{\"default_features\":false,\"name\":\"addr2line\",\"req\":\"^0.25.0\",\"target\":\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"cpp_demangle\",\"optional\":true,\"req\":\"^0.5.0\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.156\",\"target\":\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\"},{\"kind\":\"dev\",\"name\":\"libloading\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"miniz_oxide\",\"req\":\"^0.8\",\"target\":\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\"},{\"default_features\":false,\"features\":[\"read_core\",\"elf\",\"macho\",\"pe\",\"xcoff\",\"unaligned\",\"archive\"],\"name\":\"object\",\"req\":\"^0.37.0\",\"target\":\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\"},{\"name\":\"rustc-demangle\",\"req\":\"^0.1.24\"},{\"default_features\":false,\"name\":\"ruzstd\",\"optional\":true,\"req\":\"^0.8.1\",\"target\":\"cfg(not(all(windows, target_env = \\\"msvc\\\", not(target_vendor = \\\"uwp\\\"))))\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"windows-link\",\"req\":\"^0.2\",\"target\":\"cfg(any(windows, target_os = \\\"cygwin\\\"))\"}],\"features\":{\"coresymbolication\":[],\"dbghelp\":[],\"default\":[\"std\"],\"dl_iterate_phdr\":[],\"dladdr\":[],\"kernel32\":[],\"libunwind\":[],\"ruzstd\":[\"dep:ruzstd\"],\"serialize-serde\":[\"serde\"],\"std\":[],\"unix-backtrace\":[]}}", - "base16ct_0.2.0": "{\"dependencies\":[],\"features\":{\"alloc\":[],\"std\":[\"alloc\"]}}", "base64-simd_0.8.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"base64\",\"req\":\"^0.20.0\"},{\"kind\":\"dev\",\"name\":\"const-str\",\"req\":\"^0.5.3\"},{\"features\":[\"js\"],\"kind\":\"dev\",\"name\":\"getrandom\",\"req\":\"^0.2.8\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"outref\",\"req\":\"^0.5.0\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"name\":\"vsimd\",\"req\":\"^0.8.0\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.33\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"}],\"features\":{\"alloc\":[\"vsimd/alloc\"],\"default\":[\"std\",\"detect\"],\"detect\":[\"vsimd/detect\"],\"std\":[\"alloc\",\"vsimd/std\"],\"unstable\":[\"vsimd/unstable\"]}}", "base64_0.21.7": "{\"dependencies\":[{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^3.2.25\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.13.0\"},{\"kind\":\"dev\",\"name\":\"rstest_reuse\",\"req\":\"^0.6.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"strum\",\"req\":\"^0.25\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", "base64_0.22.1": "{\"dependencies\":[{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"clap\",\"req\":\"^3.2.25\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4.0\"},{\"kind\":\"dev\",\"name\":\"once_cell\",\"req\":\"^1\"},{\"features\":[\"small_rng\"],\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"kind\":\"dev\",\"name\":\"rstest\",\"req\":\"^0.13.0\"},{\"kind\":\"dev\",\"name\":\"rstest_reuse\",\"req\":\"^0.6.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"strum\",\"req\":\"^0.25\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[\"alloc\"]}}", @@ -798,7 +797,6 @@ "crossbeam-utils_0.8.21": "{\"dependencies\":[{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7.1\",\"target\":\"cfg(crossbeam_loom)\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"}],\"features\":{\"default\":[\"std\"],\"nightly\":[],\"std\":[]}}", "crossterm_winapi_0.9.1": "{\"dependencies\":[{\"features\":[\"winbase\",\"consoleapi\",\"processenv\",\"handleapi\",\"synchapi\",\"impl-default\"],\"name\":\"winapi\",\"req\":\"^0.3.8\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "crunchy_0.2.4": "{\"dependencies\":[],\"features\":{\"default\":[\"limit_128\"],\"limit_1024\":[],\"limit_128\":[],\"limit_2048\":[],\"limit_256\":[],\"limit_512\":[],\"limit_64\":[],\"std\":[]}}", - "crypto-bigint_0.5.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"der\",\"optional\":true,\"req\":\"^0.7\"},{\"name\":\"generic-array\",\"optional\":true,\"req\":\"^0.14\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-bigint\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"num-integer\",\"req\":\"^0.1\"},{\"kind\":\"dev\",\"name\":\"num-traits\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"rand_chacha\",\"req\":\"^0.3\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6.4\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"rlp\",\"optional\":true,\"req\":\"^0.5\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.4\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"serdect?/alloc\"],\"default\":[\"rand\"],\"extra-sizes\":[],\"rand\":[\"rand_core/std\"],\"serde\":[\"dep:serdect\"]}}", "crypto-common_0.1.7": "{\"dependencies\":[{\"features\":[\"more_lengths\"],\"name\":\"generic-array\",\"req\":\"=0.14.7\"},{\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6\"},{\"name\":\"typenum\",\"req\":\"^1.14\"}],\"features\":{\"getrandom\":[\"rand_core/getrandom\"],\"std\":[]}}", "crypto_box_0.9.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aead\",\"req\":\"^0.5.2\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"blake2\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"chacha20\",\"optional\":true,\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"crypto_secretbox\",\"req\":\"^0.1.1\"},{\"default_features\":false,\"features\":[\"zeroize\"],\"name\":\"curve25519-dalek\",\"req\":\"^4\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"kind\":\"dev\",\"name\":\"rmp-serde\",\"req\":\"^1\"},{\"name\":\"salsa20\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"zeroize\",\"req\":\"^1\"}],\"features\":{\"alloc\":[\"aead/alloc\"],\"chacha20\":[\"dep:chacha20\",\"crypto_secretbox/chacha20\"],\"default\":[\"alloc\",\"getrandom\",\"salsa20\"],\"getrandom\":[\"aead/getrandom\",\"rand_core\"],\"heapless\":[\"aead/heapless\"],\"rand_core\":[\"aead/rand_core\"],\"salsa20\":[\"dep:salsa20\",\"crypto_secretbox/salsa20\"],\"seal\":[\"dep:blake2\",\"alloc\"],\"serde\":[\"dep:serdect\"],\"std\":[\"aead/std\"]}}", "crypto_secretbox_0.1.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"aead\",\"req\":\"^0.5\"},{\"features\":[\"zeroize\"],\"name\":\"chacha20\",\"optional\":true,\"req\":\"^0.9\"},{\"default_features\":false,\"name\":\"cipher\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"zeroize\"],\"name\":\"generic-array\",\"req\":\"^0.14.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"name\":\"poly1305\",\"req\":\"^0.8\"},{\"features\":[\"zeroize\"],\"name\":\"salsa20\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"zeroize\",\"req\":\"^1\"}],\"features\":{\"alloc\":[\"aead/alloc\"],\"default\":[\"alloc\",\"getrandom\",\"salsa20\"],\"getrandom\":[\"aead/getrandom\",\"rand_core\"],\"heapless\":[\"aead/heapless\"],\"rand_core\":[\"aead/rand_core\"],\"std\":[\"aead/std\",\"alloc\"],\"stream\":[\"aead/stream\"]}}", @@ -872,11 +870,9 @@ "dylint_linting_5.0.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"assert_cmd\",\"req\":\"^2.0\"},{\"name\":\"cargo_metadata\",\"req\":\"^0.23\"},{\"features\":[\"config\"],\"name\":\"dylint_internal\",\"req\":\"=5.0.0\"},{\"name\":\"paste\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"rustc_version\",\"req\":\"^0.4\"},{\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.23\"},{\"name\":\"thiserror\",\"req\":\"^2.0\"},{\"name\":\"toml\",\"req\":\"^0.9\"},{\"kind\":\"build\",\"name\":\"toml\",\"req\":\"^0.9\"}],\"features\":{\"constituent\":[]}}", "dylint_testing_5.0.0": "{\"dependencies\":[{\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"cargo_metadata\",\"req\":\"^0.23\"},{\"name\":\"compiletest_rs\",\"req\":\"^0.11\"},{\"name\":\"dylint\",\"req\":\"=5.0.0\"},{\"name\":\"dylint_internal\",\"req\":\"=5.0.0\"},{\"name\":\"env_logger\",\"req\":\"^0.11\"},{\"name\":\"once_cell\",\"req\":\"^1.21\"},{\"name\":\"regex\",\"req\":\"^1.11\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"tempfile\",\"req\":\"^3.23\"}],\"features\":{\"default\":[],\"deny_warnings\":[]}}", "dyn-clone_1.0.20": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"rustversion\",\"req\":\"^1.0\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.66\"}],\"features\":{}}", - "ecdsa_0.16.9": "{\"dependencies\":[{\"name\":\"der\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"digest\",\"optional\":true,\"req\":\"^0.10.7\"},{\"default_features\":false,\"features\":[\"digest\",\"sec1\"],\"name\":\"elliptic-curve\",\"req\":\"^0.13.6\"},{\"default_features\":false,\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"elliptic-curve\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"name\":\"rfc6979\",\"optional\":true,\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"oid\"],\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"default_features\":false,\"features\":[\"rand_core\"],\"name\":\"signature\",\"req\":\"^2.0, <2.3\"},{\"default_features\":false,\"name\":\"spki\",\"optional\":true,\"req\":\"^0.7.2\"}],\"features\":{\"alloc\":[\"elliptic-curve/alloc\",\"signature/alloc\",\"spki/alloc\"],\"arithmetic\":[\"elliptic-curve/arithmetic\"],\"default\":[\"digest\"],\"dev\":[\"arithmetic\",\"digest\",\"elliptic-curve/dev\",\"hazmat\"],\"digest\":[\"dep:digest\",\"signature/digest\"],\"hazmat\":[],\"pem\":[\"elliptic-curve/pem\",\"pkcs8\"],\"pkcs8\":[\"digest\",\"elliptic-curve/pkcs8\",\"der\"],\"serde\":[\"elliptic-curve/serde\",\"serdect\"],\"signing\":[\"arithmetic\",\"digest\",\"hazmat\",\"rfc6979\"],\"std\":[\"alloc\",\"elliptic-curve/std\",\"signature/std\"],\"verifying\":[\"arithmetic\",\"digest\",\"hazmat\"]}}", "ed25519-dalek_2.2.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"blake2\",\"req\":\"^0.10\"},{\"features\":[\"html_reports\"],\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.5\"},{\"default_features\":false,\"features\":[\"digest\"],\"name\":\"curve25519-dalek\",\"req\":\"^4\"},{\"default_features\":false,\"features\":[\"digest\",\"rand_core\"],\"kind\":\"dev\",\"name\":\"curve25519-dalek\",\"req\":\"^4\"},{\"default_features\":false,\"name\":\"ed25519\",\"req\":\">=2.2, <2.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"merlin\",\"optional\":true,\"req\":\"^3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"optional\":true,\"req\":\"^0.6.4\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6.4\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"default_features\":false,\"name\":\"sha2\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"sha3\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"signature\",\"optional\":true,\"req\":\">=2.0, <2.3\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.3.0\"},{\"kind\":\"dev\",\"name\":\"toml\",\"req\":\"^0.7\"},{\"default_features\":false,\"features\":[\"static_secrets\"],\"kind\":\"dev\",\"name\":\"x25519-dalek\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1.5\"}],\"features\":{\"alloc\":[\"curve25519-dalek/alloc\",\"ed25519/alloc\",\"serde?/alloc\",\"zeroize/alloc\"],\"asm\":[\"sha2/asm\"],\"batch\":[\"alloc\",\"merlin\",\"rand_core\"],\"default\":[\"fast\",\"std\",\"zeroize\"],\"digest\":[\"signature/digest\"],\"fast\":[\"curve25519-dalek/precomputed-tables\"],\"hazmat\":[],\"legacy_compatibility\":[\"curve25519-dalek/legacy_compatibility\"],\"pem\":[\"alloc\",\"ed25519/pem\",\"pkcs8\"],\"pkcs8\":[\"ed25519/pkcs8\"],\"rand_core\":[\"dep:rand_core\"],\"serde\":[\"dep:serde\",\"ed25519/serde\"],\"std\":[\"alloc\",\"ed25519/std\",\"serde?/std\",\"sha2/std\"],\"zeroize\":[\"dep:zeroize\",\"curve25519-dalek/zeroize\"]}}", "ed25519_2.2.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1\"},{\"features\":[\"rand_core\"],\"kind\":\"dev\",\"name\":\"ed25519-dalek\",\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"name\":\"pkcs8\",\"optional\":true,\"req\":\"^0.10\"},{\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"features\":[\"signature\"],\"kind\":\"dev\",\"name\":\"ring-compat\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"serde_bytes\",\"optional\":true,\"req\":\"^0.11\"},{\"default_features\":false,\"name\":\"signature\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"pkcs8?/alloc\"],\"default\":[\"std\"],\"pem\":[\"alloc\",\"pkcs8/pem\"],\"serde_bytes\":[\"serde\",\"dep:serde_bytes\"],\"std\":[\"pkcs8?/std\",\"signature/std\"]}}", "either_1.15.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\",\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.95\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"}],\"features\":{\"default\":[\"std\"],\"std\":[],\"use_std\":[\"std\"]}}", - "elliptic-curve_0.13.8": "{\"dependencies\":[{\"name\":\"base16ct\",\"req\":\"^0.2\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"base64ct\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"rand_core\",\"generic-array\",\"zeroize\"],\"name\":\"crypto-bigint\",\"req\":\"^0.5\"},{\"name\":\"digest\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"ff\",\"optional\":true,\"req\":\"^0.13\"},{\"default_features\":false,\"features\":[\"zeroize\"],\"name\":\"generic-array\",\"req\":\"^0.14.6\"},{\"default_features\":false,\"name\":\"group\",\"optional\":true,\"req\":\"^0.13\"},{\"name\":\"hex-literal\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"hkdf\",\"optional\":true,\"req\":\"^0.12.1\"},{\"features\":[\"alloc\"],\"name\":\"pem-rfc7468\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"pkcs8\",\"optional\":true,\"req\":\"^0.10.2\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6.4\"},{\"features\":[\"subtle\",\"zeroize\"],\"name\":\"sec1\",\"optional\":true,\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.47\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"kind\":\"dev\",\"name\":\"sha3\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"tap\",\"optional\":true,\"req\":\"^1.0.1\"},{\"default_features\":false,\"name\":\"zeroize\",\"req\":\"^1.7\"}],\"features\":{\"alloc\":[\"base16ct/alloc\",\"ff?/alloc\",\"group?/alloc\",\"pkcs8?/alloc\",\"sec1?/alloc\",\"zeroize/alloc\"],\"arithmetic\":[\"group\"],\"bits\":[\"arithmetic\",\"ff/bits\",\"dep:tap\"],\"default\":[\"arithmetic\"],\"dev\":[\"arithmetic\",\"dep:hex-literal\",\"pem\",\"pkcs8\"],\"ecdh\":[\"arithmetic\",\"digest\",\"dep:hkdf\"],\"group\":[\"dep:group\",\"ff\"],\"hash2curve\":[\"arithmetic\",\"digest\"],\"hazmat\":[],\"jwk\":[\"dep:base64ct\",\"dep:serde_json\",\"alloc\",\"serde\",\"zeroize/alloc\"],\"pem\":[\"dep:pem-rfc7468\",\"alloc\",\"arithmetic\",\"pkcs8\",\"sec1/pem\"],\"pkcs8\":[\"dep:pkcs8\",\"sec1\"],\"serde\":[\"dep:serdect\",\"alloc\",\"pkcs8\",\"sec1/serde\"],\"std\":[\"alloc\",\"rand_core/std\",\"pkcs8?/std\",\"sec1?/std\"],\"voprf\":[\"digest\"]}}", "ena_0.14.3": "{\"dependencies\":[{\"name\":\"dogged\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"log\",\"req\":\"^0.4\"}],\"features\":{\"bench\":[],\"persistent\":[\"dogged\"]}}", "encode_unicode_1.0.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ascii\",\"optional\":true,\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"lazy_static\",\"req\":\"^1.0\",\"target\":\"cfg(unix)\"},{\"features\":[\"https-native\"],\"kind\":\"dev\",\"name\":\"minreq\",\"req\":\"^2.6\"}],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "encoding_rs_0.8.35": "{\"dependencies\":[{\"name\":\"any_all_workaround\",\"optional\":true,\"req\":\"^0.1.0\"},{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.0\"},{\"name\":\"cfg-if\",\"req\":\"^1.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_derive\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"fast-big5-hanzi-encode\":[],\"fast-gb-hanzi-encode\":[],\"fast-hangul-encode\":[],\"fast-hanja-encode\":[],\"fast-kanji-encode\":[],\"fast-legacy-encode\":[\"fast-hangul-encode\",\"fast-hanja-encode\",\"fast-kanji-encode\",\"fast-gb-hanzi-encode\",\"fast-big5-hanzi-encode\"],\"less-slow-big5-hanzi-encode\":[],\"less-slow-gb-hanzi-encode\":[],\"less-slow-kanji-encode\":[],\"simd-accel\":[\"any_all_workaround\"]}}", @@ -907,7 +903,6 @@ "fax_derive_0.2.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1.0\"},{\"name\":\"quote\",\"req\":\"^1.0\"},{\"name\":\"syn\",\"req\":\"^2.0\"}],\"features\":{}}", "fd-lock_4.0.4": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"features\":[\"fs\"],\"name\":\"rustix\",\"req\":\"^1.0.0\",\"target\":\"cfg(unix)\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3.0.8\"},{\"features\":[\"Win32_Foundation\",\"Win32_Storage_FileSystem\",\"Win32_System_IO\"],\"name\":\"windows-sys\",\"req\":\">=0.52.0, <0.60.0\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "fdeflate_0.3.7": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"miniz_oxide\",\"req\":\"^0.7.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.5\"},{\"name\":\"simd-adler32\",\"req\":\"^0.3.4\"}],\"features\":{}}", - "ff_0.13.1": "{\"dependencies\":[{\"default_features\":false,\"name\":\"bitvec\",\"optional\":true,\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"blake2b_simd\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"byteorder\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"ff_derive\",\"optional\":true,\"req\":\"^0.13.1\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"features\":[\"i128\"],\"name\":\"subtle\",\"req\":\"^2.2.1\"}],\"features\":{\"alloc\":[],\"bits\":[\"bitvec\"],\"default\":[\"bits\",\"std\"],\"derive\":[\"byteorder\",\"ff_derive\"],\"derive_bits\":[\"bits\",\"ff_derive/bits\"],\"std\":[\"alloc\"]}}", "fiat-crypto_0.2.9": "{\"dependencies\":[],\"features\":{\"default\":[\"std\"],\"std\":[]}}", "filedescriptor_0.8.3": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2\"},{\"name\":\"thiserror\",\"req\":\"^1.0\"},{\"features\":[\"winuser\",\"handleapi\",\"fileapi\",\"namedpipeapi\",\"processthreadsapi\",\"winsock2\",\"processenv\"],\"name\":\"winapi\",\"req\":\"^0.3\",\"target\":\"cfg(windows)\"}],\"features\":{}}", "filetime_0.2.27": "{\"dependencies\":[{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.27\",\"target\":\"cfg(unix)\"},{\"name\":\"libredox\",\"req\":\"^0.1.0\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{}}", @@ -1035,7 +1030,6 @@ "glob_0.3.3": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"tempdir\",\"req\":\"^0.3\"}],\"features\":{}}", "globset_0.4.18": "{\"dependencies\":[{\"name\":\"aho-corasick\",\"req\":\"^1.1.1\"},{\"features\":[\"derive\"],\"name\":\"arbitrary\",\"optional\":true,\"req\":\"^1.3.2\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"bstr\",\"req\":\"^1.6.2\"},{\"kind\":\"dev\",\"name\":\"glob\",\"req\":\"^0.3.1\"},{\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.20\"},{\"default_features\":false,\"features\":[\"std\",\"perf\",\"syntax\",\"meta\",\"nfa\",\"hybrid\"],\"name\":\"regex-automata\",\"req\":\"^0.4.0\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"regex-syntax\",\"req\":\"^0.8.0\"},{\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.188\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.107\"}],\"features\":{\"arbitrary\":[\"dep:arbitrary\"],\"default\":[\"log\"],\"serde1\":[\"serde\"],\"simd-accel\":[]}}", "gobject-sys_0.21.5": "{\"dependencies\":[{\"name\":\"glib-sys\",\"req\":\"^0.21\"},{\"name\":\"libc\",\"req\":\"^0.2\"},{\"kind\":\"dev\",\"name\":\"shell-words\",\"req\":\"^1.0.0\"},{\"kind\":\"build\",\"name\":\"system-deps\",\"req\":\"^7\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"}],\"features\":{\"v2_58\":[],\"v2_62\":[\"v2_58\"],\"v2_66\":[\"v2_62\"],\"v2_68\":[\"v2_66\"],\"v2_70\":[\"v2_68\"],\"v2_72\":[\"v2_70\"],\"v2_74\":[\"v2_72\"],\"v2_76\":[\"v2_74\"],\"v2_78\":[\"v2_74\"],\"v2_80\":[\"v2_78\"],\"v2_82\":[\"v2_80\"],\"v2_84\":[\"v2_82\"],\"v2_86\":[\"v2_84\"]}}", - "group_0.13.0": "{\"dependencies\":[{\"default_features\":false,\"name\":\"ff\",\"req\":\"^0.13\"},{\"name\":\"memuse\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"rand\",\"optional\":true,\"req\":\"^0.8\"},{\"default_features\":false,\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"name\":\"rand_xorshift\",\"optional\":true,\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2.2.1\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\"],\"tests\":[\"alloc\",\"rand\",\"rand_xorshift\"],\"wnaf-memuse\":[\"alloc\",\"memuse\"]}}", "gzip-header_1.0.0": "{\"dependencies\":[{\"name\":\"crc32fast\",\"req\":\"^1.2.1\"}],\"features\":{}}", "h2_0.4.13": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^1\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", "h2_0.4.6": "{\"dependencies\":[{\"name\":\"atomic-waker\",\"req\":\"^1.0.0\"},{\"name\":\"bytes\",\"req\":\"^1\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\"},{\"name\":\"fnv\",\"req\":\"^1.0.5\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3\"},{\"default_features\":false,\"name\":\"futures-sink\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"hex\",\"req\":\"^0.4.3\"},{\"name\":\"http\",\"req\":\"^1\"},{\"features\":[\"std\"],\"name\":\"indexmap\",\"req\":\"^2\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quickcheck\",\"req\":\"^1.0.3\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.4\"},{\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0.0\"},{\"kind\":\"dev\",\"name\":\"serde_json\",\"req\":\"^1.0.0\"},{\"name\":\"slab\",\"req\":\"^0.4.2\"},{\"features\":[\"io-util\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"rt-multi-thread\",\"macros\",\"sync\",\"net\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"kind\":\"dev\",\"name\":\"tokio-rustls\",\"req\":\"^0.26\"},{\"features\":[\"codec\",\"io\"],\"name\":\"tokio-util\",\"req\":\"^0.7.1\"},{\"default_features\":false,\"features\":[\"std\"],\"name\":\"tracing\",\"req\":\"^0.1.35\"},{\"kind\":\"dev\",\"name\":\"walkdir\",\"req\":\"^2.3.2\"},{\"kind\":\"dev\",\"name\":\"webpki-roots\",\"req\":\"^0.26\"}],\"features\":{\"stream\":[],\"unstable\":[]}}", @@ -1282,7 +1276,6 @@ "os_pipe_1.2.3": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.62\",\"target\":\"cfg(not(windows))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Pipes\",\"Win32_Security\"],\"name\":\"windows-sys\",\"req\":\">=0.28, <=0.61\",\"target\":\"cfg(windows)\"}],\"features\":{\"io_safety\":[]}}", "outref_0.5.2": "{\"dependencies\":[],\"features\":{}}", "owo-colors_4.3.0": "{\"dependencies\":[{\"name\":\"supports-color\",\"optional\":true,\"req\":\"^3.0.0\"},{\"name\":\"supports-color-2\",\"optional\":true,\"package\":\"supports-color\",\"req\":\"^2.0\"}],\"features\":{\"alloc\":[],\"supports-colors\":[\"dep:supports-color-2\",\"supports-color\"]}}", - "p256_0.13.2": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"blobby\",\"req\":\"^0.3\"},{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.4\"},{\"default_features\":false,\"features\":[\"der\"],\"name\":\"ecdsa-core\",\"optional\":true,\"package\":\"ecdsa\",\"req\":\"^0.16\"},{\"default_features\":false,\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"ecdsa-core\",\"package\":\"ecdsa\",\"req\":\"^0.16\"},{\"default_features\":false,\"features\":[\"hazmat\",\"sec1\"],\"name\":\"elliptic-curve\",\"req\":\"^0.13.1\"},{\"name\":\"hex-literal\",\"optional\":true,\"req\":\"^0.4\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"name\":\"primeorder\",\"optional\":true,\"req\":\"^0.13\"},{\"features\":[\"dev\"],\"kind\":\"dev\",\"name\":\"primeorder\",\"req\":\"^0.13\"},{\"kind\":\"dev\",\"name\":\"proptest\",\"req\":\"^1\"},{\"features\":[\"getrandom\"],\"kind\":\"dev\",\"name\":\"rand_core\",\"req\":\"^0.6\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10\"}],\"features\":{\"alloc\":[\"ecdsa-core?/alloc\",\"elliptic-curve/alloc\"],\"arithmetic\":[\"dep:primeorder\",\"elliptic-curve/arithmetic\"],\"bits\":[\"arithmetic\",\"elliptic-curve/bits\"],\"default\":[\"arithmetic\",\"ecdsa\",\"pem\",\"std\"],\"digest\":[\"ecdsa-core/digest\",\"ecdsa-core/hazmat\"],\"ecdh\":[\"arithmetic\",\"elliptic-curve/ecdh\"],\"ecdsa\":[\"arithmetic\",\"ecdsa-core/signing\",\"ecdsa-core/verifying\",\"sha256\"],\"expose-field\":[\"arithmetic\"],\"hash2curve\":[\"arithmetic\",\"elliptic-curve/hash2curve\"],\"jwk\":[\"elliptic-curve/jwk\"],\"pem\":[\"elliptic-curve/pem\",\"ecdsa-core/pem\",\"pkcs8\"],\"pkcs8\":[\"ecdsa-core?/pkcs8\",\"elliptic-curve/pkcs8\"],\"serde\":[\"ecdsa-core?/serde\",\"elliptic-curve/serde\",\"primeorder?/serde\",\"serdect\"],\"sha256\":[\"digest\",\"sha2\"],\"std\":[\"alloc\",\"ecdsa-core?/std\",\"elliptic-curve/std\"],\"test-vectors\":[\"dep:hex-literal\"],\"voprf\":[\"elliptic-curve/voprf\",\"sha2\"]}}", "parking_2.2.1": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"easy-parallel\",\"req\":\"^3.0.0\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\",\"target\":\"cfg(loom)\"}],\"features\":{}}", "parking_lot_0.12.5": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"bincode\",\"req\":\"^1.3.3\"},{\"name\":\"lock_api\",\"req\":\"^0.4.14\"},{\"name\":\"parking_lot_core\",\"req\":\"^0.9.12\"},{\"kind\":\"dev\",\"name\":\"rand\",\"req\":\"^0.8.3\"}],\"features\":{\"arc_lock\":[\"lock_api/arc_lock\"],\"deadlock_detection\":[\"parking_lot_core/deadlock_detection\"],\"default\":[],\"hardware-lock-elision\":[],\"nightly\":[\"parking_lot_core/nightly\",\"lock_api/nightly\"],\"owning_ref\":[\"lock_api/owning_ref\"],\"send_guard\":[],\"serde\":[\"lock_api/serde\"]}}", "parking_lot_core_0.9.12": "{\"dependencies\":[{\"name\":\"backtrace\",\"optional\":true,\"req\":\"^0.3.60\"},{\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"libc\",\"req\":\"^0.2.95\",\"target\":\"cfg(unix)\"},{\"name\":\"petgraph\",\"optional\":true,\"req\":\"^0.6.0\"},{\"name\":\"redox_syscall\",\"req\":\"^0.5\",\"target\":\"cfg(target_os = \\\"redox\\\")\"},{\"name\":\"smallvec\",\"req\":\"^1.6.1\"},{\"name\":\"windows-link\",\"req\":\"^0.2.0\",\"target\":\"cfg(windows)\"}],\"features\":{\"deadlock_detection\":[\"petgraph\",\"backtrace\"],\"nightly\":[]}}", @@ -1332,7 +1325,6 @@ "predicates_3.1.3": "{\"dependencies\":[{\"name\":\"anstyle\",\"req\":\"^1.0.0\"},{\"name\":\"difflib\",\"optional\":true,\"req\":\"^0.4\"},{\"name\":\"float-cmp\",\"optional\":true,\"req\":\"^0.10\"},{\"name\":\"normalize-line-endings\",\"optional\":true,\"req\":\"^0.3.0\"},{\"name\":\"predicates-core\",\"req\":\"^1.0\"},{\"kind\":\"dev\",\"name\":\"predicates-tree\",\"req\":\"^1.0\"},{\"name\":\"regex\",\"optional\":true,\"req\":\"^1.0\"}],\"features\":{\"color\":[],\"default\":[\"diff\",\"regex\",\"float-cmp\",\"normalize-line-endings\",\"color\"],\"diff\":[\"dep:difflib\"],\"unstable\":[]}}", "pretty_assertions_1.4.1": "{\"dependencies\":[{\"name\":\"diff\",\"req\":\"^0.1.12\"},{\"name\":\"yansi\",\"req\":\"^1.0.1\"}],\"features\":{\"alloc\":[],\"default\":[\"std\"],\"std\":[],\"unstable\":[]}}", "prettyplease_0.2.37": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"indoc\",\"req\":\"^2\"},{\"default_features\":false,\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.80\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.35\"},{\"default_features\":false,\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2.0.105\"},{\"default_features\":false,\"features\":[\"clone-impls\",\"extra-traits\",\"parsing\",\"printing\",\"visit-mut\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.105\"}],\"features\":{\"verbatim\":[\"syn/parsing\"]}}", - "primeorder_0.13.6": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"arithmetic\",\"sec1\"],\"name\":\"elliptic-curve\",\"req\":\"^0.13.7\"},{\"default_features\":false,\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"}],\"features\":{\"alloc\":[\"elliptic-curve/alloc\"],\"dev\":[],\"serde\":[\"elliptic-curve/serde\",\"serdect\"],\"std\":[\"alloc\",\"elliptic-curve/std\"]}}", "proc-macro-crate_3.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"proc-macro2\",\"req\":\"^1.0.94\"},{\"kind\":\"dev\",\"name\":\"quote\",\"req\":\"^1.0.39\"},{\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2.0.99\"},{\"default_features\":false,\"features\":[\"parse\"],\"name\":\"toml_edit\",\"req\":\"^0.23.2\"}],\"features\":{}}", "proc-macro-error-attr2_2.0.0": "{\"dependencies\":[{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"}],\"features\":{}}", "proc-macro-error2_2.0.1": "{\"dependencies\":[{\"name\":\"proc-macro-error-attr2\",\"req\":\"=2.0.0\"},{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"syn\",\"optional\":true,\"req\":\"^2\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"syn\",\"req\":\"^2\"},{\"features\":[\"diff\"],\"kind\":\"dev\",\"name\":\"trybuild\",\"req\":\"^1.0.99\"}],\"features\":{\"default\":[\"syn-error\"],\"nightly\":[],\"syn-error\":[\"dep:syn\"]}}", @@ -1415,7 +1407,6 @@ "reqwest_0.12.28": "{\"dependencies\":[{\"name\":\"base64\",\"req\":\"^0.22\"},{\"kind\":\"dev\",\"name\":\"brotli_crate\",\"package\":\"brotli\",\"req\":\"^8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"bytes\",\"req\":\"^1.2\"},{\"name\":\"cookie_crate\",\"optional\":true,\"package\":\"cookie\",\"req\":\"^0.18.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"cookie_store\",\"optional\":true,\"req\":\"^0.22.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"doc-comment\",\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"encoding_rs\",\"optional\":true,\"req\":\"^0.8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"env_logger\",\"req\":\"^0.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"flate2\",\"req\":\"^1.0.13\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"futures-channel\",\"optional\":true,\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"futures-core\",\"req\":\"^0.3.28\"},{\"default_features\":false,\"name\":\"futures-util\",\"optional\":true,\"req\":\"^0.3.28\"},{\"default_features\":false,\"features\":[\"std\",\"alloc\"],\"kind\":\"dev\",\"name\":\"futures-util\",\"req\":\"^0.3.28\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h2\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h3\",\"optional\":true,\"req\":\"^0.0.8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"h3-quinn\",\"optional\":true,\"req\":\"^0.0.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"tokio\"],\"name\":\"hickory-resolver\",\"optional\":true,\"req\":\"^0.25\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"http\",\"req\":\"^1.1\"},{\"name\":\"http-body\",\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"http-body-util\",\"req\":\"^0.1.2\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"client\"],\"name\":\"hyper\",\"req\":\"^1.1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"http1\",\"http2\",\"client\",\"server\"],\"kind\":\"dev\",\"name\":\"hyper\",\"req\":\"^1.1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"http1\",\"tls12\"],\"name\":\"hyper-rustls\",\"optional\":true,\"req\":\"^0.27.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"hyper-tls\",\"optional\":true,\"req\":\"^0.6\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"client\",\"client-legacy\",\"client-proxy\",\"tokio\"],\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"http1\",\"http2\",\"client\",\"client-legacy\",\"server-auto\",\"server-graceful\",\"tokio\"],\"kind\":\"dev\",\"name\":\"hyper-util\",\"req\":\"^0.1.12\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"js-sys\",\"req\":\"^0.3.77\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0\"},{\"name\":\"log\",\"req\":\"^0.4.17\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"mime\",\"optional\":true,\"req\":\"^0.3.16\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"name\":\"mime_guess\",\"optional\":true,\"req\":\"^2.0\"},{\"name\":\"native-tls-crate\",\"optional\":true,\"package\":\"native-tls\",\"req\":\"^0.2.10\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"num_cpus\",\"req\":\"^1.0\"},{\"name\":\"once_cell\",\"optional\":true,\"req\":\"^1.18\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"percent-encoding\",\"req\":\"^2.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2.11\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"rustls\",\"runtime-tokio\"],\"name\":\"quinn\",\"optional\":true,\"req\":\"^0.11.1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"std\",\"tls12\"],\"name\":\"rustls\",\"optional\":true,\"req\":\"^0.23.4\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"rustls-native-certs\",\"optional\":true,\"req\":\"^0.8.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"features\":[\"std\"],\"name\":\"rustls-pki-types\",\"optional\":true,\"req\":\"^1.9.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"serde\",\"req\":\"^1.0\"},{\"features\":[\"derive\"],\"kind\":\"dev\",\"name\":\"serde\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"serde_json\",\"req\":\"^1.0\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0\"},{\"name\":\"serde_urlencoded\",\"req\":\"^0.7.1\"},{\"features\":[\"futures\"],\"name\":\"sync_wrapper\",\"req\":\"^1.0\"},{\"default_features\":false,\"features\":[\"net\",\"time\"],\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"macros\",\"rt-multi-thread\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"tokio-native-tls\",\"optional\":true,\"req\":\"^0.3.0\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"tls12\"],\"name\":\"tokio-rustls\",\"optional\":true,\"req\":\"^0.26\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"io\"],\"name\":\"tokio-util\",\"optional\":true,\"req\":\"^0.7.9\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"retry\",\"timeout\",\"util\"],\"name\":\"tower\",\"req\":\"^0.5.2\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"default_features\":false,\"features\":[\"limit\"],\"kind\":\"dev\",\"name\":\"tower\",\"req\":\"^0.5.2\"},{\"default_features\":false,\"features\":[\"follow-redirect\"],\"name\":\"tower-http\",\"req\":\"^0.6.8\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"tower-service\",\"req\":\"^0.3\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"name\":\"url\",\"req\":\"^2.4\"},{\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"serde-serialize\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen\",\"req\":\"^0.2.89\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"wasm-bindgen-futures\",\"req\":\"^0.4.18\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"wasm-streams\",\"optional\":true,\"req\":\"^0.4\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"features\":[\"AbortController\",\"AbortSignal\",\"Headers\",\"Request\",\"RequestInit\",\"RequestMode\",\"Response\",\"Window\",\"FormData\",\"Blob\",\"BlobPropertyBag\",\"ServiceWorkerGlobalScope\",\"RequestCredentials\",\"File\",\"ReadableStream\",\"RequestCache\"],\"name\":\"web-sys\",\"req\":\"^0.3.28\",\"target\":\"cfg(target_arch = \\\"wasm32\\\")\"},{\"name\":\"webpki-roots\",\"optional\":true,\"req\":\"^1\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"},{\"kind\":\"dev\",\"name\":\"zstd_crate\",\"package\":\"zstd\",\"req\":\"^0.13\",\"target\":\"cfg(not(target_arch = \\\"wasm32\\\"))\"}],\"features\":{\"__rustls\":[\"dep:hyper-rustls\",\"dep:tokio-rustls\",\"dep:rustls\",\"__tls\"],\"__rustls-ring\":[\"hyper-rustls?/ring\",\"tokio-rustls?/ring\",\"rustls?/ring\",\"quinn?/ring\"],\"__tls\":[\"dep:rustls-pki-types\",\"tokio/io-util\"],\"blocking\":[\"dep:futures-channel\",\"futures-channel?/sink\",\"dep:futures-util\",\"futures-util?/io\",\"futures-util?/sink\",\"tokio/sync\"],\"brotli\":[\"tower-http/decompression-br\"],\"charset\":[\"dep:encoding_rs\",\"dep:mime\"],\"cookies\":[\"dep:cookie_crate\",\"dep:cookie_store\"],\"default\":[\"default-tls\",\"charset\",\"http2\",\"system-proxy\"],\"default-tls\":[\"dep:hyper-tls\",\"dep:native-tls-crate\",\"__tls\",\"dep:tokio-native-tls\"],\"deflate\":[\"tower-http/decompression-deflate\"],\"gzip\":[\"tower-http/decompression-gzip\"],\"hickory-dns\":[\"dep:hickory-resolver\",\"dep:once_cell\"],\"http2\":[\"h2\",\"hyper/http2\",\"hyper-util/http2\",\"hyper-rustls?/http2\"],\"http3\":[\"rustls-tls-manual-roots\",\"dep:h3\",\"dep:h3-quinn\",\"dep:quinn\",\"tokio/macros\"],\"json\":[\"dep:serde_json\"],\"macos-system-configuration\":[\"system-proxy\"],\"multipart\":[\"dep:mime_guess\",\"dep:futures-util\"],\"native-tls\":[\"default-tls\"],\"native-tls-alpn\":[\"native-tls\",\"native-tls-crate?/alpn\",\"hyper-tls?/alpn\"],\"native-tls-vendored\":[\"native-tls\",\"native-tls-crate?/vendored\"],\"rustls-tls\":[\"rustls-tls-webpki-roots\"],\"rustls-tls-manual-roots\":[\"rustls-tls-manual-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-manual-roots-no-provider\":[\"__rustls\"],\"rustls-tls-native-roots\":[\"rustls-tls-native-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-native-roots-no-provider\":[\"dep:rustls-native-certs\",\"hyper-rustls?/native-tokio\",\"__rustls\"],\"rustls-tls-no-provider\":[\"rustls-tls-manual-roots-no-provider\"],\"rustls-tls-webpki-roots\":[\"rustls-tls-webpki-roots-no-provider\",\"__rustls-ring\"],\"rustls-tls-webpki-roots-no-provider\":[\"dep:webpki-roots\",\"hyper-rustls?/webpki-tokio\",\"__rustls\"],\"socks\":[],\"stream\":[\"tokio/fs\",\"dep:futures-util\",\"dep:tokio-util\",\"dep:wasm-streams\"],\"system-proxy\":[\"hyper-util/client-proxy-system\"],\"trust-dns\":[],\"zstd\":[\"tower-http/decompression-zstd\"]}}", "resb_0.1.1": "{\"dependencies\":[{\"name\":\"indexmap\",\"optional\":true,\"req\":\"^2.0.0\"},{\"default_features\":false,\"name\":\"log\",\"optional\":true,\"req\":\"^0.4.17\"},{\"name\":\"nom\",\"optional\":true,\"req\":\"^7.0.0\"},{\"default_features\":false,\"name\":\"potential_utf\",\"req\":\"^0.1.3\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde_core\",\"req\":\"^1.0.220\"}],\"features\":{\"default\":[],\"logging\":[\"dep:log\"],\"serialize\":[\"std\"],\"std\":[],\"text\":[\"dep:indexmap\",\"dep:nom\",\"std\"]}}", "resolv-conf_0.7.6": "{\"dependencies\":[],\"features\":{\"system\":[]}}", - "rfc6979_0.4.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.3\"},{\"default_features\":false,\"features\":[\"reset\"],\"name\":\"hmac\",\"req\":\"^0.12\"},{\"kind\":\"dev\",\"name\":\"sha2\",\"req\":\"^0.10\"},{\"default_features\":false,\"name\":\"subtle\",\"req\":\"^2\"}],\"features\":{}}", "ring_0.17.14": "{\"dependencies\":[{\"default_features\":false,\"kind\":\"build\",\"name\":\"cc\",\"req\":\"^1.2.8\"},{\"default_features\":false,\"name\":\"cfg-if\",\"req\":\"^1.0.0\"},{\"name\":\"getrandom\",\"req\":\"^0.2.10\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(all(any(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), all(target_arch = \\\"arm\\\", target_endian = \\\"little\\\")), any(target_os = \\\"android\\\", target_os = \\\"linux\\\")))\"},{\"default_features\":false,\"name\":\"libc\",\"req\":\"^0.2.155\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_vendor = \\\"apple\\\", any(target_os = \\\"ios\\\", target_os = \\\"macos\\\", target_os = \\\"tvos\\\", target_os = \\\"visionos\\\", target_os = \\\"watchos\\\")))\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"libc\",\"req\":\"^0.2.148\",\"target\":\"cfg(any(unix, windows, target_os = \\\"wasi\\\"))\"},{\"name\":\"untrusted\",\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"std\"],\"kind\":\"dev\",\"name\":\"wasm-bindgen-test\",\"req\":\"^0.3.37\",\"target\":\"cfg(all(target_arch = \\\"wasm32\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"Win32_Foundation\",\"Win32_System_Threading\"],\"name\":\"windows-sys\",\"req\":\"^0.52\",\"target\":\"cfg(all(all(target_arch = \\\"aarch64\\\", target_endian = \\\"little\\\"), target_os = \\\"windows\\\"))\"}],\"features\":{\"alloc\":[],\"default\":[\"alloc\",\"dev_urandom_fallback\"],\"dev_urandom_fallback\":[],\"less-safe-getrandom-custom-or-rdrand\":[],\"less-safe-getrandom-espidf\":[],\"slow_tests\":[],\"std\":[\"alloc\"],\"test_logging\":[],\"unstable-testing-arm-no-hw\":[],\"unstable-testing-arm-no-neon\":[],\"wasm32_unknown_unknown_js\":[\"getrandom/js\"]}}", "rmcp-macros_0.15.0": "{\"dependencies\":[{\"name\":\"darling\",\"req\":\"^0.23\"},{\"name\":\"proc-macro2\",\"req\":\"^1\"},{\"name\":\"quote\",\"req\":\"^1\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"features\":[\"full\"],\"name\":\"syn\",\"req\":\"^2\"}],\"features\":{}}", "rmcp_0.15.0": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"anyhow\",\"req\":\"^1.0\"},{\"name\":\"async-trait\",\"req\":\"^0.1.89\"},{\"kind\":\"dev\",\"name\":\"async-trait\",\"req\":\"^0.1\"},{\"name\":\"axum\",\"optional\":true,\"req\":\"^0.8\"},{\"name\":\"base64\",\"optional\":true,\"req\":\"^0.22\"},{\"name\":\"bytes\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"serde\",\"clock\",\"std\",\"oldtime\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\"))\"},{\"features\":[\"serde\"],\"name\":\"chrono\",\"req\":\"^0.4.38\",\"target\":\"cfg(not(all(target_family = \\\"wasm\\\", target_os = \\\"unknown\\\")))\"},{\"name\":\"futures\",\"req\":\"^0.3\"},{\"name\":\"http\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body\",\"optional\":true,\"req\":\"^1\"},{\"name\":\"http-body-util\",\"optional\":true,\"req\":\"^0.1\"},{\"default_features\":false,\"features\":[\"reqwest\"],\"name\":\"oauth2\",\"optional\":true,\"req\":\"^5.0\"},{\"name\":\"pastey\",\"optional\":true,\"req\":\"^0.2.0\"},{\"name\":\"pin-project-lite\",\"req\":\"^0.2\"},{\"features\":[\"tokio1\"],\"name\":\"process-wrap\",\"optional\":true,\"req\":\"^9.0\"},{\"name\":\"rand\",\"optional\":true,\"req\":\"^0.9\"},{\"default_features\":false,\"features\":[\"json\",\"stream\"],\"name\":\"reqwest\",\"optional\":true,\"req\":\"^0.12\"},{\"name\":\"rmcp-macros\",\"optional\":true,\"req\":\"^0.15.0\"},{\"features\":[\"chrono04\"],\"name\":\"schemars\",\"optional\":true,\"req\":\"^1.0\"},{\"features\":[\"chrono04\"],\"kind\":\"dev\",\"name\":\"schemars\",\"req\":\"^1.1.0\"},{\"features\":[\"derive\",\"rc\"],\"name\":\"serde\",\"req\":\"^1.0\"},{\"name\":\"serde_json\",\"req\":\"^1.0\"},{\"name\":\"sse-stream\",\"optional\":true,\"req\":\"^0.2\"},{\"name\":\"thiserror\",\"req\":\"^2\"},{\"features\":[\"sync\",\"macros\",\"rt\",\"time\"],\"name\":\"tokio\",\"req\":\"^1\"},{\"features\":[\"full\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"name\":\"tokio-stream\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"tokio-util\",\"req\":\"^0.7\"},{\"name\":\"tower-service\",\"optional\":true,\"req\":\"^0.3\"},{\"name\":\"tracing\",\"req\":\"^0.1\"},{\"features\":[\"env-filter\",\"std\",\"fmt\"],\"kind\":\"dev\",\"name\":\"tracing-subscriber\",\"req\":\"^0.3\"},{\"name\":\"url\",\"optional\":true,\"req\":\"^2.4\"},{\"features\":[\"v4\"],\"name\":\"uuid\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"__reqwest\":[\"dep:reqwest\"],\"auth\":[\"dep:oauth2\",\"__reqwest\",\"dep:url\"],\"client\":[\"dep:tokio-stream\"],\"client-side-sse\":[\"dep:sse-stream\",\"dep:http\"],\"default\":[\"base64\",\"macros\",\"server\"],\"elicitation\":[\"dep:url\"],\"macros\":[\"dep:rmcp-macros\",\"dep:pastey\"],\"reqwest\":[\"__reqwest\",\"reqwest?/rustls-tls\"],\"reqwest-native-tls\":[\"__reqwest\",\"reqwest?/native-tls\"],\"reqwest-tls-no-provider\":[\"__reqwest\",\"reqwest?/rustls-tls-no-provider\"],\"schemars\":[\"dep:schemars\"],\"server\":[\"transport-async-rw\",\"dep:schemars\",\"dep:pastey\"],\"server-side-http\":[\"uuid\",\"dep:rand\",\"dep:tokio-stream\",\"dep:http\",\"dep:http-body\",\"dep:http-body-util\",\"dep:bytes\",\"dep:sse-stream\",\"dep:axum\",\"tower\"],\"tower\":[\"dep:tower-service\"],\"transport-async-rw\":[\"tokio/io-util\",\"tokio-util/codec\"],\"transport-child-process\":[\"transport-async-rw\",\"tokio/process\",\"dep:process-wrap\"],\"transport-io\":[\"transport-async-rw\",\"tokio/io-std\"],\"transport-streamable-http-client\":[\"client-side-sse\",\"transport-worker\"],\"transport-streamable-http-client-reqwest\":[\"transport-streamable-http-client\",\"__reqwest\"],\"transport-streamable-http-server\":[\"transport-streamable-http-server-session\",\"server-side-http\",\"transport-worker\"],\"transport-streamable-http-server-session\":[\"transport-async-rw\",\"dep:tokio-stream\"],\"transport-worker\":[\"dep:tokio-stream\"]}}", @@ -1458,7 +1449,6 @@ "scratch_1.0.9": "{\"dependencies\":[],\"features\":{}}", "scrypt_0.11.0": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"rand_core\"],\"name\":\"password-hash\",\"optional\":true,\"req\":\"^0.5\"},{\"features\":[\"rand_core\"],\"kind\":\"dev\",\"name\":\"password-hash\",\"req\":\"^0.5\"},{\"name\":\"pbkdf2\",\"req\":\"^0.12\"},{\"default_features\":false,\"name\":\"salsa20\",\"req\":\"^0.10.2\"},{\"default_features\":false,\"name\":\"sha2\",\"req\":\"^0.10\"}],\"features\":{\"default\":[\"simple\",\"std\"],\"simple\":[\"password-hash\"],\"std\":[\"password-hash/std\"]}}", "sdd_3.0.10": "{\"dependencies\":[{\"kind\":\"dev\",\"name\":\"criterion\",\"req\":\"^0.6\"},{\"name\":\"loom\",\"optional\":true,\"req\":\"^0.7\"},{\"kind\":\"dev\",\"name\":\"static_assertions\",\"req\":\"^1.1\"}],\"features\":{}}", - "sec1_0.7.3": "{\"dependencies\":[{\"default_features\":false,\"name\":\"base16ct\",\"optional\":true,\"req\":\"^0.2\"},{\"features\":[\"oid\"],\"name\":\"der\",\"optional\":true,\"req\":\"^0.7\"},{\"default_features\":false,\"name\":\"generic-array\",\"optional\":true,\"req\":\"^0.14.7\"},{\"kind\":\"dev\",\"name\":\"hex-literal\",\"req\":\"^0.4\"},{\"default_features\":false,\"name\":\"pkcs8\",\"optional\":true,\"req\":\"^0.10\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serdect\",\"optional\":true,\"req\":\"^0.2\"},{\"default_features\":false,\"name\":\"subtle\",\"optional\":true,\"req\":\"^2\"},{\"kind\":\"dev\",\"name\":\"tempfile\",\"req\":\"^3\"},{\"default_features\":false,\"name\":\"zeroize\",\"optional\":true,\"req\":\"^1\"}],\"features\":{\"alloc\":[\"der?/alloc\",\"pkcs8?/alloc\",\"zeroize?/alloc\"],\"default\":[\"der\",\"point\"],\"der\":[\"dep:der\",\"zeroize\"],\"pem\":[\"alloc\",\"der/pem\",\"pkcs8/pem\"],\"point\":[\"dep:base16ct\",\"dep:generic-array\"],\"serde\":[\"dep:serdect\"],\"std\":[\"alloc\",\"der?/std\"],\"zeroize\":[\"dep:zeroize\",\"der?/zeroize\"]}}", "seccompiler_0.5.0": "{\"dependencies\":[{\"name\":\"libc\",\"req\":\"^0.2.153\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1.0.27\"},{\"name\":\"serde_json\",\"optional\":true,\"req\":\"^1.0.9\"}],\"features\":{\"json\":[\"serde\",\"serde_json\"]}}", "secrecy_0.10.3": "{\"dependencies\":[{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"serde\",\"optional\":true,\"req\":\"^1\"},{\"default_features\":false,\"features\":[\"alloc\"],\"name\":\"zeroize\",\"req\":\"^1.6\"}],\"features\":{}}", "secret-service_4.0.0": "{\"dependencies\":[{\"name\":\"aes\",\"optional\":true,\"req\":\"^0.8\"},{\"features\":[\"block-padding\",\"alloc\"],\"name\":\"cbc\",\"optional\":true,\"req\":\"^0.1\"},{\"name\":\"futures-util\",\"req\":\"^0.3\"},{\"name\":\"generic-array\",\"req\":\"^0.14\"},{\"name\":\"hkdf\",\"optional\":true,\"req\":\"^0.12.0\"},{\"name\":\"num\",\"req\":\"^0.4.0\"},{\"name\":\"once_cell\",\"req\":\"^1\"},{\"name\":\"openssl\",\"optional\":true,\"req\":\"^0.10.40\"},{\"name\":\"rand\",\"req\":\"^0.8.1\"},{\"features\":[\"derive\"],\"name\":\"serde\",\"req\":\"^1.0.103\"},{\"name\":\"sha2\",\"optional\":true,\"req\":\"^0.10.0\"},{\"default_features\":false,\"kind\":\"dev\",\"name\":\"test-with\",\"req\":\"^0.8\"},{\"features\":[\"rt\",\"macros\"],\"kind\":\"dev\",\"name\":\"tokio\",\"req\":\"^1\"},{\"default_features\":false,\"name\":\"zbus\",\"req\":\"^4\"}],\"features\":{\"crypto-openssl\":[\"dep:openssl\"],\"crypto-rust\":[\"dep:aes\",\"dep:cbc\",\"dep:sha2\",\"dep:hkdf\"],\"rt-async-io-crypto-openssl\":[\"zbus/async-io\",\"crypto-openssl\"],\"rt-async-io-crypto-rust\":[\"zbus/async-io\",\"crypto-rust\"],\"rt-tokio-crypto-openssl\":[\"zbus/tokio\",\"crypto-openssl\"],\"rt-tokio-crypto-rust\":[\"zbus/tokio\",\"crypto-rust\"]}}",