From c88f5620c0a7c5ea4f410eaf7e5d272900aecf25 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Wed, 13 May 2026 18:58:12 +0100 Subject: [PATCH] Delete tool suggestion marketplace organ --- notes/fresh-workspace-handoff.md | 15 +- state/ledgers.msgpack | Bin 103350 -> 103696 bytes state/map.yaml | 8 +- .../codex-rs/app-server/src/config_api.rs | 8 +- .../suite/v2/experimental_feature_list.rs | 11 +- .../codex/codex-rs/config/src/config_toml.rs | 2 - vendor/codex/codex-rs/config/src/types.rs | 22 - .../codex/codex-rs/connectors/src/filter.rs | 27 -- vendor/codex/codex-rs/core/config.schema.json | 64 +-- .../codex-rs/core/src/config/config_tests.rs | 65 --- vendor/codex/codex-rs/core/src/config/mod.rs | 29 -- .../codex-rs/core/src/connectors_tests.rs | 96 ---- .../codex/codex-rs/core/src/session/tests.rs | 8 +- .../codex/codex-rs/core/src/session/turn.rs | 1 - .../codex-rs/core/src/tools/code_mode/mod.rs | 1 - .../codex-rs/core/src/tools/js_repl/mod.rs | 1 - .../codex/codex-rs/core/src/tools/router.rs | 8 +- .../codex-rs/core/src/tools/router_tests.rs | 5 - vendor/codex/codex-rs/core/src/tools/spec.rs | 6 +- .../codex-rs/core/src/tools/spec_tests.rs | 73 +-- .../search_tool/tool_suggest_description.md | 26 -- vendor/codex/codex-rs/core/tests/suite/mod.rs | 1 - .../codex-rs/core/tests/suite/tool_suggest.rs | 143 ------ vendor/codex/codex-rs/features/src/lib.rs | 8 - vendor/codex/codex-rs/features/src/tests.rs | 6 - vendor/codex/codex-rs/tools/README.md | 4 +- vendor/codex/codex-rs/tools/src/lib.rs | 17 - .../codex/codex-rs/tools/src/tool_config.rs | 5 - .../codex-rs/tools/src/tool_discovery.rs | 261 ----------- .../tools/src/tool_discovery_tests.rs | 132 ------ .../codex-rs/tools/src/tool_registry_plan.rs | 24 +- .../tools/src/tool_registry_plan_tests.rs | 230 ---------- .../tools/src/tool_registry_plan_types.rs | 3 - .../codex/codex-rs/tools/src/tool_suggest.rs | 125 ----- .../codex-rs/tools/src/tool_suggest_tests.rs | 207 --------- .../codex-rs/tui/src/app/event_dispatch.rs | 3 - .../tui/src/bottom_pane/app_link_view.rs | 432 ------------------ .../src/bottom_pane/mcp_server_elicitation.rs | 157 +------ .../codex/codex-rs/tui/src/bottom_pane/mod.rs | 50 -- ...nk_view_enable_suggestion_with_reason.snap | 20 - ...k_view_install_suggestion_with_reason.snap | 18 - 41 files changed, 29 insertions(+), 2293 deletions(-) delete mode 100644 vendor/codex/codex-rs/core/templates/search_tool/tool_suggest_description.md delete mode 100644 vendor/codex/codex-rs/core/tests/suite/tool_suggest.rs delete mode 100644 vendor/codex/codex-rs/tools/src/tool_suggest.rs delete mode 100644 vendor/codex/codex-rs/tools/src/tool_suggest_tests.rs delete mode 100644 vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_enable_suggestion_with_reason.snap delete mode 100644 vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_install_suggestion_with_reason.snap diff --git a/notes/fresh-workspace-handoff.md b/notes/fresh-workspace-handoff.md index 530be022..6241d2bd 100644 --- a/notes/fresh-workspace-handoff.md +++ b/notes/fresh-workspace-handoff.md @@ -810,14 +810,13 @@ plugin/app capability summaries, inject available-skill/available-plugin/plugin instructions, parse plugin/app mentions, record app/plugin invocation telemetry, or filter MCP tools through Codex app connectors. -The tool-suggestion marketplace layer is now cold as well. `tool_suggest` is -never exposed in model-turn tool config, its core handler and discoverable -plugin scan were deleted, MCP startup/refresh passes empty plugin provenance, -session/thread state no longer carries `PluginsManager`, and the old -session-level explicit connector selection cache was removed because it only -served app/plugin suggestion bookkeeping. The remaining plugin code is now a -public Codex product library/CLI surface, not a live session organ; judge it as -the next removable husk, not as keeper spine. +The tool-suggestion marketplace layer is now deleted, not merely cold. +`tool_suggest` no longer exists as a feature/config/schema key, shared tool +spec, handler kind, discoverable-tool side channel, connector filter, TUI +suggestion elicitation flow, prompt template, or implementation-shape test +surface. If a future subsystem wants missing-tool installation, it needs an +Epiphany-owned typed MCP/CultNet adapter contract; do not resurrect this Codex +marketplace product path. That husk has now been cut from `codex-core`. The root core crate no longer exports `plugins`, no longer depends on `codex-core-plugins` or `codex-plugin`, diff --git a/state/ledgers.msgpack b/state/ledgers.msgpack index 3d01c23799d376a933959fa3fbf6c467f1ae377e..8bd733c8e1e5eda5a761198c3653a140597d1c36 100644 GIT binary patch delta 326 zcmXYtyGjE=6owg#^l5C;91t7Xb#oyG*K%zX)DUB1BjfDZ-O<^ZW#&Y*QpgKL6yqBR zc7kY==diF7d=O`e-GTpdKK_rF#_Y8*TU&YjdRu>DtT|n<&jn+@_wxiJH2sdxz6_KACDJvx&QzG delta 49 zcmbQRif!9+wh78ilWR7rPGe*gXx_uPeGen!lZj#tTZ{~h%ybP*bq$R}49%=eOsot| Fq5!r751jx2 diff --git a/state/map.yaml b/state/map.yaml index 47624472..da9c5b89 100644 --- a/state/map.yaml +++ b/state/map.yaml @@ -336,6 +336,10 @@ current_status: import product is gone too: no `externalAgentConfig/detect`, `externalAgentConfig/import`, import-completed notification, TUI startup prompt, migration modules, snapshots, disabled app-server handlers, or - generated schemas remain. MCP remains JSON-RPC at the edge; user-declared - MCP servers are the only runtime MCP authority. + generated schemas remain. The tool-suggestion marketplace organ is now + deleted, not merely disabled: no `tool_suggest` feature/config/schema, tool + spec, handler kind, discoverable-tool side channel, connector filter, TUI + suggestion elicitation flow, prompt template, or implementation-shape tests + remain. MCP remains JSON-RPC at the edge; user-declared MCP servers are the + only runtime MCP authority. next_action: Continue starving coordinator/runtime execution and operator surfaces off app-server JSON-RPC and out of `codex_message_processor.rs`; keep the vestigial Codex organ narrowed to subscription auth/model transport. diff --git a/vendor/codex/codex-rs/app-server/src/config_api.rs b/vendor/codex/codex-rs/app-server/src/config_api.rs index 39672e1d..c71d26ef 100644 --- a/vendor/codex/codex-rs/app-server/src/config_api.rs +++ b/vendor/codex/codex-rs/app-server/src/config_api.rs @@ -32,12 +32,8 @@ use std::path::PathBuf; use std::sync::Arc; use tracing::warn; -const SUPPORTED_EXPERIMENTAL_FEATURE_ENABLEMENT: &[&str] = &[ - "memories", - "tool_search", - "tool_suggest", - "tool_call_mcp_elicitation", -]; +const SUPPORTED_EXPERIMENTAL_FEATURE_ENABLEMENT: &[&str] = + &["memories", "tool_search", "tool_call_mcp_elicitation"]; #[async_trait] pub(crate) trait UserConfigReloader: Send + Sync { diff --git a/vendor/codex/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs b/vendor/codex/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs index 656c3130..d952e9e8 100644 --- a/vendor/codex/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs +++ b/vendor/codex/codex-rs/app-server/tests/suite/v2/experimental_feature_list.rs @@ -176,7 +176,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re &mut mcp, BTreeMap::from([ ("memories".to_string(), true), - ("tool_suggest".to_string(), true), ("tool_call_mcp_elicitation".to_string(), false), ]), ) @@ -187,7 +186,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re ExperimentalFeatureEnablementSetResponse { enablement: BTreeMap::from([ ("memories".to_string(), true), - ("tool_suggest".to_string(), true), ("tool_call_mcp_elicitation".to_string(), false), ]), } @@ -209,13 +207,6 @@ async fn experimental_feature_enablement_set_only_updates_named_features() -> Re .and_then(|features| features.get("memories")), Some(&json!(true)) ); - assert_eq!( - config - .additional - .get("features") - .and_then(|features| features.get("tool_suggest")), - Some(&json!(true)) - ); assert_eq!( config .additional @@ -288,7 +279,7 @@ async fn experimental_feature_enablement_set_rejects_non_allowlisted_feature() - assert!( error .message - .contains("memories, tool_search, tool_suggest, tool_call_mcp_elicitation"), + .contains("memories, tool_search, tool_call_mcp_elicitation"), "{}", error.message ); diff --git a/vendor/codex/codex-rs/config/src/config_toml.rs b/vendor/codex/codex-rs/config/src/config_toml.rs index b8cbf8d0..dd456ebf 100644 --- a/vendor/codex/codex-rs/config/src/config_toml.rs +++ b/vendor/codex/codex-rs/config/src/config_toml.rs @@ -22,7 +22,6 @@ use crate::types::PluginConfig; use crate::types::SandboxWorkspaceWrite; use crate::types::ShellEnvironmentPolicyToml; use crate::types::SkillsConfig; -use crate::types::ToolSuggestConfig; use crate::types::Tui; use crate::types::UriBasedFileOpener; use crate::types::WindowsToml; @@ -321,7 +320,6 @@ pub struct ConfigToml { pub tools: Option, /// Additional discoverable tools that can be suggested for installation. - pub tool_suggest: Option, /// Agent-related settings (thread limits, etc.). pub agents: Option, diff --git a/vendor/codex/codex-rs/config/src/types.rs b/vendor/codex/codex-rs/config/src/types.rs index 50a24db5..0e629ca5 100644 --- a/vendor/codex/codex-rs/config/src/types.rs +++ b/vendor/codex/codex-rs/config/src/types.rs @@ -157,28 +157,6 @@ pub struct FeedbackConfigToml { pub enabled: Option, } -#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Hash, JsonSchema)] -#[serde(rename_all = "snake_case")] -pub enum ToolSuggestDiscoverableType { - Connector, - Plugin, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Hash, JsonSchema)] -#[schemars(deny_unknown_fields)] -pub struct ToolSuggestDiscoverable { - #[serde(rename = "type")] - pub kind: ToolSuggestDiscoverableType, - pub id: String, -} - -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default, JsonSchema)] -#[schemars(deny_unknown_fields)] -pub struct ToolSuggestConfig { - #[serde(default)] - pub discoverables: Vec, -} - /// Memories settings loaded from config.toml. #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default, JsonSchema)] #[schemars(deny_unknown_fields)] diff --git a/vendor/codex/codex-rs/connectors/src/filter.rs b/vendor/codex/codex-rs/connectors/src/filter.rs index 82c334f8..bb82621d 100644 --- a/vendor/codex/codex-rs/connectors/src/filter.rs +++ b/vendor/codex/codex-rs/connectors/src/filter.rs @@ -1,32 +1,5 @@ -use std::collections::HashSet; - use codex_app_server_protocol::AppInfo; -pub fn filter_tool_suggest_discoverable_connectors( - directory_connectors: Vec, - accessible_connectors: &[AppInfo], - discoverable_connector_ids: &HashSet, - originator_value: &str, -) -> Vec { - let accessible_connector_ids: HashSet<&str> = accessible_connectors - .iter() - .filter(|connector| connector.is_accessible) - .map(|connector| connector.id.as_str()) - .collect(); - - let mut connectors = filter_disallowed_connectors(directory_connectors, originator_value) - .into_iter() - .filter(|connector| !accessible_connector_ids.contains(connector.id.as_str())) - .filter(|connector| discoverable_connector_ids.contains(connector.id.as_str())) - .collect::>(); - connectors.sort_by(|left, right| { - left.name - .cmp(&right.name) - .then_with(|| left.id.cmp(&right.id)) - }); - connectors -} - const DISALLOWED_CONNECTOR_IDS: &[&str] = &[ "asdk_app_6938a94a61d881918ef32cb999ff937c", "connector_2b0a9009c9c64bf9933a3dae3f2b1254", diff --git a/vendor/codex/codex-rs/core/config.schema.json b/vendor/codex/codex-rs/core/config.schema.json index 245a55e1..838593b1 100644 --- a/vendor/codex/codex-rs/core/config.schema.json +++ b/vendor/codex/codex-rs/core/config.schema.json @@ -36,12 +36,6 @@ "$ref": "#/definitions/AgentRoleToml" }, "properties": { - "job_max_runtime_seconds": { - "description": "Default maximum runtime in seconds for agent job workers.", - "format": "uint64", - "minimum": 1.0, - "type": "integer" - }, "max_depth": { "description": "Maximum nesting depth allowed for spawned agent threads. Root sessions start at depth 0.", "format": "int32", @@ -390,9 +384,6 @@ "enable_experimental_windows_sandbox": { "type": "boolean" }, - "enable_fanout": { - "type": "boolean" - }, "enable_request_compression": { "type": "boolean" }, @@ -525,9 +516,6 @@ "tool_search_always_defer_mcp_tools": { "type": "boolean" }, - "tool_suggest": { - "type": "boolean" - }, "tui_app_server": { "type": "boolean" }, @@ -1953,42 +1941,6 @@ }, "type": "object" }, - "ToolSuggestConfig": { - "additionalProperties": false, - "properties": { - "discoverables": { - "default": [], - "items": { - "$ref": "#/definitions/ToolSuggestDiscoverable" - }, - "type": "array" - } - }, - "type": "object" - }, - "ToolSuggestDiscoverable": { - "additionalProperties": false, - "properties": { - "id": { - "type": "string" - }, - "type": { - "$ref": "#/definitions/ToolSuggestDiscoverableType" - } - }, - "required": [ - "id", - "type" - ], - "type": "object" - }, - "ToolSuggestDiscoverableType": { - "enum": [ - "connector", - "plugin" - ], - "type": "string" - }, "ToolsToml": { "additionalProperties": false, "properties": { @@ -2221,7 +2173,7 @@ "$ref": "#/definitions/AgentsToml" } ], - "description": "Agent-related settings (thread limits, etc.)." + "description": "Additional discoverable tools that can be suggested for installation. Agent-related settings (thread limits, etc.)." }, "allow_login_shell": { "description": "Whether the model may request a login shell for shell-based tools. Default to `true`\n\nIf `true`, the model may request a login shell (`login = true`), and omitting `login` defaults to using a login shell. If `false`, the model can never use a login shell: `login = true` requests are rejected, and omitting `login` defaults to a non-login shell.", @@ -2408,9 +2360,6 @@ "enable_experimental_windows_sandbox": { "type": "boolean" }, - "enable_fanout": { - "type": "boolean" - }, "enable_request_compression": { "type": "boolean" }, @@ -2543,9 +2492,6 @@ "tool_search_always_defer_mcp_tools": { "type": "boolean" }, - "tool_suggest": { - "type": "boolean" - }, "tui_app_server": { "type": "boolean" }, @@ -2957,14 +2903,6 @@ "minimum": 0.0, "type": "integer" }, - "tool_suggest": { - "allOf": [ - { - "$ref": "#/definitions/ToolSuggestConfig" - } - ], - "description": "Additional discoverable tools that can be suggested for installation." - }, "tools": { "allOf": [ { diff --git a/vendor/codex/codex-rs/core/src/config/config_tests.rs b/vendor/codex/codex-rs/core/src/config/config_tests.rs index 6bf4ca54..0b9c0050 100644 --- a/vendor/codex/codex-rs/core/src/config/config_tests.rs +++ b/vendor/codex/codex-rs/core/src/config/config_tests.rs @@ -43,7 +43,6 @@ use codex_config::types::NotificationMethod; use codex_config::types::Notifications; use codex_config::types::SandboxWorkspaceWrite; use codex_config::types::SkillsConfig; -use codex_config::types::ToolSuggestDiscoverableType; use codex_config::types::Tui; use codex_config::types::TuiNotificationSettings; use codex_exec_server::LOCAL_FS; @@ -5258,7 +5257,6 @@ async fn test_precedence_fixture_with_o3_profile() -> std::io::Result<()> { model_availability_nux: ModelAvailabilityNuxConfig::default(), analytics_enabled: Some(true), feedback_enabled: true, - tool_suggest: ToolSuggestConfig::default(), tui_alternate_screen: AltScreenMode::Auto, tui_status_line: None, tui_terminal_title: None, @@ -5409,7 +5407,6 @@ async fn test_precedence_fixture_with_gpt3_profile() -> std::io::Result<()> { model_availability_nux: ModelAvailabilityNuxConfig::default(), analytics_enabled: Some(true), feedback_enabled: true, - tool_suggest: ToolSuggestConfig::default(), tui_alternate_screen: AltScreenMode::Auto, tui_status_line: None, tui_terminal_title: None, @@ -5558,7 +5555,6 @@ async fn test_precedence_fixture_with_zdr_profile() -> std::io::Result<()> { model_availability_nux: ModelAvailabilityNuxConfig::default(), analytics_enabled: Some(false), feedback_enabled: true, - tool_suggest: ToolSuggestConfig::default(), tui_alternate_screen: AltScreenMode::Auto, tui_status_line: None, tui_terminal_title: None, @@ -5692,7 +5688,6 @@ async fn test_precedence_fixture_with_gpt5_profile() -> std::io::Result<()> { model_availability_nux: ModelAvailabilityNuxConfig::default(), analytics_enabled: Some(true), feedback_enabled: true, - tool_suggest: ToolSuggestConfig::default(), tui_alternate_screen: AltScreenMode::Auto, tui_status_line: None, tui_terminal_title: None, @@ -7035,66 +7030,6 @@ async fn feature_requirements_reject_collab_legacy_alias() { ); } -#[tokio::test] -async fn tool_suggest_discoverables_load_from_config_toml() -> std::io::Result<()> { - let cfg: ConfigToml = toml::from_str( - r#" -[tool_suggest] -discoverables = [ - { type = "connector", id = "connector_alpha" }, - { type = "plugin", id = "plugin_alpha@openai-curated" }, - { type = "connector", id = " " } -] -"#, - ) - .expect("TOML deserialization should succeed"); - - assert_eq!( - cfg.tool_suggest, - Some(ToolSuggestConfig { - discoverables: vec![ - ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Connector, - id: "connector_alpha".to_string(), - }, - ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Plugin, - id: "plugin_alpha@openai-curated".to_string(), - }, - ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Connector, - id: " ".to_string(), - }, - ], - }) - ); - - let codex_home = TempDir::new()?; - let config = Config::load_from_base_config_with_overrides( - cfg, - ConfigOverrides::default(), - codex_home.abs(), - ) - .await?; - - assert_eq!( - config.tool_suggest, - ToolSuggestConfig { - discoverables: vec![ - ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Connector, - id: "connector_alpha".to_string(), - }, - ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Plugin, - id: "plugin_alpha@openai-curated".to_string(), - }, - ], - } - ); - Ok(()) -} - #[tokio::test] async fn experimental_realtime_start_instructions_load_from_config_toml() -> std::io::Result<()> { let cfg: ConfigToml = toml::from_str( diff --git a/vendor/codex/codex-rs/core/src/config/mod.rs b/vendor/codex/codex-rs/core/src/config/mod.rs index a7a0c8ec..a4502cd5 100644 --- a/vendor/codex/codex-rs/core/src/config/mod.rs +++ b/vendor/codex/codex-rs/core/src/config/mod.rs @@ -44,8 +44,6 @@ use codex_config::types::OtelConfig; use codex_config::types::OtelConfigToml; use codex_config::types::OtelExporterKind; use codex_config::types::ShellEnvironmentPolicy; -use codex_config::types::ToolSuggestConfig; -use codex_config::types::ToolSuggestDiscoverable; use codex_config::types::TuiNotificationSettings; use codex_config::types::UriBasedFileOpener; use codex_config::types::WindowsSandboxModeToml; @@ -606,9 +604,6 @@ pub struct Config { /// Defaults to `true`. pub feedback_enabled: bool, - /// Configured discoverable tools for tool suggestions. - pub tool_suggest: ToolSuggestConfig, - /// OTEL configuration (exporter type, endpoint, headers, etc.). pub otel: codex_config::types::OtelConfig, } @@ -1249,28 +1244,6 @@ pub struct AgentRoleConfig { pub nickname_candidates: Option>, } -fn resolve_tool_suggest_config(config_toml: &ConfigToml) -> ToolSuggestConfig { - let discoverables = config_toml - .tool_suggest - .as_ref() - .into_iter() - .flat_map(|tool_suggest| tool_suggest.discoverables.iter()) - .filter_map(|discoverable| { - let trimmed = discoverable.id.trim(); - if trimmed.is_empty() { - None - } else { - Some(ToolSuggestDiscoverable { - kind: discoverable.kind, - id: trimmed.to_string(), - }) - } - }) - .collect(); - - ToolSuggestConfig { discoverables } -} - #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum PermissionConfigSyntax { Legacy, @@ -1625,7 +1598,6 @@ impl Config { .clone(), None => ConfigProfile::default(), }; - let tool_suggest = resolve_tool_suggest_config(&cfg); let feature_overrides = FeatureOverrides { include_apply_patch_tool: include_apply_patch_tool_override, web_search_request: override_tools_web_search_request, @@ -2389,7 +2361,6 @@ impl Config { .as_ref() .and_then(|feedback| feedback.enabled) .unwrap_or(true), - tool_suggest, tui_notifications: cfg .tui .as_ref() diff --git a/vendor/codex/codex-rs/core/src/connectors_tests.rs b/vendor/codex/codex-rs/core/src/connectors_tests.rs index 0f9e834d..f6d4c2b6 100644 --- a/vendor/codex/codex-rs/core/src/connectors_tests.rs +++ b/vendor/codex/codex-rs/core/src/connectors_tests.rs @@ -12,7 +12,6 @@ use codex_config::types::AppToolConfig; use codex_config::types::AppToolsConfig; use codex_config::types::AppsDefaultConfig; use codex_connectors::filter::filter_disallowed_connectors; -use codex_connectors::filter::filter_tool_suggest_discoverable_connectors; use codex_connectors::merge::merge_connectors; use codex_connectors::merge::plugin_connector_to_app_info; use codex_connectors::metadata::connector_install_url; @@ -1084,98 +1083,3 @@ fn first_party_chat_originator_filters_target_and_openai_prefixed_connectors() { vec![app("asdk_app_6938a94a61d881918ef32cb999ff937c")] ); } - -#[tokio::test] -async fn tool_suggest_connector_ids_include_configured_tool_suggest_discoverables() { - let codex_home = tempdir().expect("tempdir should succeed"); - std::fs::write( - codex_home.path().join(CONFIG_TOML_FILE), - r#" -[tool_suggest] -discoverables = [ - { type = "connector", id = "connector_2128aebfecb84f64a069897515042a44" }, - { type = "plugin", id = "slack@openai-curated" }, - { type = "connector", id = " " } -] -"#, - ) - .expect("write config"); - let config = ConfigBuilder::default() - .codex_home(codex_home.path().to_path_buf()) - .build() - .await - .expect("config should load"); - - assert_eq!( - tool_suggest_connector_ids(&config).await, - HashSet::from(["connector_2128aebfecb84f64a069897515042a44".to_string()]) - ); -} - -#[test] -fn filter_tool_suggest_discoverable_connectors_keeps_only_plugin_backed_uninstalled_apps() { - let filtered = filter_tool_suggest_discoverable_connectors( - vec![ - named_app( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - ), - named_app("connector_68df038e0ba48191908c8434991bbac2", "Gmail"), - named_app("connector_other", "Other"), - ], - &[AppInfo { - is_accessible: true, - ..named_app( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - ) - }], - &HashSet::from([ - "connector_2128aebfecb84f64a069897515042a44".to_string(), - "connector_68df038e0ba48191908c8434991bbac2".to_string(), - ]), - "codex_cli", - ); - - assert_eq!( - filtered, - vec![named_app( - "connector_68df038e0ba48191908c8434991bbac2", - "Gmail", - )] - ); -} - -#[test] -fn filter_tool_suggest_discoverable_connectors_excludes_accessible_apps_even_when_disabled() { - let filtered = filter_tool_suggest_discoverable_connectors( - vec![ - named_app( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - ), - named_app("connector_68df038e0ba48191908c8434991bbac2", "Gmail"), - ], - &[ - AppInfo { - is_accessible: true, - ..named_app( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - ) - }, - AppInfo { - is_accessible: true, - is_enabled: false, - ..named_app("connector_68df038e0ba48191908c8434991bbac2", "Gmail") - }, - ], - &HashSet::from([ - "connector_2128aebfecb84f64a069897515042a44".to_string(), - "connector_68df038e0ba48191908c8434991bbac2".to_string(), - ]), - "codex_cli", - ); - - assert_eq!(filtered, Vec::::new()); -} diff --git a/vendor/codex/codex-rs/core/src/session/tests.rs b/vendor/codex/codex-rs/core/src/session/tests.rs index 9249f504..33314e4e 100644 --- a/vendor/codex/codex-rs/core/src/session/tests.rs +++ b/vendor/codex/codex-rs/core/src/session/tests.rs @@ -14,15 +14,15 @@ use crate::context::TurnAborted; use crate::exec::ExecCapturePolicy; use crate::function_tool::FunctionCallError; use crate::shell::default_user_shell; -use crate::skills::build_available_skills; use crate::skills::SkillRenderSideEffects; +use crate::skills::build_available_skills; use crate::skills::render::SkillMetadataBudget; use crate::tools::format_exec_output_str; -use codex_features::Feature; -use codex_features::Features; use codex_core_skills::SkillMetadata; use codex_core_skills::SkillsLoadInput; +use codex_features::Feature; +use codex_features::Features; use codex_login::CodexAuth; use codex_model_provider_info::ModelProviderInfo; use codex_models_manager::bundled_models_response; @@ -751,7 +751,6 @@ fn test_tool_runtime(session: Arc, turn_context: Arc) -> T deferred_mcp_tools: None, unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn_context.dynamic_tools.as_slice(), }, )); @@ -6906,7 +6905,6 @@ async fn fatal_tool_error_stops_turn_and_reports_error() { mcp_tools: Some(tools), unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn_context.dynamic_tools.as_slice(), }, ); diff --git a/vendor/codex/codex-rs/core/src/session/turn.rs b/vendor/codex/codex-rs/core/src/session/turn.rs index 0fcffa08..ddf56fb2 100644 --- a/vendor/codex/codex-rs/core/src/session/turn.rs +++ b/vendor/codex/codex-rs/core/src/session/turn.rs @@ -907,7 +907,6 @@ pub(crate) async fn built_tools( deferred_mcp_tools, unavailable_called_tools, parallel_mcp_server_names, - discoverable_tools: None, dynamic_tools: turn_context.dynamic_tools.as_slice(), }, ))) diff --git a/vendor/codex/codex-rs/core/src/tools/code_mode/mod.rs b/vendor/codex/codex-rs/core/src/tools/code_mode/mod.rs index 575d3f9a..007aec05 100644 --- a/vendor/codex/codex-rs/core/src/tools/code_mode/mod.rs +++ b/vendor/codex/codex-rs/core/src/tools/code_mode/mod.rs @@ -293,7 +293,6 @@ async fn build_nested_router(exec: &ExecContext) -> ToolRouter { mcp_tools: Some(listed_mcp_tools), unavailable_called_tools: Vec::new(), parallel_mcp_server_names, - discoverable_tools: None, dynamic_tools: exec.turn.dynamic_tools.as_slice(), }, ) diff --git a/vendor/codex/codex-rs/core/src/tools/js_repl/mod.rs b/vendor/codex/codex-rs/core/src/tools/js_repl/mod.rs index c91d0fec..9ac7998c 100644 --- a/vendor/codex/codex-rs/core/src/tools/js_repl/mod.rs +++ b/vendor/codex/codex-rs/core/src/tools/js_repl/mod.rs @@ -1603,7 +1603,6 @@ impl JsReplManager { // JS REPL dispatches nested tool calls directly, not through // `ToolCallRuntime`'s parallel scheduling lock. parallel_mcp_server_names: std::collections::HashSet::new(), - discoverable_tools: None, dynamic_tools: exec.turn.dynamic_tools.as_slice(), }, ); diff --git a/vendor/codex/codex-rs/core/src/tools/router.rs b/vendor/codex/codex-rs/core/src/tools/router.rs index c3b4b86d..9111f937 100644 --- a/vendor/codex/codex-rs/core/src/tools/router.rs +++ b/vendor/codex/codex-rs/core/src/tools/router.rs @@ -8,7 +8,7 @@ use crate::tools::context::ToolPayload; use crate::tools::registry::AnyToolResult; use crate::tools::registry::ToolArgumentDiffConsumer; use crate::tools::registry::ToolRegistry; -use crate::tools::spec::build_specs_with_discoverable_tools; +use crate::tools::spec::build_specs; use codex_mcp::ToolInfo; use codex_protocol::dynamic_tools::DynamicToolSpec; use codex_protocol::models::LocalShellAction; @@ -16,7 +16,6 @@ use codex_protocol::models::ResponseItem; use codex_protocol::models::SearchToolCallParams; use codex_protocol::models::ShellToolCallParams; use codex_tools::ConfiguredToolSpec; -use codex_tools::DiscoverableTool; use codex_tools::ResponsesApiNamespaceTool; use codex_tools::ToolName; use codex_tools::ToolSpec; @@ -48,7 +47,6 @@ pub(crate) struct ToolRouterParams<'a> { pub(crate) deferred_mcp_tools: Option>, pub(crate) unavailable_called_tools: Vec, pub(crate) parallel_mcp_server_names: HashSet, - pub(crate) discoverable_tools: Option>, pub(crate) dynamic_tools: &'a [DynamicToolSpec], } @@ -59,15 +57,13 @@ impl ToolRouter { deferred_mcp_tools, unavailable_called_tools, parallel_mcp_server_names, - discoverable_tools, dynamic_tools, } = params; - let builder = build_specs_with_discoverable_tools( + let builder = build_specs( config, mcp_tools, deferred_mcp_tools, unavailable_called_tools, - discoverable_tools, dynamic_tools, ); let (specs, registry) = builder.build(); diff --git a/vendor/codex/codex-rs/core/src/tools/router_tests.rs b/vendor/codex/codex-rs/core/src/tools/router_tests.rs index c83c65fc..db4ad0b3 100644 --- a/vendor/codex/codex-rs/core/src/tools/router_tests.rs +++ b/vendor/codex/codex-rs/core/src/tools/router_tests.rs @@ -40,7 +40,6 @@ async fn js_repl_tools_only_blocks_direct_tool_calls() -> anyhow::Result<()> { mcp_tools: Some(mcp_tools), unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn.dynamic_tools.as_slice(), }, ); @@ -99,7 +98,6 @@ async fn js_repl_tools_only_allows_js_repl_source_calls() -> anyhow::Result<()> mcp_tools: Some(mcp_tools), unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn.dynamic_tools.as_slice(), }, ); @@ -147,7 +145,6 @@ async fn js_repl_tools_only_blocks_namespaced_js_repl_tool() -> anyhow::Result<( mcp_tools: None, unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn.dynamic_tools.as_slice(), }, ); @@ -203,7 +200,6 @@ async fn parallel_support_does_not_match_namespaced_local_tool_names() -> anyhow mcp_tools: Some(mcp_tools), unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::new(), - discoverable_tools: None, dynamic_tools: turn.dynamic_tools.as_slice(), }, ); @@ -276,7 +272,6 @@ async fn mcp_parallel_support_uses_exact_payload_server() -> anyhow::Result<()> mcp_tools: None, unavailable_called_tools: Vec::new(), parallel_mcp_server_names: HashSet::from(["echo".to_string()]), - discoverable_tools: None, dynamic_tools: turn.dynamic_tools.as_slice(), }, ); diff --git a/vendor/codex/codex-rs/core/src/tools/spec.rs b/vendor/codex/codex-rs/core/src/tools/spec.rs index 154d0a43..221ce5df 100644 --- a/vendor/codex/codex-rs/core/src/tools/spec.rs +++ b/vendor/codex/codex-rs/core/src/tools/spec.rs @@ -7,7 +7,6 @@ use crate::tools::registry::ToolRegistryBuilder; use codex_mcp::ToolInfo; use codex_protocol::dynamic_tools::DynamicToolSpec; use codex_tools::AdditionalProperties; -use codex_tools::DiscoverableTool; use codex_tools::JsonSchema; use codex_tools::ResponsesApiTool; use codex_tools::ToolHandlerKind; @@ -67,12 +66,11 @@ fn map_mcp_tools_for_plan(mcp_tools: &HashMap) -> McpToolPlanI } } -pub(crate) fn build_specs_with_discoverable_tools( +pub(crate) fn build_specs( config: &ToolsConfig, mcp_tools: Option>, deferred_mcp_tools: Option>, unavailable_called_tools: Vec, - discoverable_tools: Option>, dynamic_tools: &[DynamicToolSpec], ) -> ToolRegistryBuilder { use crate::tools::handlers::ApplyPatchHandler; @@ -133,7 +131,6 @@ pub(crate) fn build_specs_with_discoverable_tools( tool_namespaces: mcp_tool_plan_inputs .as_ref() .map(|inputs| &inputs.tool_namespaces), - discoverable_tools: discoverable_tools.as_deref(), dynamic_tools, default_agent_type_description: &default_agent_type_description, wait_agent_timeouts: WaitAgentTimeoutOptions { @@ -269,7 +266,6 @@ pub(crate) fn build_specs_with_discoverable_tools( builder.register_handler(handler.name, tool_search_handler.clone()); } } - ToolHandlerKind::ToolSuggest => {} ToolHandlerKind::UnifiedExec => { builder.register_handler(handler.name, unified_exec_handler.clone()); } diff --git a/vendor/codex/codex-rs/core/src/tools/spec_tests.rs b/vendor/codex/codex-rs/core/src/tools/spec_tests.rs index ac800c02..a10856be 100644 --- a/vendor/codex/codex-rs/core/src/tools/spec_tests.rs +++ b/vendor/codex/codex-rs/core/src/tools/spec_tests.rs @@ -4,7 +4,6 @@ use crate::shell::ShellType; use crate::test_support::construct_model_info_offline; use crate::tools::ToolRouter; use crate::tools::router::ToolRouterParams; -use codex_app_server_protocol::AppInfo; use codex_features::Feature; use codex_features::Features; use codex_models_manager::bundled_models_response; @@ -17,13 +16,11 @@ use codex_protocol::protocol::SandboxPolicy; use codex_protocol::protocol::SessionSource; use codex_tools::AdditionalProperties; use codex_tools::ConfiguredToolSpec; -use codex_tools::DiscoverableTool; use codex_tools::JsonSchema; use codex_tools::ResponsesApiNamespaceTool; use codex_tools::ResponsesApiTool; use codex_tools::ShellCommandBackendConfig; use codex_tools::TOOL_SEARCH_TOOL_NAME; -use codex_tools::TOOL_SUGGEST_TOOL_NAME; use codex_tools::ToolName; use codex_tools::ToolSpec; use codex_tools::ToolsConfig; @@ -87,25 +84,6 @@ fn mcp_tool_info_with_display_name(display_name: &str, tool: rmcp::model::Tool) } } -fn discoverable_connector(id: &str, name: &str, description: &str) -> DiscoverableTool { - let slug = name.replace(' ', "-").to_lowercase(); - DiscoverableTool::Connector(Box::new(AppInfo { - id: id.to_string(), - name: name.to_string(), - description: Some(description.to_string()), - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: Some(format!("https://chatgpt.com/apps/{slug}/{id}")), - is_accessible: false, - is_enabled: true, - plugin_display_names: Vec::new(), - })) -} - async fn search_capable_model_info() -> ModelInfo { let config = test_config().await; let mut model_info = construct_model_info_offline("gpt-5.4", &config); @@ -284,12 +262,11 @@ fn build_specs_with_unavailable_tools( unavailable_called_tools: Vec, dynamic_tools: &[DynamicToolSpec], ) -> ToolRegistryBuilder { - build_specs_with_discoverable_tools( + build_specs( config, mcp_tools, deferred_mcp_tools, unavailable_called_tools, - /*discoverable_tools*/ None, dynamic_tools, ) } @@ -375,7 +352,6 @@ async fn assert_model_tools( deferred_mcp_tools: None, unavailable_called_tools: Vec::new(), parallel_mcp_server_names: std::collections::HashSet::new(), - discoverable_tools: None, dynamic_tools: &[], }, ); @@ -780,53 +756,6 @@ async fn spawn_agent_description_uses_configured_usage_hint_text() { ); } -#[tokio::test] -async fn tool_suggest_requires_apps_and_plugins_features() { - let model_info = search_capable_model_info().await; - let discoverable_tools = Some(vec![discoverable_connector( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - "Plan events and schedules.", - )]); - let available_models = Vec::new(); - - for disabled_feature in [Feature::Apps, Feature::Plugins] { - let mut features = Features::with_defaults(); - features.enable(Feature::ToolSearch); - features.enable(Feature::ToolSuggest); - features.enable(Feature::Apps); - features.enable(Feature::Plugins); - features.disable(disabled_feature); - - let tools_config = ToolsConfig::new(&ToolsConfigParams { - model_info: &model_info, - available_models: &available_models, - features: &features, - image_generation_tool_auth_allowed: true, - web_search_mode: Some(WebSearchMode::Cached), - session_source: SessionSource::Cli, - sandbox_policy: &SandboxPolicy::DangerFullAccess, - windows_sandbox_level: WindowsSandboxLevel::Disabled, - }); - let (tools, _) = build_specs_with_discoverable_tools( - &tools_config, - /*mcp_tools*/ None, - /*deferred_mcp_tools*/ None, - Vec::new(), - discoverable_tools.clone(), - &[], - ) - .build(); - - assert!( - !tools - .iter() - .any(|tool| tool.name() == TOOL_SUGGEST_TOOL_NAME), - "tool_suggest should be absent when {disabled_feature:?} is disabled" - ); - } -} - #[tokio::test] async fn search_tool_description_handles_no_enabled_mcp_tools() { let model_info = search_capable_model_info().await; diff --git a/vendor/codex/codex-rs/core/templates/search_tool/tool_suggest_description.md b/vendor/codex/codex-rs/core/templates/search_tool/tool_suggest_description.md deleted file mode 100644 index ad0a50fc..00000000 --- a/vendor/codex/codex-rs/core/templates/search_tool/tool_suggest_description.md +++ /dev/null @@ -1,26 +0,0 @@ -# Tool suggestion discovery - -Suggests a missing connector in an installed plugin, or in narrower cases a not installed but discoverable plugin, when the user clearly wants a capability that is not currently available in the active `tools` list. - -Use this ONLY when: -- You've already tried to find a matching available tool for the user's request but couldn't find a good match. This includes `tool_search` (if available) and other means. -- For connectors/apps that are not installed but needed for an installed plugin, suggest to install them if the task requirements match precisely. -- For plugins that are not installed but discoverable, only suggest discoverable and installable plugins when the user's intent very explicitly and unambiguously matches that plugin itself. Do not suggest a plugin just because one of its connectors or capabilities seems relevant. - -Tool suggestions should only use the discoverable tools listed here. DO NOT explore or recommend tools that are not on this list. - -Discoverable tools: -{{discoverable_tools}} - -Workflow: - -1. Ensure all possible means have been exhausted to find an existing available tool but none of them matches the request intent. -2. Match the user's request against the discoverable tools list above. Apply the stricter explicit-and-unambiguous rule for *discoverable tools* like plugin install suggestions; *missing tools* like connector install suggestions continue to use the normal clear-fit standard. -3. If one tool clearly fits, call `tool_suggest` with: - - `tool_type`: `connector` or `plugin` - - `action_type`: `install` or `enable` - - `tool_id`: exact id from the discoverable tools list above - - `suggest_reason`: concise one-line user-facing reason this tool can help with the current request -4. After the suggestion flow completes: - - if the user finished the install or enable flow, continue by searching again or using the newly available tool - - if the user did not finish, continue without that tool, and don't suggest that tool again unless the user explicitly asks you to. diff --git a/vendor/codex/codex-rs/core/tests/suite/mod.rs b/vendor/codex/codex-rs/core/tests/suite/mod.rs index ee9ac8b8..ef12b6a9 100644 --- a/vendor/codex/codex-rs/core/tests/suite/mod.rs +++ b/vendor/codex/codex-rs/core/tests/suite/mod.rs @@ -96,7 +96,6 @@ mod stream_no_completed; mod subagent_notifications; mod tool_harness; mod tool_parallelism; -mod tool_suggest; mod tools; mod truncation; mod turn_state; diff --git a/vendor/codex/codex-rs/core/tests/suite/tool_suggest.rs b/vendor/codex/codex-rs/core/tests/suite/tool_suggest.rs deleted file mode 100644 index 30da83e9..00000000 --- a/vendor/codex/codex-rs/core/tests/suite/tool_suggest.rs +++ /dev/null @@ -1,143 +0,0 @@ -#![cfg(not(target_os = "windows"))] -#![allow(clippy::unwrap_used, clippy::expect_used)] - -use anyhow::Result; -use codex_config::types::ToolSuggestDiscoverable; -use codex_config::types::ToolSuggestDiscoverableType; -use codex_core::config::Config; -use codex_features::Feature; -use codex_login::CodexAuth; -use codex_models_manager::bundled_models_response; -use codex_protocol::protocol::AskForApproval; -use codex_protocol::protocol::SandboxPolicy; -use core_test_support::apps_test_server::AppsTestServer; -use core_test_support::responses::ev_assistant_message; -use core_test_support::responses::ev_completed; -use core_test_support::responses::ev_response_created; -use core_test_support::responses::mount_sse_once; -use core_test_support::responses::sse; -use core_test_support::responses::start_mock_server; -use core_test_support::skip_if_no_network; -use core_test_support::test_codex::test_codex; -use serde_json::Value; - -const TOOL_SEARCH_TOOL_NAME: &str = "tool_search"; -const TOOL_SUGGEST_TOOL_NAME: &str = "tool_suggest"; -const DISCOVERABLE_GMAIL_ID: &str = "connector_68df038e0ba48191908c8434991bbac2"; - -fn tool_names(body: &Value) -> Vec { - body.get("tools") - .and_then(Value::as_array) - .map(|tools| { - tools - .iter() - .filter_map(|tool| { - tool.get("name") - .or_else(|| tool.get("type")) - .and_then(Value::as_str) - .map(str::to_string) - }) - .collect() - }) - .unwrap_or_default() -} - -fn function_tool_description(body: &Value, name: &str) -> Option { - body.get("tools") - .and_then(Value::as_array) - .and_then(|tools| { - tools.iter().find_map(|tool| { - if tool.get("name").and_then(Value::as_str) == Some(name) { - tool.get("description") - .and_then(Value::as_str) - .map(str::to_string) - } else { - None - } - }) - }) -} - -fn configure_apps_without_search_tool(config: &mut Config, apps_base_url: &str) { - config - .features - .enable(Feature::Apps) - .expect("test config should allow feature update"); - config - .features - .enable(Feature::Plugins) - .expect("test config should allow feature update"); - config - .features - .enable(Feature::ToolSuggest) - .expect("test config should allow feature update"); - let mut model_catalog = bundled_models_response() - .unwrap_or_else(|err| panic!("bundled models.json should parse: {err}")); - let model = model_catalog - .models - .iter_mut() - .find(|model| model.slug == "gpt-5.4") - .expect("gpt-5.4 exists in bundled models.json"); - config.chatgpt_base_url = apps_base_url.to_string(); - config.model = Some("gpt-5.4".to_string()); - config.tool_suggest.discoverables = vec![ToolSuggestDiscoverable { - kind: ToolSuggestDiscoverableType::Connector, - id: DISCOVERABLE_GMAIL_ID.to_string(), - }]; - model.supports_search_tool = false; - config.model_catalog = Some(model_catalog); -} - -#[tokio::test(flavor = "multi_thread", worker_threads = 2)] -async fn tool_suggest_is_available_without_search_tool_after_discovery_attempts() -> Result<()> { - skip_if_no_network!(Ok(())); - - let server = start_mock_server().await; - let apps_server = AppsTestServer::mount(&server).await?; - let mock = mount_sse_once( - &server, - sse(vec![ - ev_response_created("resp-1"), - ev_assistant_message("msg-1", "done"), - ev_completed("resp-1"), - ]), - ) - .await; - - let mut builder = test_codex() - .with_auth(CodexAuth::create_dummy_chatgpt_auth_for_testing()) - .with_config(move |config| { - configure_apps_without_search_tool(config, apps_server.chatgpt_base_url.as_str()) - }); - let test = builder.build(&server).await?; - - test.submit_turn_with_policies( - "list tools", - AskForApproval::Never, - SandboxPolicy::DangerFullAccess, - ) - .await?; - - let body = mock.single_request().body_json(); - let tools = tool_names(&body); - assert!( - !tools.iter().any(|name| name == TOOL_SEARCH_TOOL_NAME), - "tools list should not include {TOOL_SEARCH_TOOL_NAME}: {tools:?}" - ); - assert!( - tools.iter().any(|name| name == TOOL_SUGGEST_TOOL_NAME), - "tools list should include {TOOL_SUGGEST_TOOL_NAME}: {tools:?}" - ); - - let description = - function_tool_description(&body, TOOL_SUGGEST_TOOL_NAME).expect("description"); - assert!( - description.contains( - "You've already tried to find a matching available tool for the user's request" - ) - ); - assert!(description.contains("This includes `tool_search` (if available) and other means.")); - assert!(!description.contains("tool_search fails to find a good match")); - - Ok(()) -} diff --git a/vendor/codex/codex-rs/features/src/lib.rs b/vendor/codex/codex-rs/features/src/lib.rs index 295e4ce1..47b2eda9 100644 --- a/vendor/codex/codex-rs/features/src/lib.rs +++ b/vendor/codex/codex-rs/features/src/lib.rs @@ -150,8 +150,6 @@ pub enum Feature { ToolSearchAlwaysDeferMcpTools, /// Expose placeholder tools for unavailable historical tool calls. UnavailableDummyTools, - /// Enable discoverable tool suggestions for apps. - ToolSuggest, /// Enable plugins. Plugins, /// Allow the in-app browser pane in desktop apps. @@ -833,12 +831,6 @@ pub const FEATURES: &[FeatureSpec] = &[ stage: Stage::UnderDevelopment, default_enabled: false, }, - FeatureSpec { - id: Feature::ToolSuggest, - key: "tool_suggest", - stage: Stage::Stable, - default_enabled: true, - }, FeatureSpec { id: Feature::Plugins, key: "plugins", diff --git a/vendor/codex/codex-rs/features/src/tests.rs b/vendor/codex/codex-rs/features/src/tests.rs index 73ed0112..88fd7a51 100644 --- a/vendor/codex/codex-rs/features/src/tests.rs +++ b/vendor/codex/codex-rs/features/src/tests.rs @@ -129,12 +129,6 @@ fn request_permissions_tool_is_under_development() { assert_eq!(Feature::RequestPermissionsTool.default_enabled(), false); } -#[test] -fn tool_suggest_is_stable_and_enabled_by_default() { - assert_eq!(Feature::ToolSuggest.stage(), Stage::Stable); - assert_eq!(Feature::ToolSuggest.default_enabled(), true); -} - #[test] fn tool_search_is_stable_and_enabled_by_default() { assert_eq!(Feature::ToolSearch.stage(), Stage::Stable); diff --git a/vendor/codex/codex-rs/tools/README.md b/vendor/codex/codex-rs/tools/README.md index 5416e7f2..e968d48c 100644 --- a/vendor/codex/codex-rs/tools/README.md +++ b/vendor/codex/codex-rs/tools/README.md @@ -27,8 +27,8 @@ schema and Responses API tool primitives that no longer need to live in - local host tool spec builders for shell/exec/request-permissions/view-image - collaboration `ToolSpec` builders for spawn/send/wait/close, `request_user_input`, and CSV fanout/reporting -- discoverable-tool models, client filtering, and `ToolSpec` builders for - `tool_search` and `tool_suggest` +- deferred MCP/dynamic discovery models and `ToolSpec` builders for + `tool_search` - `parse_tool_input_schema()` - `parse_dynamic_tool()` - `parse_mcp_tool()` diff --git a/vendor/codex/codex-rs/tools/src/lib.rs b/vendor/codex/codex-rs/tools/src/lib.rs index f01f1c89..4bb01752 100644 --- a/vendor/codex/codex-rs/tools/src/lib.rs +++ b/vendor/codex/codex-rs/tools/src/lib.rs @@ -20,7 +20,6 @@ mod tool_discovery; mod tool_registry_plan; mod tool_registry_plan_types; mod tool_spec; -mod tool_suggest; mod utility_tool; mod view_image; @@ -98,22 +97,13 @@ pub use tool_config::ToolsConfigParams; pub use tool_config::UnifiedExecShellMode; pub use tool_config::ZshForkConfig; pub use tool_definition::ToolDefinition; -pub use tool_discovery::DiscoverablePluginInfo; -pub use tool_discovery::DiscoverableTool; -pub use tool_discovery::DiscoverableToolAction; -pub use tool_discovery::DiscoverableToolType; pub use tool_discovery::TOOL_SEARCH_DEFAULT_LIMIT; pub use tool_discovery::TOOL_SEARCH_TOOL_NAME; -pub use tool_discovery::TOOL_SUGGEST_TOOL_NAME; pub use tool_discovery::ToolSearchResultSource; pub use tool_discovery::ToolSearchSource; pub use tool_discovery::ToolSearchSourceInfo; -pub use tool_discovery::ToolSuggestEntry; pub use tool_discovery::collect_tool_search_source_infos; -pub use tool_discovery::collect_tool_suggest_entries; pub use tool_discovery::create_tool_search_tool; -pub use tool_discovery::create_tool_suggest_tool; -pub use tool_discovery::filter_tool_suggest_discoverable_tools_for_client; pub use tool_discovery::tool_search_result_source_to_loadable_tool_spec; pub use tool_registry_plan::build_tool_registry_plan; pub use tool_registry_plan_types::ToolHandlerKind; @@ -132,13 +122,6 @@ pub use tool_spec::create_image_generation_tool; pub use tool_spec::create_local_shell_tool; pub use tool_spec::create_tools_json_for_responses_api; pub use tool_spec::create_web_search_tool; -pub use tool_suggest::TOOL_SUGGEST_APPROVAL_KIND_VALUE; -pub use tool_suggest::ToolSuggestArgs; -pub use tool_suggest::ToolSuggestMeta; -pub use tool_suggest::ToolSuggestResult; -pub use tool_suggest::all_suggested_connectors_picked_up; -pub use tool_suggest::build_tool_suggestion_elicitation_request; -pub use tool_suggest::verified_connector_suggestion_completed; pub use utility_tool::create_list_dir_tool; pub use utility_tool::create_test_sync_tool; pub use view_image::ViewImageToolOptions; diff --git a/vendor/codex/codex-rs/tools/src/tool_config.rs b/vendor/codex/codex-rs/tools/src/tool_config.rs index e343ef05..22feebc1 100644 --- a/vendor/codex/codex-rs/tools/src/tool_config.rs +++ b/vendor/codex/codex-rs/tools/src/tool_config.rs @@ -93,7 +93,6 @@ pub struct ToolsConfig { pub web_search_tool_type: WebSearchToolType, pub image_gen_tool: bool, pub search_tool: bool, - pub tool_suggest: bool, pub exec_permission_approvals_enabled: bool, pub request_permissions_tool_enabled: bool, pub code_mode_enabled: bool, @@ -146,9 +145,6 @@ impl ToolsConfig { features.enabled(Feature::DefaultModeRequestUserInput); let include_search_tool = model_info.supports_search_tool && features.enabled(Feature::ToolSearch); - // Epiphany keeps Codex for subscription auth/model routing, not for - // app/plugin marketplace discovery inside model turns. - let include_tool_suggest = false; let include_original_image_detail = can_request_original_image_detail(model_info); // API-key auth bypasses Codex backend entitlement/tool normalization, so // callers must confirm ChatGPT auth before exposing the built-in tool. @@ -204,7 +200,6 @@ impl ToolsConfig { web_search_tool_type: model_info.web_search_tool_type, image_gen_tool: include_image_gen_tool, search_tool: include_search_tool, - tool_suggest: include_tool_suggest, exec_permission_approvals_enabled, request_permissions_tool_enabled, code_mode_enabled: include_code_mode, diff --git a/vendor/codex/codex-rs/tools/src/tool_discovery.rs b/vendor/codex/codex-rs/tools/src/tool_discovery.rs index ddcd2f1c..cfa1a72f 100644 --- a/vendor/codex/codex-rs/tools/src/tool_discovery.rs +++ b/vendor/codex/codex-rs/tools/src/tool_discovery.rs @@ -2,20 +2,14 @@ use crate::JsonSchema; use crate::LoadableToolSpec; use crate::ResponsesApiNamespace; use crate::ResponsesApiNamespaceTool; -use crate::ResponsesApiTool; use crate::ToolName; use crate::ToolSpec; use crate::default_namespace_description; use crate::mcp_tool_to_deferred_responses_api_tool; -use codex_app_server_protocol::AppInfo; -use serde::Deserialize; -use serde::Serialize; use std::collections::BTreeMap; -const TUI_CLIENT_NAME: &str = "codex-tui"; pub const TOOL_SEARCH_TOOL_NAME: &str = "tool_search"; pub const TOOL_SEARCH_DEFAULT_LIMIT: usize = 8; -pub const TOOL_SUGGEST_TOOL_NAME: &str = "tool_suggest"; #[derive(Clone, Debug, PartialEq, Eq)] pub struct ToolSearchSourceInfo { @@ -40,112 +34,6 @@ pub struct ToolSearchResultSource<'a> { pub connector_description: Option<&'a str>, } -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub enum DiscoverableToolType { - Connector, - Plugin, -} - -impl DiscoverableToolType { - fn as_str(self) -> &'static str { - match self { - Self::Connector => "connector", - Self::Plugin => "plugin", - } - } -} - -#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, Eq)] -#[serde(rename_all = "snake_case")] -pub enum DiscoverableToolAction { - Install, - Enable, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum DiscoverableTool { - Connector(Box), - Plugin(Box), -} - -impl DiscoverableTool { - pub fn tool_type(&self) -> DiscoverableToolType { - match self { - Self::Connector(_) => DiscoverableToolType::Connector, - Self::Plugin(_) => DiscoverableToolType::Plugin, - } - } - - pub fn id(&self) -> &str { - match self { - Self::Connector(connector) => connector.id.as_str(), - Self::Plugin(plugin) => plugin.id.as_str(), - } - } - - pub fn name(&self) -> &str { - match self { - Self::Connector(connector) => connector.name.as_str(), - Self::Plugin(plugin) => plugin.name.as_str(), - } - } - - pub fn install_url(&self) -> Option<&str> { - match self { - Self::Connector(connector) => connector.install_url.as_deref(), - Self::Plugin(_) => None, - } - } -} - -impl From for DiscoverableTool { - fn from(value: AppInfo) -> Self { - Self::Connector(Box::new(value)) - } -} - -impl From for DiscoverableTool { - fn from(value: DiscoverablePluginInfo) -> Self { - Self::Plugin(Box::new(value)) - } -} - -pub fn filter_tool_suggest_discoverable_tools_for_client( - discoverable_tools: Vec, - app_server_client_name: Option<&str>, -) -> Vec { - if app_server_client_name != Some(TUI_CLIENT_NAME) { - return discoverable_tools; - } - - discoverable_tools - .into_iter() - .filter(|tool| !matches!(tool, DiscoverableTool::Plugin(_))) - .collect() -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct DiscoverablePluginInfo { - pub id: String, - pub name: String, - pub description: Option, - pub has_skills: bool, - pub mcp_server_names: Vec, - pub app_connector_ids: Vec, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ToolSuggestEntry { - pub id: String, - pub name: String, - pub description: Option, - pub tool_type: DiscoverableToolType, - pub has_skills: bool, - pub mcp_server_names: Vec, - pub app_connector_ids: Vec, -} - pub fn create_tool_search_tool( searchable_sources: &[ToolSearchSourceInfo], default_limit: usize, @@ -271,155 +159,6 @@ pub fn collect_tool_search_source_infos<'a>( .collect() } -pub fn create_tool_suggest_tool(discoverable_tools: &[ToolSuggestEntry]) -> ToolSpec { - let discoverable_tool_ids = discoverable_tools - .iter() - .map(|tool| tool.id.as_str()) - .collect::>() - .join(", "); - let properties = BTreeMap::from([ - ( - "tool_type".to_string(), - JsonSchema::string(Some( - "Type of discoverable tool to suggest. Use \"connector\" or \"plugin\"." - .to_string(), - )), - ), - ( - "action_type".to_string(), - JsonSchema::string(Some( - "Suggested action for the tool. Use \"install\" or \"enable\".".to_string(), - )), - ), - ( - "tool_id".to_string(), - JsonSchema::string(Some(format!( - "Connector or plugin id to suggest. Must be one of: {discoverable_tool_ids}." - ))), - ), - ( - "suggest_reason".to_string(), - JsonSchema::string(Some( - "Concise one-line user-facing reason why this tool can help with the current request." - .to_string(), - )), - ), - ]); - - let discoverable_tools = format_discoverable_tools(discoverable_tools); - let description = format!( - "# Tool suggestion discovery\n\nSuggests a missing connector in an installed plugin, or in narrower cases a not installed but discoverable plugin, when the user clearly wants a capability that is not currently available in the active `tools` list.\n\nUse this ONLY when:\n- You've already tried to find a matching available tool for the user's request but couldn't find a good match. This includes `{TOOL_SEARCH_TOOL_NAME}` (if available) and other means.\n- For connectors/apps that are not installed but needed for an installed plugin, suggest to install them if the task requirements match precisely.\n- For plugins that are not installed but discoverable, only suggest discoverable and installable plugins when the user's intent very explicitly and unambiguously matches that plugin itself. Do not suggest a plugin just because one of its connectors or capabilities seems relevant.\n\nTool suggestions should only use the discoverable tools listed here. DO NOT explore or recommend tools that are not on this list.\n\nDiscoverable tools:\n{discoverable_tools}\n\nWorkflow:\n\n1. Ensure all possible means have been exhausted to find an existing available tool but none of them matches the request intent.\n2. Match the user's request against the discoverable tools list above. Apply the stricter explicit-and-unambiguous rule for *discoverable tools* like plugin install suggestions; *missing tools* like connector install suggestions continue to use the normal clear-fit standard.\n3. If one tool clearly fits, call `{TOOL_SUGGEST_TOOL_NAME}` with:\n - `tool_type`: `connector` or `plugin`\n - `action_type`: `install` or `enable`\n - `tool_id`: exact id from the discoverable tools list above\n - `suggest_reason`: concise one-line user-facing reason this tool can help with the current request\n4. After the suggestion flow completes:\n - if the user finished the install or enable flow, continue by searching again or using the newly available tool\n - if the user did not finish, continue without that tool, and don't suggest that tool again unless the user explicitly asks for it." - ); - - ToolSpec::Function(ResponsesApiTool { - name: TOOL_SUGGEST_TOOL_NAME.to_string(), - description, - strict: false, - defer_loading: None, - parameters: JsonSchema::object( - properties, - Some(vec![ - "tool_type".to_string(), - "action_type".to_string(), - "tool_id".to_string(), - "suggest_reason".to_string(), - ]), - Some(false.into()), - ), - output_schema: None, - }) -} - -pub fn collect_tool_suggest_entries( - discoverable_tools: &[DiscoverableTool], -) -> Vec { - discoverable_tools - .iter() - .map(|tool| match tool { - DiscoverableTool::Connector(connector) => ToolSuggestEntry { - id: connector.id.clone(), - name: connector.name.clone(), - description: connector.description.clone(), - tool_type: DiscoverableToolType::Connector, - has_skills: false, - mcp_server_names: Vec::new(), - app_connector_ids: Vec::new(), - }, - DiscoverableTool::Plugin(plugin) => ToolSuggestEntry { - id: plugin.id.clone(), - name: plugin.name.clone(), - description: plugin.description.clone(), - tool_type: DiscoverableToolType::Plugin, - has_skills: plugin.has_skills, - mcp_server_names: plugin.mcp_server_names.clone(), - app_connector_ids: plugin.app_connector_ids.clone(), - }, - }) - .collect() -} - -fn format_discoverable_tools(discoverable_tools: &[ToolSuggestEntry]) -> String { - let mut discoverable_tools = discoverable_tools.to_vec(); - discoverable_tools.sort_by(|left, right| { - left.name - .cmp(&right.name) - .then_with(|| left.id.cmp(&right.id)) - }); - - discoverable_tools - .into_iter() - .map(|tool| { - let description = tool_description_or_fallback(&tool); - format!( - "- {} (id: `{}`, type: {}, action: install): {}", - tool.name, - tool.id, - tool.tool_type.as_str(), - description - ) - }) - .collect::>() - .join("\n") -} - -fn tool_description_or_fallback(tool: &ToolSuggestEntry) -> String { - if let Some(description) = tool - .description - .as_deref() - .map(str::trim) - .filter(|description| !description.is_empty()) - { - return description.to_string(); - } - - match tool.tool_type { - DiscoverableToolType::Connector => "No description provided.".to_string(), - DiscoverableToolType::Plugin => plugin_summary(tool), - } -} - -fn plugin_summary(tool: &ToolSuggestEntry) -> String { - let mut details = Vec::new(); - if tool.has_skills { - details.push("skills".to_string()); - } - if !tool.mcp_server_names.is_empty() { - details.push(format!("MCP servers: {}", tool.mcp_server_names.join(", "))); - } - if !tool.app_connector_ids.is_empty() { - details.push(format!( - "app connectors: {}", - tool.app_connector_ids.join(", ") - )); - } - - if details.is_empty() { - "No description provided.".to_string() - } else { - details.join("; ") - } -} - #[cfg(test)] #[path = "tool_discovery_tests.rs"] mod tests; diff --git a/vendor/codex/codex-rs/tools/src/tool_discovery_tests.rs b/vendor/codex/codex-rs/tools/src/tool_discovery_tests.rs index 9afd3223..d01a711b 100644 --- a/vendor/codex/codex-rs/tools/src/tool_discovery_tests.rs +++ b/vendor/codex/codex-rs/tools/src/tool_discovery_tests.rs @@ -1,8 +1,6 @@ use super::*; use crate::JsonSchema; -use codex_app_server_protocol::AppInfo; use pretty_assertions::assert_eq; -use serde_json::json; use std::collections::BTreeMap; #[test] @@ -47,133 +45,3 @@ fn create_tool_search_tool_deduplicates_and_renders_enabled_sources() { } ); } - -#[test] -fn create_tool_suggest_tool_uses_plugin_summary_fallback() { - assert_eq!( - create_tool_suggest_tool(&[ - ToolSuggestEntry { - id: "slack@openai-curated".to_string(), - name: "Slack".to_string(), - description: None, - tool_type: DiscoverableToolType::Connector, - has_skills: false, - mcp_server_names: Vec::new(), - app_connector_ids: Vec::new(), - }, - ToolSuggestEntry { - id: "github".to_string(), - name: "GitHub".to_string(), - description: None, - tool_type: DiscoverableToolType::Plugin, - has_skills: true, - mcp_server_names: vec!["github-mcp".to_string()], - app_connector_ids: vec!["github-app".to_string()], - }, - ]), - ToolSpec::Function(ResponsesApiTool { - name: "tool_suggest".to_string(), - description: "# Tool suggestion discovery\n\nSuggests a missing connector in an installed plugin, or in narrower cases a not installed but discoverable plugin, when the user clearly wants a capability that is not currently available in the active `tools` list.\n\nUse this ONLY when:\n- You've already tried to find a matching available tool for the user's request but couldn't find a good match. This includes `tool_search` (if available) and other means.\n- For connectors/apps that are not installed but needed for an installed plugin, suggest to install them if the task requirements match precisely.\n- For plugins that are not installed but discoverable, only suggest discoverable and installable plugins when the user's intent very explicitly and unambiguously matches that plugin itself. Do not suggest a plugin just because one of its connectors or capabilities seems relevant.\n\nTool suggestions should only use the discoverable tools listed here. DO NOT explore or recommend tools that are not on this list.\n\nDiscoverable tools:\n- GitHub (id: `github`, type: plugin, action: install): skills; MCP servers: github-mcp; app connectors: github-app\n- Slack (id: `slack@openai-curated`, type: connector, action: install): No description provided.\n\nWorkflow:\n\n1. Ensure all possible means have been exhausted to find an existing available tool but none of them matches the request intent.\n2. Match the user's request against the discoverable tools list above. Apply the stricter explicit-and-unambiguous rule for *discoverable tools* like plugin install suggestions; *missing tools* like connector install suggestions continue to use the normal clear-fit standard.\n3. If one tool clearly fits, call `tool_suggest` with:\n - `tool_type`: `connector` or `plugin`\n - `action_type`: `install` or `enable`\n - `tool_id`: exact id from the discoverable tools list above\n - `suggest_reason`: concise one-line user-facing reason this tool can help with the current request\n4. After the suggestion flow completes:\n - if the user finished the install or enable flow, continue by searching again or using the newly available tool\n - if the user did not finish, continue without that tool, and don't suggest that tool again unless the user explicitly asks for it.".to_string(), - strict: false, - defer_loading: None, - parameters: JsonSchema::object(BTreeMap::from([ - ( - "action_type".to_string(), - JsonSchema::string(Some( - "Suggested action for the tool. Use \"install\" or \"enable\"." - .to_string(), - ),), - ), - ( - "suggest_reason".to_string(), - JsonSchema::string(Some( - "Concise one-line user-facing reason why this tool can help with the current request." - .to_string(), - ),), - ), - ( - "tool_id".to_string(), - JsonSchema::string(Some( - "Connector or plugin id to suggest. Must be one of: slack@openai-curated, github." - .to_string(), - ),), - ), - ( - "tool_type".to_string(), - JsonSchema::string(Some( - "Type of discoverable tool to suggest. Use \"connector\" or \"plugin\"." - .to_string(), - ),), - ), - ]), Some(vec![ - "tool_type".to_string(), - "action_type".to_string(), - "tool_id".to_string(), - "suggest_reason".to_string(), - ]), Some(false.into())), - output_schema: None, - }) - ); -} - -#[test] -fn discoverable_tool_enums_use_expected_wire_names() { - assert_eq!( - json!({ - "tool_type": DiscoverableToolType::Connector, - "action_type": DiscoverableToolAction::Install, - }), - json!({ - "tool_type": "connector", - "action_type": "install", - }) - ); -} - -#[test] -fn filter_tool_suggest_discoverable_tools_for_codex_tui_omits_plugins() { - let discoverable_tools = vec![ - DiscoverableTool::Connector(Box::new(AppInfo { - id: "connector_google_calendar".to_string(), - name: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: Some("https://example.test/google-calendar".to_string()), - is_accessible: false, - is_enabled: true, - plugin_display_names: Vec::new(), - })), - DiscoverableTool::Plugin(Box::new(DiscoverablePluginInfo { - id: "slack@openai-curated".to_string(), - name: "Slack".to_string(), - description: Some("Search Slack messages".to_string()), - has_skills: true, - mcp_server_names: vec!["slack".to_string()], - app_connector_ids: vec!["connector_slack".to_string()], - })), - ]; - - assert_eq!( - filter_tool_suggest_discoverable_tools_for_client(discoverable_tools, Some("codex-tui"),), - vec![DiscoverableTool::Connector(Box::new(AppInfo { - id: "connector_google_calendar".to_string(), - name: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: Some("https://example.test/google-calendar".to_string()), - is_accessible: false, - is_enabled: true, - plugin_display_names: Vec::new(), - }))] - ); -} diff --git a/vendor/codex/codex-rs/tools/src/tool_registry_plan.rs b/vendor/codex/codex-rs/tools/src/tool_registry_plan.rs index 985778ed..e681e0e4 100644 --- a/vendor/codex/codex-rs/tools/src/tool_registry_plan.rs +++ b/vendor/codex/codex-rs/tools/src/tool_registry_plan.rs @@ -6,7 +6,6 @@ use crate::ShellToolOptions; use crate::SpawnAgentToolOptions; use crate::TOOL_SEARCH_DEFAULT_LIMIT; use crate::TOOL_SEARCH_TOOL_NAME; -use crate::TOOL_SUGGEST_TOOL_NAME; use crate::ToolHandlerKind; use crate::ToolName; use crate::ToolRegistryPlan; @@ -20,7 +19,6 @@ use crate::WebSearchToolOptions; use crate::coalesce_loadable_tool_specs; use crate::collect_code_mode_exec_prompt_tool_definitions; use crate::collect_tool_search_source_infos; -use crate::collect_tool_suggest_entries; use crate::create_apply_patch_freeform_tool; use crate::create_apply_patch_json_tool; use crate::create_close_agent_tool_v1; @@ -48,7 +46,6 @@ use crate::create_spawn_agent_tool_v1; use crate::create_spawn_agent_tool_v2; use crate::create_test_sync_tool; use crate::create_tool_search_tool; -use crate::create_tool_suggest_tool; use crate::create_update_plan_tool; use crate::create_view_image_tool; use crate::create_wait_agent_tool_v1; @@ -89,13 +86,8 @@ pub fn build_tool_registry_plan( }) .collect::>(); let nested_config = config.for_code_mode_nested_tools(); - let nested_plan = build_tool_registry_plan( - &nested_config, - ToolRegistryPlanParams { - discoverable_tools: None, - ..params - }, - ); + let nested_plan = + build_tool_registry_plan(&nested_config, ToolRegistryPlanParams { ..params }); let mut enabled_tools = collect_code_mode_exec_prompt_tool_definitions( nested_plan .specs @@ -295,18 +287,6 @@ pub fn build_tool_registry_plan( } } - if config.tool_suggest - && let Some(discoverable_tools) = - params.discoverable_tools.filter(|tools| !tools.is_empty()) - { - plan.push_spec( - create_tool_suggest_tool(&collect_tool_suggest_entries(discoverable_tools)), - /*supports_parallel_tool_calls*/ true, - /*code_mode_enabled*/ false, - ); - plan.register_handler(TOOL_SUGGEST_TOOL_NAME, ToolHandlerKind::ToolSuggest); - } - if config.has_environment && let Some(apply_patch_tool_type) = &config.apply_patch_tool_type { diff --git a/vendor/codex/codex-rs/tools/src/tool_registry_plan_tests.rs b/vendor/codex/codex-rs/tools/src/tool_registry_plan_tests.rs index 14d0202b..7ea4c216 100644 --- a/vendor/codex/codex-rs/tools/src/tool_registry_plan_tests.rs +++ b/vendor/codex/codex-rs/tools/src/tool_registry_plan_tests.rs @@ -1,8 +1,6 @@ use super::*; use crate::AdditionalProperties; use crate::ConfiguredToolSpec; -use crate::DiscoverablePluginInfo; -use crate::DiscoverableTool; use crate::FreeformTool; use crate::JsonSchema; use crate::JsonSchemaPrimitiveType; @@ -19,7 +17,6 @@ use crate::ToolRegistryPlanMcpTool; use crate::ToolsConfigParams; use crate::WaitAgentTimeoutOptions; use crate::mcp_call_tool_result_output_schema; -use codex_app_server_protocol::AppInfo; use codex_features::Feature; use codex_features::Features; use codex_protocol::config_types::WebSearchConfig; @@ -1442,195 +1439,6 @@ fn search_tool_registers_for_deferred_dynamic_tools() { })); } -#[test] -fn tool_suggest_is_not_registered_without_feature_flag() { - let model_info = search_capable_model_info(); - let mut features = Features::with_defaults(); - features.enable(Feature::ToolSearch); - features.enable(Feature::Apps); - features.enable(Feature::Plugins); - features.disable(Feature::ToolSuggest); - let available_models = Vec::new(); - let tools_config = ToolsConfig::new(&ToolsConfigParams { - model_info: &model_info, - available_models: &available_models, - features: &features, - image_generation_tool_auth_allowed: true, - web_search_mode: Some(WebSearchMode::Cached), - session_source: SessionSource::Cli, - sandbox_policy: &SandboxPolicy::DangerFullAccess, - windows_sandbox_level: WindowsSandboxLevel::Disabled, - }); - let (tools, _) = build_specs_with_discoverable_tools( - &tools_config, - /*mcp_tools*/ None, - /*deferred_mcp_tools*/ None, - Some(vec![discoverable_connector( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - "Plan events and schedules.", - )]), - &[], - ); - - assert!( - !tools - .iter() - .any(|tool| tool.name() == TOOL_SUGGEST_TOOL_NAME) - ); -} - -#[test] -fn tool_suggest_can_be_registered_without_search_tool() { - let model_info = ModelInfo { - supports_search_tool: false, - ..search_capable_model_info() - }; - let mut features = Features::with_defaults(); - features.enable(Feature::Apps); - features.enable(Feature::Plugins); - features.enable(Feature::ToolSuggest); - let available_models = Vec::new(); - let tools_config = ToolsConfig::new(&ToolsConfigParams { - model_info: &model_info, - available_models: &available_models, - features: &features, - image_generation_tool_auth_allowed: true, - web_search_mode: Some(WebSearchMode::Cached), - session_source: SessionSource::Cli, - sandbox_policy: &SandboxPolicy::DangerFullAccess, - windows_sandbox_level: WindowsSandboxLevel::Disabled, - }); - let (tools, _) = build_specs_with_discoverable_tools( - &tools_config, - /*mcp_tools*/ None, - /*deferred_mcp_tools*/ None, - Some(vec![discoverable_connector( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - "Plan events and schedules.", - )]), - &[], - ); - - assert_contains_tool_names(&tools, &[TOOL_SUGGEST_TOOL_NAME]); - assert_lacks_tool_name(&tools, TOOL_SEARCH_TOOL_NAME); - - let tool_suggest = find_tool(&tools, TOOL_SUGGEST_TOOL_NAME); - let ToolSpec::Function(ResponsesApiTool { description, .. }) = &tool_suggest.spec else { - panic!("expected function tool"); - }; - assert!(description.contains( - "Suggests a missing connector in an installed plugin, or in narrower cases a not installed but discoverable plugin" - )); - assert!(description.contains( - "You've already tried to find a matching available tool for the user's request but couldn't find a good match. This includes `tool_search` (if available) and other means." - )); -} - -#[test] -fn tool_suggest_description_lists_discoverable_tools() { - let model_info = search_capable_model_info(); - let mut features = Features::with_defaults(); - features.enable(Feature::Apps); - features.enable(Feature::Plugins); - features.enable(Feature::ToolSearch); - features.enable(Feature::ToolSuggest); - let available_models = Vec::new(); - let tools_config = ToolsConfig::new(&ToolsConfigParams { - model_info: &model_info, - available_models: &available_models, - features: &features, - image_generation_tool_auth_allowed: true, - web_search_mode: Some(WebSearchMode::Cached), - session_source: SessionSource::Cli, - sandbox_policy: &SandboxPolicy::DangerFullAccess, - windows_sandbox_level: WindowsSandboxLevel::Disabled, - }); - - let discoverable_tools = vec![ - discoverable_connector( - "connector_2128aebfecb84f64a069897515042a44", - "Google Calendar", - "Plan events and schedules.", - ), - discoverable_connector( - "connector_68df038e0ba48191908c8434991bbac2", - "Gmail", - "Find and summarize email threads.", - ), - DiscoverableTool::Plugin(Box::new(DiscoverablePluginInfo { - id: "sample@test".to_string(), - name: "Sample Plugin".to_string(), - description: None, - has_skills: true, - mcp_server_names: vec!["sample-docs".to_string()], - app_connector_ids: vec!["connector_sample".to_string()], - })), - ]; - - let (tools, _) = build_specs_with_discoverable_tools( - &tools_config, - /*mcp_tools*/ None, - /*deferred_mcp_tools*/ None, - Some(discoverable_tools), - &[], - ); - - let tool_suggest = find_tool(&tools, TOOL_SUGGEST_TOOL_NAME); - let ToolSpec::Function(ResponsesApiTool { - description, - parameters, - .. - }) = &tool_suggest.spec - else { - panic!("expected function tool"); - }; - assert!(description.contains( - "Suggests a missing connector in an installed plugin, or in narrower cases a not installed but discoverable plugin" - )); - assert!(description.contains("Google Calendar")); - assert!(description.contains("Gmail")); - assert!(description.contains("Sample Plugin")); - assert!(description.contains("Plan events and schedules.")); - assert!(description.contains("Find and summarize email threads.")); - assert!(description.contains("id: `sample@test`, type: plugin, action: install")); - assert!(description.contains("`action_type`: `install` or `enable`")); - assert!( - description.contains("skills; MCP servers: sample-docs; app connectors: connector_sample") - ); - assert!( - description.contains( - "You've already tried to find a matching available tool for the user's request but couldn't find a good match. This includes `tool_search` (if available) and other means." - ) - ); - assert!(description.contains( - "For connectors/apps that are not installed but needed for an installed plugin, suggest to install them if the task requirements match precisely." - )); - assert!(description.contains( - "For plugins that are not installed but discoverable, only suggest discoverable and installable plugins when the user's intent very explicitly and unambiguously matches that plugin itself." - )); - assert!(description.contains( - "Do not suggest a plugin just because one of its connectors or capabilities seems relevant." - )); - assert!(description.contains( - "Apply the stricter explicit-and-unambiguous rule for *discoverable tools* like plugin install suggestions; *missing tools* like connector install suggestions continue to use the normal clear-fit standard." - )); - assert!(description.contains("DO NOT explore or recommend tools that are not on this list.")); - assert!(!description.contains("{{discoverable_tools}}")); - assert!(!description.contains("tool_search fails to find a good match")); - let (_, required) = expect_object_schema(parameters); - assert_eq!( - required, - Some(&vec![ - "tool_type".to_string(), - "action_type".to_string(), - "tool_id".to_string(), - "suggest_reason".to_string(), - ]) - ); -} - #[test] fn code_mode_augments_mcp_tool_descriptions_with_namespaced_sample() { let model_info = model_info(); @@ -1924,29 +1732,12 @@ fn build_specs<'a>( mcp_tools: Option>, deferred_mcp_tools: Option>>, dynamic_tools: &[DynamicToolSpec], -) -> (Vec, Vec) { - build_specs_with_discoverable_tools( - config, - mcp_tools, - deferred_mcp_tools, - /*discoverable_tools*/ None, - dynamic_tools, - ) -} - -fn build_specs_with_discoverable_tools<'a>( - config: &ToolsConfig, - mcp_tools: Option>, - deferred_mcp_tools: Option>>, - discoverable_tools: Option>, - dynamic_tools: &[DynamicToolSpec], ) -> (Vec, Vec) { build_specs_with_optional_tool_namespaces( config, mcp_tools, deferred_mcp_tools, /*tool_namespaces*/ None, - discoverable_tools, dynamic_tools, ) } @@ -1956,7 +1747,6 @@ fn build_specs_with_optional_tool_namespaces<'a>( mcp_tools: Option>, deferred_mcp_tools: Option>>, tool_namespaces: Option>, - discoverable_tools: Option>, dynamic_tools: &[DynamicToolSpec], ) -> (Vec, Vec) { let mcp_tool_inputs = mcp_tools.as_ref().map(|mcp_tools| { @@ -1974,7 +1764,6 @@ fn build_specs_with_optional_tool_namespaces<'a>( mcp_tools: mcp_tool_inputs.as_deref(), deferred_mcp_tools: deferred_mcp_tools.as_deref(), tool_namespaces: tool_namespaces.as_ref(), - discoverable_tools: discoverable_tools.as_deref(), dynamic_tools, default_agent_type_description: DEFAULT_AGENT_TYPE_DESCRIPTION, wait_agent_timeouts: wait_agent_timeout_options(), @@ -2069,25 +1858,6 @@ declare const tools: { mcp__sample__echo(args: { message: string; }): Promise DiscoverableTool { - let slug = name.replace(' ', "-").to_lowercase(); - DiscoverableTool::Connector(Box::new(AppInfo { - id: id.to_string(), - name: name.to_string(), - description: Some(description.to_string()), - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: Some(format!("https://chatgpt.com/apps/{slug}/{id}")), - is_accessible: false, - is_enabled: true, - plugin_display_names: Vec::new(), - })) -} - fn deferred_mcp_tool<'a>( tool_name: &'a str, tool_namespace: &'a str, diff --git a/vendor/codex/codex-rs/tools/src/tool_registry_plan_types.rs b/vendor/codex/codex-rs/tools/src/tool_registry_plan_types.rs index ef168bb5..2cde4ec1 100644 --- a/vendor/codex/codex-rs/tools/src/tool_registry_plan_types.rs +++ b/vendor/codex/codex-rs/tools/src/tool_registry_plan_types.rs @@ -1,5 +1,4 @@ use crate::ConfiguredToolSpec; -use crate::DiscoverableTool; use crate::ToolName; use crate::ToolSpec; use crate::ToolsConfig; @@ -35,7 +34,6 @@ pub enum ToolHandlerKind { SpawnAgentV2, TestSync, ToolSearch, - ToolSuggest, UnifiedExec, ViewImage, WaitAgentV1, @@ -59,7 +57,6 @@ pub struct ToolRegistryPlanParams<'a> { pub mcp_tools: Option<&'a [ToolRegistryPlanMcpTool<'a>]>, pub deferred_mcp_tools: Option<&'a [ToolRegistryPlanDeferredTool<'a>]>, pub tool_namespaces: Option<&'a HashMap>, - pub discoverable_tools: Option<&'a [DiscoverableTool]>, pub dynamic_tools: &'a [DynamicToolSpec], pub default_agent_type_description: &'a str, pub wait_agent_timeouts: WaitAgentTimeoutOptions, diff --git a/vendor/codex/codex-rs/tools/src/tool_suggest.rs b/vendor/codex/codex-rs/tools/src/tool_suggest.rs deleted file mode 100644 index 7a6e87ff..00000000 --- a/vendor/codex/codex-rs/tools/src/tool_suggest.rs +++ /dev/null @@ -1,125 +0,0 @@ -use std::collections::BTreeMap; - -use codex_app_server_protocol::AppInfo; -use codex_app_server_protocol::McpElicitationObjectType; -use codex_app_server_protocol::McpElicitationSchema; -use codex_app_server_protocol::McpServerElicitationRequest; -use codex_app_server_protocol::McpServerElicitationRequestParams; -use serde::Deserialize; -use serde::Serialize; -use serde_json::json; - -use crate::DiscoverableTool; -use crate::DiscoverableToolAction; -use crate::DiscoverableToolType; - -pub const TOOL_SUGGEST_APPROVAL_KIND_VALUE: &str = "tool_suggestion"; - -#[derive(Debug, Deserialize)] -pub struct ToolSuggestArgs { - pub tool_type: DiscoverableToolType, - pub action_type: DiscoverableToolAction, - pub tool_id: String, - pub suggest_reason: String, -} - -#[derive(Debug, Serialize, PartialEq, Eq)] -pub struct ToolSuggestResult { - pub completed: bool, - pub user_confirmed: bool, - pub tool_type: DiscoverableToolType, - pub action_type: DiscoverableToolAction, - pub tool_id: String, - pub tool_name: String, - pub suggest_reason: String, -} - -#[derive(Debug, Serialize, PartialEq, Eq)] -pub struct ToolSuggestMeta<'a> { - pub codex_approval_kind: &'static str, - pub tool_type: DiscoverableToolType, - pub suggest_type: DiscoverableToolAction, - pub suggest_reason: &'a str, - pub tool_id: &'a str, - pub tool_name: &'a str, - #[serde(skip_serializing_if = "Option::is_none")] - pub install_url: Option<&'a str>, -} - -pub fn build_tool_suggestion_elicitation_request( - server_name: &str, - thread_id: String, - turn_id: String, - args: &ToolSuggestArgs, - suggest_reason: &str, - tool: &DiscoverableTool, -) -> McpServerElicitationRequestParams { - let tool_name = tool.name().to_string(); - let install_url = tool.install_url().map(ToString::to_string); - let message = suggest_reason.to_string(); - - McpServerElicitationRequestParams { - thread_id, - turn_id: Some(turn_id), - server_name: server_name.to_string(), - request: McpServerElicitationRequest::Form { - meta: Some(json!(build_tool_suggestion_meta( - args.tool_type, - args.action_type, - suggest_reason, - tool.id(), - tool_name.as_str(), - install_url.as_deref(), - ))), - message, - requested_schema: McpElicitationSchema { - schema_uri: None, - type_: McpElicitationObjectType::Object, - properties: BTreeMap::new(), - required: None, - }, - }, - } -} - -pub fn all_suggested_connectors_picked_up( - expected_connector_ids: &[String], - accessible_connectors: &[AppInfo], -) -> bool { - expected_connector_ids.iter().all(|connector_id| { - verified_connector_suggestion_completed(connector_id, accessible_connectors) - }) -} - -pub fn verified_connector_suggestion_completed( - tool_id: &str, - accessible_connectors: &[AppInfo], -) -> bool { - accessible_connectors - .iter() - .find(|connector| connector.id == tool_id) - .is_some_and(|connector| connector.is_accessible) -} - -fn build_tool_suggestion_meta<'a>( - tool_type: DiscoverableToolType, - action_type: DiscoverableToolAction, - suggest_reason: &'a str, - tool_id: &'a str, - tool_name: &'a str, - install_url: Option<&'a str>, -) -> ToolSuggestMeta<'a> { - ToolSuggestMeta { - codex_approval_kind: TOOL_SUGGEST_APPROVAL_KIND_VALUE, - tool_type, - suggest_type: action_type, - suggest_reason, - tool_id, - tool_name, - install_url, - } -} - -#[cfg(test)] -#[path = "tool_suggest_tests.rs"] -mod tests; diff --git a/vendor/codex/codex-rs/tools/src/tool_suggest_tests.rs b/vendor/codex/codex-rs/tools/src/tool_suggest_tests.rs deleted file mode 100644 index d3c37bf1..00000000 --- a/vendor/codex/codex-rs/tools/src/tool_suggest_tests.rs +++ /dev/null @@ -1,207 +0,0 @@ -use super::*; -use crate::DiscoverablePluginInfo; -use pretty_assertions::assert_eq; -use serde_json::json; - -#[test] -fn build_tool_suggestion_elicitation_request_uses_expected_shape() { - let args = ToolSuggestArgs { - tool_type: DiscoverableToolType::Connector, - action_type: DiscoverableToolAction::Install, - tool_id: "connector_2128aebfecb84f64a069897515042a44".to_string(), - suggest_reason: "Plan and reference events from your calendar".to_string(), - }; - let connector = DiscoverableTool::Connector(Box::new(AppInfo { - id: "connector_2128aebfecb84f64a069897515042a44".to_string(), - name: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: Some( - "https://chatgpt.com/apps/google-calendar/connector_2128aebfecb84f64a069897515042a44" - .to_string(), - ), - is_accessible: false, - is_enabled: true, - plugin_display_names: Vec::new(), - })); - - let request = build_tool_suggestion_elicitation_request( - "codex-apps", - "thread-1".to_string(), - "turn-1".to_string(), - &args, - "Plan and reference events from your calendar", - &connector, - ); - - assert_eq!( - request, - McpServerElicitationRequestParams { - thread_id: "thread-1".to_string(), - turn_id: Some("turn-1".to_string()), - server_name: "codex-apps".to_string(), - request: McpServerElicitationRequest::Form { - meta: Some(json!(ToolSuggestMeta { - codex_approval_kind: TOOL_SUGGEST_APPROVAL_KIND_VALUE, - tool_type: DiscoverableToolType::Connector, - suggest_type: DiscoverableToolAction::Install, - suggest_reason: "Plan and reference events from your calendar", - tool_id: "connector_2128aebfecb84f64a069897515042a44", - tool_name: "Google Calendar", - install_url: Some( - "https://chatgpt.com/apps/google-calendar/connector_2128aebfecb84f64a069897515042a44" - ), - })), - message: "Plan and reference events from your calendar".to_string(), - requested_schema: McpElicitationSchema { - schema_uri: None, - type_: McpElicitationObjectType::Object, - properties: BTreeMap::new(), - required: None, - }, - }, - }, - ); -} - -#[test] -fn build_tool_suggestion_elicitation_request_for_plugin_omits_install_url() { - let args = ToolSuggestArgs { - tool_type: DiscoverableToolType::Plugin, - action_type: DiscoverableToolAction::Install, - tool_id: "sample@openai-curated".to_string(), - suggest_reason: "Use the sample plugin's skills and MCP server".to_string(), - }; - let plugin = DiscoverableTool::Plugin(Box::new(DiscoverablePluginInfo { - id: "sample@openai-curated".to_string(), - name: "Sample Plugin".to_string(), - description: Some("Includes skills, MCP servers, and apps.".to_string()), - has_skills: true, - mcp_server_names: vec!["sample-docs".to_string()], - app_connector_ids: vec!["connector_calendar".to_string()], - })); - - let request = build_tool_suggestion_elicitation_request( - "codex-apps", - "thread-1".to_string(), - "turn-1".to_string(), - &args, - "Use the sample plugin's skills and MCP server", - &plugin, - ); - - assert_eq!( - request, - McpServerElicitationRequestParams { - thread_id: "thread-1".to_string(), - turn_id: Some("turn-1".to_string()), - server_name: "codex-apps".to_string(), - request: McpServerElicitationRequest::Form { - meta: Some(json!(ToolSuggestMeta { - codex_approval_kind: TOOL_SUGGEST_APPROVAL_KIND_VALUE, - tool_type: DiscoverableToolType::Plugin, - suggest_type: DiscoverableToolAction::Install, - suggest_reason: "Use the sample plugin's skills and MCP server", - tool_id: "sample@openai-curated", - tool_name: "Sample Plugin", - install_url: None, - })), - message: "Use the sample plugin's skills and MCP server".to_string(), - requested_schema: McpElicitationSchema { - schema_uri: None, - type_: McpElicitationObjectType::Object, - properties: BTreeMap::new(), - required: None, - }, - }, - }, - ); -} - -#[test] -fn build_tool_suggestion_meta_uses_expected_shape() { - let meta = build_tool_suggestion_meta( - DiscoverableToolType::Connector, - DiscoverableToolAction::Install, - "Find and reference emails from your inbox", - "connector_68df038e0ba48191908c8434991bbac2", - "Gmail", - Some("https://chatgpt.com/apps/gmail/connector_68df038e0ba48191908c8434991bbac2"), - ); - - assert_eq!( - meta, - ToolSuggestMeta { - codex_approval_kind: TOOL_SUGGEST_APPROVAL_KIND_VALUE, - tool_type: DiscoverableToolType::Connector, - suggest_type: DiscoverableToolAction::Install, - suggest_reason: "Find and reference emails from your inbox", - tool_id: "connector_68df038e0ba48191908c8434991bbac2", - tool_name: "Gmail", - install_url: Some( - "https://chatgpt.com/apps/gmail/connector_68df038e0ba48191908c8434991bbac2" - ), - }, - ); -} - -#[test] -fn verified_connector_suggestion_completed_requires_accessible_connector() { - let accessible_connectors = vec![AppInfo { - id: "calendar".to_string(), - name: "Google Calendar".to_string(), - description: None, - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: None, - is_accessible: true, - is_enabled: false, - plugin_display_names: Vec::new(), - }]; - - assert!(verified_connector_suggestion_completed( - "calendar", - &accessible_connectors, - )); - assert!(!verified_connector_suggestion_completed( - "gmail", - &accessible_connectors, - )); -} - -#[test] -fn all_suggested_connectors_picked_up_requires_every_expected_connector() { - let accessible_connectors = vec![AppInfo { - id: "calendar".to_string(), - name: "Google Calendar".to_string(), - description: None, - logo_url: None, - logo_url_dark: None, - distribution_channel: None, - branding: None, - app_metadata: None, - labels: None, - install_url: None, - is_accessible: true, - is_enabled: false, - plugin_display_names: Vec::new(), - }]; - - assert!(all_suggested_connectors_picked_up( - &["calendar".to_string()], - &accessible_connectors, - )); - assert!(!all_suggested_connectors_picked_up( - &["calendar".to_string(), "gmail".to_string()], - &accessible_connectors, - )); -} diff --git a/vendor/codex/codex-rs/tui/src/app/event_dispatch.rs b/vendor/codex/codex-rs/tui/src/app/event_dispatch.rs index 2b533509..553062a8 100644 --- a/vendor/codex/codex-rs/tui/src/app/event_dispatch.rs +++ b/vendor/codex/codex-rs/tui/src/app/event_dispatch.rs @@ -292,9 +292,6 @@ impl App { url, is_installed, is_enabled, - suggest_reason: None, - suggestion_type: None, - elicitation_target: None, }); } AppEvent::OpenUrlInBrowser { url } => { diff --git a/vendor/codex/codex-rs/tui/src/bottom_pane/app_link_view.rs b/vendor/codex/codex-rs/tui/src/bottom_pane/app_link_view.rs index 4ffdb304..5dbbcf1e 100644 --- a/vendor/codex/codex-rs/tui/src/bottom_pane/app_link_view.rs +++ b/vendor/codex/codex-rs/tui/src/bottom_pane/app_link_view.rs @@ -1,8 +1,3 @@ -use codex_protocol::ThreadId; -use codex_protocol::approvals::ElicitationAction; -use codex_protocol::mcp::RequestId as McpRequestId; -#[cfg(test)] -use codex_protocol::protocol::Op; use crossterm::event::KeyCode; use crossterm::event::KeyEvent; use crossterm::event::KeyModifiers; @@ -24,7 +19,6 @@ use super::scroll_state::ScrollState; use super::selection_popup_common::GenericDisplayRow; use super::selection_popup_common::measure_rows_height; use super::selection_popup_common::render_rows; -use crate::app::app_server_requests::ResolvedAppServerRequest; use crate::app_event::AppEvent; use crate::app_event_sender::AppEventSender; use crate::key_hint; @@ -40,19 +34,6 @@ enum AppLinkScreen { InstallConfirmation, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum AppLinkSuggestionType { - Install, - Enable, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct AppLinkElicitationTarget { - pub(crate) thread_id: ThreadId, - pub(crate) server_name: String, - pub(crate) request_id: McpRequestId, -} - pub(crate) struct AppLinkViewParams { pub(crate) app_id: String, pub(crate) title: String, @@ -61,9 +42,6 @@ pub(crate) struct AppLinkViewParams { pub(crate) url: String, pub(crate) is_installed: bool, pub(crate) is_enabled: bool, - pub(crate) suggest_reason: Option, - pub(crate) suggestion_type: Option, - pub(crate) elicitation_target: Option, } pub(crate) struct AppLinkView { @@ -74,9 +52,6 @@ pub(crate) struct AppLinkView { url: String, is_installed: bool, is_enabled: bool, - suggest_reason: Option, - suggestion_type: Option, - elicitation_target: Option, app_event_tx: AppEventSender, screen: AppLinkScreen, selected_action: usize, @@ -93,9 +68,6 @@ impl AppLinkView { url, is_installed, is_enabled, - suggest_reason, - suggestion_type, - elicitation_target, } = params; Self { app_id, @@ -105,9 +77,6 @@ impl AppLinkView { url, is_installed, is_enabled, - suggest_reason, - suggestion_type, - elicitation_target, app_event_tx, screen: AppLinkScreen::Link, selected_action: 0, @@ -144,29 +113,6 @@ impl AppLinkView { self.selected_action = (self.selected_action + 1).min(self.action_labels().len() - 1); } - fn is_tool_suggestion(&self) -> bool { - self.elicitation_target.is_some() - } - - fn resolve_elicitation(&self, decision: ElicitationAction) { - let Some(target) = self.elicitation_target.as_ref() else { - return; - }; - self.app_event_tx.resolve_elicitation( - target.thread_id, - target.server_name.clone(), - target.request_id.clone(), - decision, - /*content*/ None, - /*meta*/ None, - ); - } - - fn decline_tool_suggestion(&mut self) { - self.resolve_elicitation(ElicitationAction::Decline); - self.complete = true; - } - fn open_chatgpt_link(&mut self) { self.app_event_tx.send(AppEvent::OpenUrlInBrowser { url: self.url.clone(), @@ -181,9 +127,6 @@ impl AppLinkView { self.app_event_tx.send(AppEvent::RefreshConnectors { force_refetch: true, }); - if self.is_tool_suggestion() { - self.resolve_elicitation(ElicitationAction::Accept); - } self.complete = true; } @@ -198,40 +141,9 @@ impl AppLinkView { id: self.app_id.clone(), enabled: self.is_enabled, }); - if self.is_tool_suggestion() { - self.resolve_elicitation(ElicitationAction::Accept); - self.complete = true; - } } fn activate_selected_action(&mut self) { - if self.is_tool_suggestion() { - match self.suggestion_type { - Some(AppLinkSuggestionType::Enable) => match self.screen { - AppLinkScreen::Link => match self.selected_action { - 0 => self.open_chatgpt_link(), - 1 if self.is_installed => self.toggle_enabled(), - _ => self.decline_tool_suggestion(), - }, - AppLinkScreen::InstallConfirmation => match self.selected_action { - 0 => self.refresh_connectors_and_close(), - _ => self.decline_tool_suggestion(), - }, - }, - Some(AppLinkSuggestionType::Install) | None => match self.screen { - AppLinkScreen::Link => match self.selected_action { - 0 => self.open_chatgpt_link(), - _ => self.decline_tool_suggestion(), - }, - AppLinkScreen::InstallConfirmation => match self.selected_action { - 0 => self.refresh_connectors_and_close(), - _ => self.decline_tool_suggestion(), - }, - }, - } - return; - } - match self.screen { AppLinkScreen::Link => match self.selected_action { 0 => self.open_chatgpt_link(), @@ -269,17 +181,6 @@ impl AppLinkView { } lines.push(Line::from("")); - if let Some(suggest_reason) = self - .suggest_reason - .as_deref() - .map(str::trim) - .filter(|suggest_reason| !suggest_reason.is_empty()) - { - for line in wrap(suggest_reason, usable_width) { - lines.push(Line::from(line.into_owned().italic())); - } - lines.push(Line::from("")); - } if self.is_installed { for line in wrap("Use $ to insert this app into the prompt.", usable_width) { lines.push(Line::from(line.into_owned())); @@ -465,9 +366,6 @@ impl BottomPaneView for AppLinkView { } fn on_ctrl_c(&mut self) -> CancellationEvent { - if self.is_tool_suggestion() { - self.resolve_elicitation(ElicitationAction::Decline); - } self.complete = true; CancellationEvent::Handled } @@ -475,25 +373,6 @@ impl BottomPaneView for AppLinkView { fn is_complete(&self) -> bool { self.complete } - - fn dismiss_app_server_request(&mut self, request: &ResolvedAppServerRequest) -> bool { - let ResolvedAppServerRequest::McpElicitation { - server_name, - request_id, - } = request - else { - return false; - }; - let Some(target) = self.elicitation_target.as_ref() else { - return false; - }; - if target.server_name != *server_name || target.request_id != *request_id { - return false; - } - - self.complete = true; - true - } } impl crate::render::renderable::Renderable for AppLinkView { @@ -566,44 +445,11 @@ impl crate::render::renderable::Renderable for AppLinkView { #[cfg(test)] mod tests { use super::*; - use crate::app::app_server_requests::ResolvedAppServerRequest; use crate::app_event::AppEvent; use crate::render::renderable::Renderable; - use insta::assert_snapshot; use pretty_assertions::assert_eq; use tokio::sync::mpsc::unbounded_channel; - fn suggestion_target() -> AppLinkElicitationTarget { - AppLinkElicitationTarget { - thread_id: ThreadId::try_from("00000000-0000-0000-0000-000000000001") - .expect("valid thread id"), - server_name: "codex_apps".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - } - } - - fn render_snapshot(view: &AppLinkView, area: Rect) -> String { - let mut buf = Buffer::empty(area); - view.render(area, &mut buf); - (0..area.height) - .map(|y| { - (0..area.width) - .map(|x| { - let symbol = buf[(x, y)].symbol(); - if symbol.is_empty() { - ' ' - } else { - symbol.chars().next().unwrap_or(' ') - } - }) - .collect::() - .trim_end() - .to_string() - }) - .collect::>() - .join("\n") - } - #[test] fn installed_app_has_toggle_action() { let (tx_raw, _rx) = unbounded_channel::(); @@ -617,9 +463,6 @@ mod tests { url: "https://example.test/notion".to_string(), is_installed: true, is_enabled: true, - suggest_reason: None, - suggestion_type: None, - elicitation_target: None, }, tx, ); @@ -643,9 +486,6 @@ mod tests { url: "https://example.test/notion".to_string(), is_installed: true, is_enabled: true, - suggest_reason: None, - suggestion_type: None, - elicitation_target: None, }, tx, ); @@ -682,9 +522,6 @@ mod tests { url: url_like.to_string(), is_installed: true, is_enabled: true, - suggest_reason: None, - suggestion_type: None, - elicitation_target: None, }, tx, ); @@ -725,9 +562,6 @@ mod tests { url: url.to_string(), is_installed: true, is_enabled: true, - suggest_reason: None, - suggestion_type: None, - elicitation_target: None, }, tx, ); @@ -760,270 +594,4 @@ mod tests { "expected wrapped setup URL tail to remain visible in narrow pane, got:\n{rendered_blob}" ); } - - #[test] - fn install_tool_suggestion_resolves_elicitation_after_confirmation() { - let (tx_raw, mut rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let mut view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Install this app in your browser, then return here.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: false, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Install), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - view.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); - match rx.try_recv() { - Ok(AppEvent::OpenUrlInBrowser { url }) => { - assert_eq!(url, "https://example.test/google-calendar".to_string()); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - assert_eq!(view.screen, AppLinkScreen::InstallConfirmation); - - view.handle_key_event(KeyEvent::new(KeyCode::Enter, KeyModifiers::NONE)); - match rx.try_recv() { - Ok(AppEvent::RefreshConnectors { force_refetch }) => { - assert!(force_refetch); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - match rx.try_recv() { - Ok(AppEvent::SubmitThreadOp { thread_id, op }) => { - assert_eq!(thread_id, suggestion_target().thread_id); - assert_eq!( - op, - Op::ResolveElicitation { - server_name: "codex_apps".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - decision: ElicitationAction::Accept, - content: None, - meta: None, - } - ); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - assert!(view.is_complete()); - } - - #[test] - fn declined_tool_suggestion_resolves_elicitation_decline() { - let (tx_raw, mut rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let mut view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: None, - instructions: "Install this app in your browser, then return here.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: false, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Install), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - view.handle_key_event(KeyEvent::new(KeyCode::Char('2'), KeyModifiers::NONE)); - - match rx.try_recv() { - Ok(AppEvent::SubmitThreadOp { thread_id, op }) => { - assert_eq!(thread_id, suggestion_target().thread_id); - assert_eq!( - op, - Op::ResolveElicitation { - server_name: "codex_apps".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - decision: ElicitationAction::Decline, - content: None, - meta: None, - } - ); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - assert!(view.is_complete()); - } - - #[test] - fn enable_tool_suggestion_resolves_elicitation_after_enable() { - let (tx_raw, mut rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let mut view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Enable this app to use it for the current request.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: true, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Enable), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - view.handle_key_event(KeyEvent::new(KeyCode::Char('2'), KeyModifiers::NONE)); - - match rx.try_recv() { - Ok(AppEvent::SetAppEnabled { id, enabled }) => { - assert_eq!(id, "connector_google_calendar"); - assert!(enabled); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - match rx.try_recv() { - Ok(AppEvent::SubmitThreadOp { thread_id, op }) => { - assert_eq!(thread_id, suggestion_target().thread_id); - assert_eq!( - op, - Op::ResolveElicitation { - server_name: "codex_apps".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - decision: ElicitationAction::Accept, - content: None, - meta: None, - } - ); - } - Ok(other) => panic!("unexpected app event: {other:?}"), - Err(err) => panic!("missing app event: {err}"), - } - assert!(view.is_complete()); - } - - #[test] - fn resolved_tool_suggestion_dismisses_matching_view() { - let (tx_raw, _rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let mut view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Enable this app to use it for the current request.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: true, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Enable), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - assert!( - view.dismiss_app_server_request(&ResolvedAppServerRequest::McpElicitation { - server_name: "codex_apps".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - }) - ); - assert!(view.is_complete()); - } - - #[test] - fn resolved_tool_suggestion_ignores_non_matching_request() { - let (tx_raw, _rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let mut view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Enable this app to use it for the current request.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: true, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Enable), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - assert!( - !view.dismiss_app_server_request(&ResolvedAppServerRequest::McpElicitation { - server_name: "other_server".to_string(), - request_id: McpRequestId::String("request-1".to_string()), - }) - ); - assert!(!view.is_complete()); - } - - #[test] - fn install_suggestion_with_reason_snapshot() { - let (tx_raw, _rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Install this app in your browser, then return here.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: false, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Install), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - assert_snapshot!( - "app_link_view_install_suggestion_with_reason", - render_snapshot( - &view, - Rect::new(0, 0, 72, view.desired_height(/*width*/ 72)) - ) - ); - } - - #[test] - fn enable_suggestion_with_reason_snapshot() { - let (tx_raw, _rx) = unbounded_channel::(); - let tx = AppEventSender::new(tx_raw); - let view = AppLinkView::new( - AppLinkViewParams { - app_id: "connector_google_calendar".to_string(), - title: "Google Calendar".to_string(), - description: Some("Plan events and schedules.".to_string()), - instructions: "Enable this app to use it for the current request.".to_string(), - url: "https://example.test/google-calendar".to_string(), - is_installed: true, - is_enabled: false, - suggest_reason: Some("Plan and reference events from your calendar".to_string()), - suggestion_type: Some(AppLinkSuggestionType::Enable), - elicitation_target: Some(suggestion_target()), - }, - tx, - ); - - assert_snapshot!( - "app_link_view_enable_suggestion_with_reason", - render_snapshot( - &view, - Rect::new(0, 0, 72, view.desired_height(/*width*/ 72)) - ) - ); - } } diff --git a/vendor/codex/codex-rs/tui/src/bottom_pane/mcp_server_elicitation.rs b/vendor/codex/codex-rs/tui/src/bottom_pane/mcp_server_elicitation.rs index 3c0abec2..bfe6a1e5 100644 --- a/vendor/codex/codex-rs/tui/src/bottom_pane/mcp_server_elicitation.rs +++ b/vendor/codex/codex-rs/tui/src/bottom_pane/mcp_server_elicitation.rs @@ -59,7 +59,6 @@ const APPROVAL_DECLINE_VALUE: &str = "decline"; const APPROVAL_CANCEL_VALUE: &str = "cancel"; const APPROVAL_META_KIND_KEY: &str = "codex_approval_kind"; const APPROVAL_META_KIND_MCP_TOOL_CALL: &str = "mcp_tool_call"; -const APPROVAL_META_KIND_TOOL_SUGGESTION: &str = "tool_suggestion"; const APPROVAL_PERSIST_KEY: &str = "persist"; const APPROVAL_PERSIST_SESSION_VALUE: &str = "session"; const APPROVAL_PERSIST_ALWAYS_VALUE: &str = "always"; @@ -67,12 +66,6 @@ const APPROVAL_TOOL_PARAMS_KEY: &str = "tool_params"; const APPROVAL_TOOL_PARAMS_DISPLAY_KEY: &str = "tool_params_display"; const APPROVAL_TOOL_PARAM_DISPLAY_LIMIT: usize = 3; const APPROVAL_TOOL_PARAM_VALUE_TRUNCATE_GRAPHEMES: usize = 60; -const TOOL_TYPE_KEY: &str = "tool_type"; -const TOOL_ID_KEY: &str = "tool_id"; -const TOOL_NAME_KEY: &str = "tool_name"; -const TOOL_SUGGEST_SUGGEST_TYPE_KEY: &str = "suggest_type"; -const TOOL_SUGGEST_REASON_KEY: &str = "suggest_reason"; -const TOOL_SUGGEST_INSTALL_URL_KEY: &str = "install_url"; #[derive(Clone, PartialEq, Default)] struct ComposerDraft { @@ -133,28 +126,6 @@ enum McpServerElicitationResponseMode { ApprovalAction, } -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum ToolSuggestionToolType { - Connector, - Plugin, -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub(crate) enum ToolSuggestionType { - Install, - Enable, -} - -#[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) struct ToolSuggestionRequest { - pub(crate) tool_type: ToolSuggestionToolType, - pub(crate) suggest_type: ToolSuggestionType, - pub(crate) suggest_reason: String, - pub(crate) tool_id: String, - pub(crate) tool_name: String, - pub(crate) install_url: Option, -} - #[derive(Clone, Debug, PartialEq)] struct McpToolApprovalDisplayParam { name: String, @@ -171,7 +142,6 @@ pub(crate) struct McpServerElicitationFormRequest { approval_display_params: Vec, response_mode: McpServerElicitationResponseMode, fields: Vec, - tool_suggestion: Option, } #[derive(Default)] @@ -265,7 +235,6 @@ impl McpServerElicitationFormRequest { message: String, requested_schema: Value, ) -> Option { - let tool_suggestion = parse_tool_suggestion_request(meta.as_ref()); let is_tool_approval = meta .as_ref() .and_then(Value::as_object) @@ -287,9 +256,7 @@ impl McpServerElicitationFormRequest { Vec::new() }; - let (response_mode, fields) = if tool_suggestion.is_some() && is_message_only_schema { - (McpServerElicitationResponseMode::FormContent, Vec::new()) - } else if is_message_only_schema { + let (response_mode, fields) = if is_message_only_schema { let allow_description = if is_tool_approval_action { "Run the tool and continue." } else { @@ -372,63 +339,9 @@ impl McpServerElicitationFormRequest { approval_display_params, response_mode, fields, - tool_suggestion, }) } - pub(crate) fn tool_suggestion(&self) -> Option<&ToolSuggestionRequest> { - self.tool_suggestion.as_ref() - } - - pub(crate) fn thread_id(&self) -> ThreadId { - self.thread_id - } - - pub(crate) fn server_name(&self) -> &str { - self.server_name.as_str() - } - - pub(crate) fn request_id(&self) -> &McpRequestId { - &self.request_id - } -} - -fn parse_tool_suggestion_request(meta: Option<&Value>) -> Option { - let meta = meta?.as_object()?; - if meta.get(APPROVAL_META_KIND_KEY).and_then(Value::as_str) - != Some(APPROVAL_META_KIND_TOOL_SUGGESTION) - { - return None; - } - - let tool_type = match meta.get(TOOL_TYPE_KEY).and_then(Value::as_str) { - Some("connector") => ToolSuggestionToolType::Connector, - Some("plugin") => ToolSuggestionToolType::Plugin, - _ => return None, - }; - let suggest_type = match meta - .get(TOOL_SUGGEST_SUGGEST_TYPE_KEY) - .and_then(Value::as_str) - { - Some("install") => ToolSuggestionType::Install, - Some("enable") => ToolSuggestionType::Enable, - _ => return None, - }; - - Some(ToolSuggestionRequest { - tool_type, - suggest_type, - suggest_reason: meta - .get(TOOL_SUGGEST_REASON_KEY) - .and_then(Value::as_str)? - .to_string(), - tool_id: meta.get(TOOL_ID_KEY).and_then(Value::as_str)?.to_string(), - tool_name: meta.get(TOOL_NAME_KEY).and_then(Value::as_str)?.to_string(), - install_url: meta - .get(TOOL_SUGGEST_INSTALL_URL_KEY) - .and_then(Value::as_str) - .map(ToString::to_string), - }) } fn approval_supports_persist_mode(meta: Option<&Value>, expected_mode: &str) -> bool { @@ -1862,7 +1775,6 @@ mod tests { default_idx: None, }, }], - tool_suggestion: None, } ); } @@ -1933,7 +1845,6 @@ mod tests { default_idx: Some(0), }, }], - tool_suggestion: None, } ); } @@ -1985,76 +1896,10 @@ mod tests { default_idx: Some(0), }, }], - tool_suggestion: None, } ); } - #[test] - fn tool_suggestion_meta_is_parsed_into_request_payload() { - let request = McpServerElicitationFormRequest::from_event( - ThreadId::default(), - form_request( - "Suggest Google Calendar", - empty_object_schema(), - Some(serde_json::json!({ - "codex_approval_kind": "tool_suggestion", - "tool_type": "connector", - "suggest_type": "install", - "suggest_reason": "Plan and reference events from your calendar", - "tool_id": "connector_2128aebfecb84f64a069897515042a44", - "tool_name": "Google Calendar", - "install_url": "https://example.test/google-calendar", - })), - ), - ) - .expect("expected tool suggestion form"); - - assert_eq!( - request.tool_suggestion(), - Some(&ToolSuggestionRequest { - tool_type: ToolSuggestionToolType::Connector, - suggest_type: ToolSuggestionType::Install, - suggest_reason: "Plan and reference events from your calendar".to_string(), - tool_id: "connector_2128aebfecb84f64a069897515042a44".to_string(), - tool_name: "Google Calendar".to_string(), - install_url: Some("https://example.test/google-calendar".to_string()), - }) - ); - } - - #[test] - fn plugin_tool_suggestion_meta_without_install_url_is_parsed_into_request_payload() { - let request = McpServerElicitationFormRequest::from_event( - ThreadId::default(), - form_request( - "Suggest Slack", - empty_object_schema(), - Some(serde_json::json!({ - "codex_approval_kind": "tool_suggestion", - "tool_type": "plugin", - "suggest_type": "install", - "suggest_reason": "Install the Slack plugin to search messages", - "tool_id": "slack@openai-curated", - "tool_name": "Slack", - })), - ), - ) - .expect("expected tool suggestion form"); - - assert_eq!( - request.tool_suggestion(), - Some(&ToolSuggestionRequest { - tool_type: ToolSuggestionToolType::Plugin, - suggest_type: ToolSuggestionType::Install, - suggest_reason: "Install the Slack plugin to search messages".to_string(), - tool_id: "slack@openai-curated".to_string(), - tool_name: "Slack".to_string(), - install_url: None, - }) - ); - } - #[test] fn tool_approval_display_params_prefer_explicit_display_order() { let request = McpServerElicitationFormRequest::from_event( diff --git a/vendor/codex/codex-rs/tui/src/bottom_pane/mod.rs b/vendor/codex/codex-rs/tui/src/bottom_pane/mod.rs index 96d938e8..8d035ccc 100644 --- a/vendor/codex/codex-rs/tui/src/bottom_pane/mod.rs +++ b/vendor/codex/codex-rs/tui/src/bottom_pane/mod.rs @@ -50,8 +50,6 @@ mod request_user_input; mod status_line_setup; mod status_surface_preview; mod title_setup; -pub(crate) use app_link_view::AppLinkElicitationTarget; -pub(crate) use app_link_view::AppLinkSuggestionType; pub(crate) use app_link_view::AppLinkView; pub(crate) use app_link_view::AppLinkViewParams; pub(crate) use approval_overlay::ApprovalOverlay; @@ -1002,54 +1000,6 @@ impl BottomPane { request }; - if let Some(tool_suggestion) = request.tool_suggestion() - && let Some(install_url) = tool_suggestion.install_url.clone() - { - let suggestion_type = match tool_suggestion.suggest_type { - mcp_server_elicitation::ToolSuggestionType::Install => { - AppLinkSuggestionType::Install - } - mcp_server_elicitation::ToolSuggestionType::Enable => AppLinkSuggestionType::Enable, - }; - let is_installed = matches!( - tool_suggestion.suggest_type, - mcp_server_elicitation::ToolSuggestionType::Enable - ); - let view = AppLinkView::new( - AppLinkViewParams { - app_id: tool_suggestion.tool_id.clone(), - title: tool_suggestion.tool_name.clone(), - description: None, - instructions: match suggestion_type { - AppLinkSuggestionType::Install => { - "Install this app in your browser, then return here.".to_string() - } - AppLinkSuggestionType::Enable => { - "Enable this app to use it for the current request.".to_string() - } - }, - url: install_url, - is_installed, - is_enabled: false, - suggest_reason: Some(tool_suggestion.suggest_reason.clone()), - suggestion_type: Some(suggestion_type), - elicitation_target: Some(AppLinkElicitationTarget { - thread_id: request.thread_id(), - server_name: request.server_name().to_string(), - request_id: request.request_id().clone(), - }), - }, - self.app_event_tx.clone(), - ); - self.pause_status_timer_for_modal(); - self.set_composer_input_enabled( - /*enabled*/ false, - Some("Respond to the tool suggestion to continue.".to_string()), - ); - self.push_view(Box::new(view)); - return; - } - let modal = McpServerElicitationOverlay::new( request, self.app_event_tx.clone(), diff --git a/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_enable_suggestion_with_reason.snap b/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_enable_suggestion_with_reason.snap deleted file mode 100644 index 94980ff6..00000000 --- a/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_enable_suggestion_with_reason.snap +++ /dev/null @@ -1,20 +0,0 @@ ---- -source: tui/src/bottom_pane/app_link_view.rs -expression: "render_snapshot(&view, Rect::new(0, 0, 72, view.desired_height(72)))" ---- - - Google Calendar - Plan events and schedules. - - Plan and reference events from your calendar - - Use $ to insert this app into the prompt. - - Enable this app to use it for the current request. - Newly installed apps can take a few minutes to appear in /apps. - - - › 1. Manage on ChatGPT - 2. Enable app - 3. Back - Use tab / ↑ ↓ to move, enter to select, esc to close diff --git a/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_install_suggestion_with_reason.snap b/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_install_suggestion_with_reason.snap deleted file mode 100644 index ac47f874..00000000 --- a/vendor/codex/codex-rs/tui/src/bottom_pane/snapshots/codex_tui__bottom_pane__app_link_view__tests__app_link_view_install_suggestion_with_reason.snap +++ /dev/null @@ -1,18 +0,0 @@ ---- -source: tui/src/bottom_pane/app_link_view.rs -expression: "render_snapshot(&view, Rect::new(0, 0, 72, view.desired_height(72)))" ---- - - Google Calendar - Plan events and schedules. - - Plan and reference events from your calendar - - Install this app in your browser, then return here. - Newly installed apps can take a few minutes to appear in /apps. - After installed, use $ to insert this app into the prompt. - - - › 1. Install on ChatGPT - 2. Back - Use tab / ↑ ↓ to move, enter to select, esc to close