diff --git a/codex-rs/app-server-protocol/src/protocol/common.rs b/codex-rs/app-server-protocol/src/protocol/common.rs index d8394635b1..0204c13b5b 100644 --- a/codex-rs/app-server-protocol/src/protocol/common.rs +++ b/codex-rs/app-server-protocol/src/protocol/common.rs @@ -2935,7 +2935,9 @@ mod tests { turn_id: Some("turn_123".to_string()), server_name: "codex_apps".to_string(), request: v2::McpServerElicitationRequest::Form { - meta: None, + meta: Some(json!({ + "suggestion_id": "request_plugin_install_install-github" + })), message: "Allow this request?".to_string(), requested_schema, }, @@ -2954,7 +2956,9 @@ mod tests { "turnId": "turn_123", "serverName": "codex_apps", "mode": "form", - "_meta": null, + "_meta": { + "suggestion_id": "request_plugin_install_install-github" + }, "message": "Allow this request?", "requestedSchema": { "type": "object", diff --git a/codex-rs/core/src/tools/handlers/request_plugin_install.rs b/codex-rs/core/src/tools/handlers/request_plugin_install.rs index 6236423d23..02dcebc54d 100644 --- a/codex-rs/core/src/tools/handlers/request_plugin_install.rs +++ b/codex-rs/core/src/tools/handlers/request_plugin_install.rs @@ -235,8 +235,9 @@ impl RequestPluginInstallHandler { ); } + let request = + build_request_plugin_install_elicitation_request(suggest_reason, &tool, &suggestion_id); let request_id = RequestId::String(suggestion_id.into()); - let request = build_request_plugin_install_elicitation_request(suggest_reason, &tool); let elicitation = session .request_mcp_server_elicitation( turn.as_ref(), diff --git a/codex-rs/core/tests/suite/request_plugin_install.rs b/codex-rs/core/tests/suite/request_plugin_install.rs index 571697f24c..5d3eda19bb 100644 --- a/codex-rs/core/tests/suite/request_plugin_install.rs +++ b/codex-rs/core/tests/suite/request_plugin_install.rs @@ -859,6 +859,10 @@ async fn run_remote_plugin_install_metadata_case() -> Result<()> { } tokio::time::sleep(Duration::from_millis(50)).await; }; + assert_eq!( + meta["suggestion_id"], + analytics_event["event_params"]["suggestion_id"] + ); let thread_id = analytics_event["event_params"]["thread_id"].clone(); let turn_id = analytics_event["event_params"]["turn_id"].clone(); assert_eq!( diff --git a/codex-rs/tools/src/request_plugin_install.rs b/codex-rs/tools/src/request_plugin_install.rs index 207a9d7249..3316c2565f 100644 --- a/codex-rs/tools/src/request_plugin_install.rs +++ b/codex-rs/tools/src/request_plugin_install.rs @@ -41,6 +41,8 @@ pub struct RequestPluginInstallMeta<'a> { pub tool_id: &'a str, pub tool_name: &'a str, #[serde(skip_serializing_if = "Option::is_none")] + pub suggestion_id: Option<&'a str>, + #[serde(skip_serializing_if = "Option::is_none")] pub install_url: Option<&'a str>, #[serde(skip_serializing_if = "Option::is_none")] pub remote_plugin_id: Option<&'a str>, @@ -51,6 +53,7 @@ pub struct RequestPluginInstallMeta<'a> { pub fn build_request_plugin_install_elicitation_request( suggest_reason: &str, tool: &DiscoverableTool, + suggestion_id: &str, ) -> ElicitationRequest { let message = suggest_reason.to_string(); @@ -58,6 +61,7 @@ pub fn build_request_plugin_install_elicitation_request( meta: Some(json!(build_request_plugin_install_meta( suggest_reason, tool, + suggestion_id, ))), message, requested_schema: json!({ @@ -89,11 +93,13 @@ pub fn verified_connector_install_completed( fn build_request_plugin_install_meta<'a>( suggest_reason: &'a str, tool: &'a DiscoverableTool, + suggestion_id: &'a str, ) -> RequestPluginInstallMeta<'a> { - let (tool_type, remote_plugin_id, app_connector_ids) = match tool { - DiscoverableTool::Connector(_) => (DiscoverableToolType::Connector, None, None), + let (tool_type, suggestion_id, remote_plugin_id, app_connector_ids) = match tool { + DiscoverableTool::Connector(_) => (DiscoverableToolType::Connector, None, None, None), DiscoverableTool::Plugin(plugin) => ( DiscoverableToolType::Plugin, + Some(suggestion_id), plugin.remote_plugin_id.as_deref(), Some(plugin.app_connector_ids.as_slice()), ), @@ -106,6 +112,7 @@ fn build_request_plugin_install_meta<'a>( suggest_reason, tool_id: tool.id(), tool_name: tool.name(), + suggestion_id, install_url: tool.install_url(), remote_plugin_id, app_connector_ids, diff --git a/codex-rs/tools/src/request_plugin_install_tests.rs b/codex-rs/tools/src/request_plugin_install_tests.rs index 666d0f2466..eb1c78e7c4 100644 --- a/codex-rs/tools/src/request_plugin_install_tests.rs +++ b/codex-rs/tools/src/request_plugin_install_tests.rs @@ -29,6 +29,7 @@ fn build_request_plugin_install_elicitation_request_uses_expected_shape() { let request = build_request_plugin_install_elicitation_request( "Plan and reference events from your calendar", &connector, + "request_plugin_install_connector-calendar", ); assert_eq!( @@ -42,6 +43,7 @@ fn build_request_plugin_install_elicitation_request_uses_expected_shape() { suggest_reason: "Plan and reference events from your calendar", tool_id: "connector_2128aebfecb84f64a069897515042a44", tool_name: "Google Calendar", + suggestion_id: None, install_url: Some( "https://chatgpt.com/apps/google-calendar/connector_2128aebfecb84f64a069897515042a44" ), @@ -72,6 +74,7 @@ fn build_request_plugin_install_elicitation_request_injects_plugin_metadata() { let request = build_request_plugin_install_elicitation_request( "Use the sample plugin's skills and MCP server", &plugin, + "request_plugin_install_install-sample", ); assert_eq!( @@ -85,6 +88,7 @@ fn build_request_plugin_install_elicitation_request_injects_plugin_metadata() { suggest_reason: "Use the sample plugin's skills and MCP server", tool_id: "sample@openai-curated-remote", tool_name: "Sample Plugin", + suggestion_id: Some("request_plugin_install_install-sample"), install_url: None, remote_plugin_id: Some("plugins~Plugin_sample"), app_connector_ids: Some(&["connector_calendar".to_string()]), @@ -119,8 +123,11 @@ fn build_request_plugin_install_meta_uses_expected_shape() { is_enabled: true, plugin_display_names: Vec::new(), })); - let meta = - build_request_plugin_install_meta("Find and reference emails from your inbox", &connector); + let meta = build_request_plugin_install_meta( + "Find and reference emails from your inbox", + &connector, + "request_plugin_install_connector-gmail", + ); assert_eq!( meta, @@ -132,6 +139,7 @@ fn build_request_plugin_install_meta_uses_expected_shape() { suggest_reason: "Find and reference emails from your inbox", tool_id: "connector_68df038e0ba48191908c8434991bbac2", tool_name: "Gmail", + suggestion_id: None, install_url: Some( "https://chatgpt.com/apps/gmail/connector_68df038e0ba48191908c8434991bbac2" ),