use super::*;use rmcp::model::BooleanSchema;use rmcp::model::ElicitationSchema;use rmcp::model::PrimitiveSchema;use serde_json::json;fn meta(value: Value) -> Option<Meta> { let Value::Object(map) = value else { panic!("metadata must be an object"); }; Some(Meta(map))}fn guardian_meta(tool_params: Option<Value>) -> Option<Meta> { let mut value = json!({ "codex_approval_kind": "mcp_tool_call", "codex_request_type": "approval_request", "connector_id": "browser-use", "connector_name": "Browser Use", "tool_name": "access_browser_origin", "tool_title": "Access browser origin", }); if let Some(tool_params) = tool_params { value["tool_params"] = tool_params; } meta(value)}fn form_request(meta: Option<Meta>) -> ElicitationReviewRequest { ElicitationReviewRequest { server_name: "browser-use".to_string(), request_id: rmcp::model::NumberOrString::Number(7), elicitation: CreateElicitationRequestParams::FormElicitationParams { meta, message: "Allow origin?".to_string(), requested_schema: ElicitationSchema::builder() .build() .expect("schema should build"), }, }}#[test]fn guardian_elicitation_review_request_builds_mcp_tool_call() { let request = form_request(guardian_meta(Some(json!({ "origin": "https://example.com", })))); let GuardianElicitationReview::ApprovalRequest(guardian_request) = guardian_elicitation_review_request(&request) else { panic!("expected Guardian MCP tool call request"); }; let crate::guardian::GuardianApprovalRequest::McpToolCall { id, server, tool_name, arguments, connector_id, connector_name, connector_description, tool_title, tool_description, annotations, } = *guardian_request else { panic!("expected Guardian MCP tool call request"); }; assert_eq!(id, "mcp_elicitation:browser-use:7"); assert_eq!(server, "browser-use"); assert_eq!(tool_name, "access_browser_origin"); assert_eq!(arguments, Some(json!({ "origin": "https://example.com" }))); assert_eq!(connector_id.as_deref(), Some("browser-use")); assert_eq!(connector_name.as_deref(), Some("Browser Use")); assert_eq!(connector_description, None); assert_eq!(tool_title.as_deref(), Some("Access browser origin")); assert_eq!(tool_description, None); assert_eq!(annotations, None);}#[test]fn guardian_elicitation_review_request_defaults_missing_tool_params() { let request = form_request(guardian_meta(/*tool_params*/ None)); let GuardianElicitationReview::ApprovalRequest(guardian_request) = guardian_elicitation_review_request(&request) else { panic!("expected Guardian MCP tool call request"); }; let crate::guardian::GuardianApprovalRequest::McpToolCall { arguments, .. } = *guardian_request else { panic!("expected Guardian MCP tool call request"); }; assert_eq!(arguments, Some(json!({})));}#[test]fn plugin_install_elicitation_telemetry_metadata_requires_install_tool_suggestion() { let event = EventMsg::ElicitationRequest(ElicitationRequestEvent { turn_id: Some("turn-1".to_string()), server_name: "codex_apps".to_string(), id: codex_protocol::mcp::RequestId::String("request-1".to_string()), request: codex_protocol::approvals::ElicitationRequest::Form { meta: Some(json!({ "codex_approval_kind": "tool_suggestion", "suggest_type": "install", "tool_type": "plugin", "tool_id": "slack@openai-curated", "tool_name": "Slack", })), message: "Install Slack?".to_string(), requested_schema: json!({ "type": "object", "properties": {}, }), }, }); assert_eq!( plugin_install_elicitation_telemetry_metadata(&event), Some(PluginInstallElicitationTelemetryMetadata { tool_type: "plugin".to_string(), tool_id: "slack@openai-curated".to_string(), tool_name: "Slack".to_string(), }) ); let enable_event = EventMsg::ElicitationRequest(ElicitationRequestEvent { turn_id: Some("turn-1".to_string()), server_name: "codex_apps".to_string(), id: codex_protocol::mcp::RequestId::String("request-2".to_string()), request: codex_protocol::approvals::ElicitationRequest::Form { meta: Some(json!({ "codex_approval_kind": "tool_suggestion", "suggest_type": "enable", "tool_type": "plugin", "tool_id": "slack@openai-curated", "tool_name": "Slack", })), message: "Enable Slack?".to_string(), requested_schema: json!({ "type": "object", "properties": {}, }), }, }); assert_eq!( plugin_install_elicitation_telemetry_metadata(&enable_event), None );}#[test]fn guardian_elicitation_review_request_requires_opt_in() { let request = form_request(meta(json!({ "codex_approval_kind": "mcp_tool_call", "tool_name": "access_browser_origin", }))); assert_eq!( guardian_elicitation_review_request(&request), GuardianElicitationReview::NotRequested );}#[test]fn guardian_elicitation_review_request_declines_unsupported_opt_in_shapes() { let url_request = ElicitationReviewRequest { server_name: "browser-use".to_string(), request_id: rmcp::model::NumberOrString::Number(8), elicitation: CreateElicitationRequestParams::UrlElicitationParams { meta: guardian_meta(Some(json!({}))), message: "Open URL".to_string(), url: "https://example.com".to_string(), elicitation_id: "elicit-1".to_string(), }, }; assert!(matches!( guardian_elicitation_review_request(&url_request), GuardianElicitationReview::Decline(_) )); let non_empty_schema_request = ElicitationReviewRequest { server_name: "browser-use".to_string(), request_id: rmcp::model::NumberOrString::Number(9), elicitation: CreateElicitationRequestParams::FormElicitationParams { meta: guardian_meta(Some(json!({}))), message: "Allow origin?".to_string(), requested_schema: ElicitationSchema::builder() .required_property("confirmed", PrimitiveSchema::Boolean(BooleanSchema::new())) .build() .expect("schema should build"), }, }; assert!(matches!( guardian_elicitation_review_request(&non_empty_schema_request), GuardianElicitationReview::Decline(_) )); let missing_tool_name_request = form_request(meta(json!({ "codex_approval_kind": "mcp_tool_call", "codex_request_type": "approval_request", }))); assert!(matches!( guardian_elicitation_review_request(&missing_tool_name_request), GuardianElicitationReview::Decline(_) ));}#[test]fn guardian_decisions_map_to_elicitation_responses_without_session_state() { assert_eq!( mcp_elicitation_response_from_guardian_decision_parts( ReviewDecision::Approved, /*denial_message*/ None, ), ElicitationResponse { action: ElicitationAction::Accept, content: Some(json!({})), meta: Some(json!({ "approvals_reviewer": ApprovalsReviewer::AutoReview, })), } ); assert_eq!( mcp_elicitation_response_from_guardian_decision_parts( ReviewDecision::Denied, Some("Denied by Guardian".to_string()), ), ElicitationResponse { action: ElicitationAction::Decline, content: None, meta: Some(json!({ "approvals_reviewer": ApprovalsReviewer::AutoReview, "message": "Denied by Guardian", })), } ); assert_eq!( mcp_elicitation_response_from_guardian_decision_parts( ReviewDecision::TimedOut, /*denial_message*/ None, ), ElicitationResponse { action: ElicitationAction::Decline, content: None, meta: Some(json!({ "approvals_reviewer": ApprovalsReviewer::AutoReview, "message": crate::guardian::guardian_timeout_message(), })), } ); assert_eq!( mcp_elicitation_response_from_guardian_decision_parts( ReviewDecision::Abort, /*denial_message*/ None, ), ElicitationResponse { action: ElicitationAction::Cancel, content: None, meta: Some(json!({ "approvals_reviewer": ApprovalsReviewer::AutoReview, })), } );}