mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Merge branch 'dev/winston/mitm-sandbox-readable-carvebacks' into dev/winston/mitm-child-env-snapshots
This commit is contained in:
@@ -692,6 +692,9 @@
|
||||
"unified_exec_zsh_fork": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"use_agent_identity": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"use_legacy_landlock": {
|
||||
"type": "boolean"
|
||||
},
|
||||
@@ -4932,6 +4935,9 @@
|
||||
"unified_exec_zsh_fork": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"use_agent_identity": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"use_legacy_landlock": {
|
||||
"type": "boolean"
|
||||
},
|
||||
|
||||
@@ -31,8 +31,8 @@ use codex_core_plugins::PluginsManager;
|
||||
use codex_features::Feature;
|
||||
use codex_login::AuthManager;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_login::default_client::originator;
|
||||
use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_mcp::MCP_TOOL_CODEX_APPS_META_KEY;
|
||||
use codex_mcp::McpConnectionManager;
|
||||
use codex_mcp::McpRuntimeContext;
|
||||
use codex_mcp::ToolInfo;
|
||||
@@ -112,7 +112,6 @@ pub(crate) async fn list_tool_suggest_discoverable_tools_with_auth(
|
||||
directory_connectors,
|
||||
accessible_connectors,
|
||||
&connector_ids,
|
||||
originator().value.as_str(),
|
||||
)
|
||||
.into_iter()
|
||||
.map(DiscoverableTool::from);
|
||||
@@ -143,12 +142,7 @@ pub async fn list_cached_accessible_connectors_from_mcp_tools(
|
||||
return Some(Vec::new());
|
||||
}
|
||||
let cache_key = accessible_connectors_cache_key(config, auth.as_ref());
|
||||
read_cached_accessible_connectors(&cache_key).map(|connectors| {
|
||||
codex_connectors::filter::filter_disallowed_connectors(
|
||||
connectors,
|
||||
originator().value.as_str(),
|
||||
)
|
||||
})
|
||||
read_cached_accessible_connectors(&cache_key)
|
||||
}
|
||||
|
||||
pub(crate) fn refresh_accessible_connectors_cache_from_mcp_tools(
|
||||
@@ -161,10 +155,7 @@ pub(crate) fn refresh_accessible_connectors_cache_from_mcp_tools(
|
||||
}
|
||||
|
||||
let cache_key = accessible_connectors_cache_key(config, auth);
|
||||
let accessible_connectors = codex_connectors::filter::filter_disallowed_connectors(
|
||||
accessible_connectors_from_mcp_tools(mcp_tools),
|
||||
originator().value.as_str(),
|
||||
);
|
||||
let accessible_connectors = accessible_connectors_for_app_list_from_mcp_tools(mcp_tools);
|
||||
write_cached_accessible_connectors(cache_key, &accessible_connectors);
|
||||
}
|
||||
|
||||
@@ -240,10 +231,6 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
|
||||
let tool_plugin_provenance = tool_plugin_provenance(&mcp_config);
|
||||
if !force_refetch && let Some(cached_connectors) = read_cached_accessible_connectors(&cache_key)
|
||||
{
|
||||
let cached_connectors = codex_connectors::filter::filter_disallowed_connectors(
|
||||
cached_connectors,
|
||||
originator().value.as_str(),
|
||||
);
|
||||
let cached_connectors = with_app_plugin_sources(cached_connectors, &tool_plugin_provenance);
|
||||
return Ok(AccessibleConnectorsStatus {
|
||||
connectors: cached_connectors,
|
||||
@@ -353,10 +340,7 @@ pub async fn list_accessible_connectors_from_mcp_tools_with_mcp_manager(
|
||||
cancel_token.cancel();
|
||||
}
|
||||
|
||||
let accessible_connectors = codex_connectors::filter::filter_disallowed_connectors(
|
||||
accessible_connectors_from_mcp_tools(&tools),
|
||||
originator().value.as_str(),
|
||||
);
|
||||
let accessible_connectors = accessible_connectors_for_app_list_from_mcp_tools(&tools);
|
||||
if codex_apps_ready || !accessible_connectors.is_empty() {
|
||||
write_cached_accessible_connectors(cache_key, &accessible_connectors);
|
||||
}
|
||||
@@ -486,9 +470,15 @@ async fn cached_directory_connectors_for_tool_suggest_with_auth(
|
||||
}
|
||||
|
||||
pub(crate) fn accessible_connectors_from_mcp_tools(mcp_tools: &[ToolInfo]) -> Vec<AppInfo> {
|
||||
collect_accessible_connectors_from_mcp_tools(mcp_tools.iter())
|
||||
}
|
||||
|
||||
fn collect_accessible_connectors_from_mcp_tools<'a>(
|
||||
mcp_tools: impl Iterator<Item = &'a ToolInfo>,
|
||||
) -> Vec<AppInfo> {
|
||||
// ToolInfo already carries plugin provenance, so app-level plugin sources
|
||||
// can be derived here instead of requiring a separate enrichment pass.
|
||||
let tools = mcp_tools.iter().filter_map(|tool| {
|
||||
let tools = mcp_tools.filter_map(|tool| {
|
||||
if tool.server_name != CODEX_APPS_MCP_SERVER_NAME {
|
||||
return None;
|
||||
}
|
||||
@@ -503,6 +493,20 @@ pub(crate) fn accessible_connectors_from_mcp_tools(mcp_tools: &[ToolInfo]) -> Ve
|
||||
codex_connectors::accessible::collect_accessible_connectors(tools)
|
||||
}
|
||||
|
||||
fn accessible_connectors_for_app_list_from_mcp_tools(mcp_tools: &[ToolInfo]) -> Vec<AppInfo> {
|
||||
let non_synthetic_tools = mcp_tools.iter().filter(|tool| {
|
||||
tool.tool
|
||||
.meta
|
||||
.as_deref()
|
||||
.and_then(|meta| meta.get(MCP_TOOL_CODEX_APPS_META_KEY))
|
||||
.and_then(serde_json::Value::as_object)
|
||||
.and_then(|meta| meta.get("synthetic_link"))
|
||||
.and_then(serde_json::Value::as_bool)
|
||||
!= Some(true)
|
||||
});
|
||||
collect_accessible_connectors_from_mcp_tools(non_synthetic_tools)
|
||||
}
|
||||
|
||||
pub fn with_app_enabled_state(mut connectors: Vec<AppInfo>, config: &Config) -> Vec<AppInfo> {
|
||||
let user_apps_config = apps_config_from_layer_stack(&config.config_layer_stack);
|
||||
let requirements_apps_config = config.config_layer_stack.requirements_toml().apps.as_ref();
|
||||
|
||||
@@ -17,6 +17,7 @@ use codex_mcp::CODEX_APPS_MCP_SERVER_NAME;
|
||||
use codex_mcp::ToolInfo;
|
||||
use pretty_assertions::assert_eq;
|
||||
use rmcp::model::JsonObject;
|
||||
use rmcp::model::Meta;
|
||||
use rmcp::model::Tool;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::HashSet;
|
||||
@@ -140,6 +141,69 @@ fn accessible_connectors_from_mcp_tools_carries_plugin_display_names() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn synthetic_links_are_exposed_to_the_agent_but_not_accessible_in_app_list() {
|
||||
let mut synthetic_tool = codex_app_tool("gmail_batch_read_email", "gmail", Some("Gmail"), &[]);
|
||||
synthetic_tool.tool.meta = Some(Meta(
|
||||
serde_json::json!({
|
||||
"resource_name": "gmail.batch_read_email",
|
||||
"_codex_apps": {
|
||||
"resource_uri": "/connector/gmail/batch_read_email",
|
||||
"contains_mcp_source": false,
|
||||
"synthetic_link": true
|
||||
}
|
||||
})
|
||||
.as_object()
|
||||
.expect("meta should be an object")
|
||||
.clone(),
|
||||
));
|
||||
let tools = vec![
|
||||
synthetic_tool,
|
||||
codex_app_tool("calendar_list_events", "calendar", Some("Calendar"), &[]),
|
||||
];
|
||||
|
||||
let calendar = AppInfo {
|
||||
id: "calendar".to_string(),
|
||||
name: "Calendar".to_string(),
|
||||
description: None,
|
||||
logo_url: None,
|
||||
logo_url_dark: None,
|
||||
distribution_channel: None,
|
||||
install_url: Some(connector_install_url("Calendar", "calendar")),
|
||||
branding: None,
|
||||
app_metadata: None,
|
||||
labels: None,
|
||||
is_accessible: true,
|
||||
is_enabled: true,
|
||||
plugin_display_names: Vec::new(),
|
||||
};
|
||||
assert_eq!(
|
||||
accessible_connectors_for_app_list_from_mcp_tools(&tools),
|
||||
vec![calendar.clone()]
|
||||
);
|
||||
assert_eq!(
|
||||
accessible_connectors_from_mcp_tools(&tools),
|
||||
vec![
|
||||
calendar,
|
||||
AppInfo {
|
||||
id: "gmail".to_string(),
|
||||
name: "Gmail".to_string(),
|
||||
description: None,
|
||||
logo_url: None,
|
||||
logo_url_dark: None,
|
||||
distribution_channel: None,
|
||||
install_url: Some(connector_install_url("Gmail", "gmail")),
|
||||
branding: None,
|
||||
app_metadata: None,
|
||||
labels: None,
|
||||
is_accessible: true,
|
||||
is_enabled: true,
|
||||
plugin_display_names: Vec::new(),
|
||||
}
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn refresh_accessible_connectors_cache_from_mcp_tools_writes_latest_installed_apps() {
|
||||
let codex_home = tempdir().expect("tempdir should succeed");
|
||||
|
||||
@@ -143,14 +143,7 @@ pub(crate) async fn handle_mcp_tool_call(
|
||||
|
||||
let metadata =
|
||||
lookup_mcp_tool_metadata(sess.as_ref(), turn_context.as_ref(), &server, &tool_name).await;
|
||||
let item_metadata = McpToolCallItemMetadata {
|
||||
mcp_app_resource_uri: metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.mcp_app_resource_uri.clone()),
|
||||
plugin_id: metadata
|
||||
.as_ref()
|
||||
.and_then(|metadata| metadata.plugin_id.clone()),
|
||||
};
|
||||
let item_metadata = McpToolCallItemMetadata::from_tool_metadata(&server, metadata.as_ref());
|
||||
let app_tool_policy = if server == CODEX_APPS_MCP_SERVER_NAME {
|
||||
let annotations = metadata
|
||||
.as_ref()
|
||||
@@ -312,12 +305,32 @@ pub(crate) struct HandledMcpToolCall {
|
||||
pub(crate) tool_input: JsonValue,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
struct McpToolCallItemMetadata {
|
||||
connector_id: Option<String>,
|
||||
link_id: Option<String>,
|
||||
mcp_app_resource_uri: Option<String>,
|
||||
plugin_id: Option<String>,
|
||||
}
|
||||
|
||||
impl McpToolCallItemMetadata {
|
||||
fn from_tool_metadata(server: &str, metadata: Option<&McpToolApprovalMetadata>) -> Self {
|
||||
let trusted_mcp_app_metadata = if server == CODEX_APPS_MCP_SERVER_NAME {
|
||||
metadata
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Self {
|
||||
connector_id: trusted_mcp_app_metadata
|
||||
.and_then(|metadata| metadata.connector_id.clone()),
|
||||
link_id: trusted_mcp_app_metadata.and_then(|metadata| metadata.link_id.clone()),
|
||||
mcp_app_resource_uri: metadata
|
||||
.and_then(|metadata| metadata.mcp_app_resource_uri.clone()),
|
||||
plugin_id: metadata.and_then(|metadata| metadata.plugin_id.clone()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_approved_mcp_tool_call(
|
||||
sess: &Session,
|
||||
turn_context: &TurnContext,
|
||||
@@ -892,7 +905,9 @@ async fn notify_mcp_tool_call_started(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(JsonValue::Null),
|
||||
connector_id: item_metadata.connector_id,
|
||||
mcp_app_resource_uri: item_metadata.mcp_app_resource_uri,
|
||||
link_id: item_metadata.link_id,
|
||||
plugin_id: item_metadata.plugin_id,
|
||||
status: McpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -932,7 +947,9 @@ async fn notify_mcp_tool_call_completed(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(JsonValue::Null),
|
||||
connector_id: item_metadata.connector_id,
|
||||
mcp_app_resource_uri: item_metadata.mcp_app_resource_uri,
|
||||
link_id: item_metadata.link_id,
|
||||
plugin_id: item_metadata.plugin_id,
|
||||
status,
|
||||
result,
|
||||
@@ -998,6 +1015,7 @@ enum McpToolApprovalDecision {
|
||||
pub(crate) struct McpToolApprovalMetadata {
|
||||
annotations: Option<ToolAnnotations>,
|
||||
connector_id: Option<String>,
|
||||
link_id: Option<String>,
|
||||
connector_name: Option<String>,
|
||||
connector_description: Option<String>,
|
||||
plugin_id: Option<String>,
|
||||
@@ -1010,6 +1028,7 @@ pub(crate) struct McpToolApprovalMetadata {
|
||||
|
||||
const MCP_TOOL_OPENAI_OUTPUT_TEMPLATE_META_KEY: &str = "openai/outputTemplate";
|
||||
const MCP_TOOL_UI_RESOURCE_URI_META_KEY: &str = "ui/resourceUri";
|
||||
const MCP_TOOL_LINK_ID_META_KEY: &str = "link_id";
|
||||
const MCP_TOOL_PLUGIN_ID_META_KEY: &str = "plugin_id";
|
||||
const MCP_TOOL_THREAD_ID_META_KEY: &str = "threadId";
|
||||
|
||||
@@ -1493,6 +1512,13 @@ pub(crate) async fn lookup_mcp_tool_metadata(
|
||||
Some(McpToolApprovalMetadata {
|
||||
annotations: tool_info.tool.annotations,
|
||||
connector_id: tool_info.connector_id,
|
||||
link_id: tool_info
|
||||
.tool
|
||||
.meta
|
||||
.as_ref()
|
||||
.and_then(|meta| meta.get(MCP_TOOL_LINK_ID_META_KEY))
|
||||
.and_then(serde_json::Value::as_str)
|
||||
.map(str::to_string),
|
||||
connector_name: tool_info.connector_name,
|
||||
connector_description,
|
||||
plugin_id,
|
||||
|
||||
@@ -78,6 +78,7 @@ fn approval_metadata(
|
||||
McpToolApprovalMetadata {
|
||||
annotations: None,
|
||||
connector_id: connector_id.map(str::to_string),
|
||||
link_id: None,
|
||||
connector_name: connector_name.map(str::to_string),
|
||||
connector_description: connector_description.map(str::to_string),
|
||||
plugin_id: None,
|
||||
@@ -1149,8 +1150,39 @@ async fn plugin_mcp_tool_call_request_meta_includes_plugin_id() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_tool_call_item_metadata_only_trusts_codex_apps_identity() {
|
||||
let mut metadata = approval_metadata(
|
||||
Some("asdk_app_0123456789abcdef0123456789abcdef"),
|
||||
/*connector_name*/ None,
|
||||
/*connector_description*/ None,
|
||||
/*tool_title*/ None,
|
||||
/*tool_description*/ None,
|
||||
);
|
||||
metadata.link_id = Some("link_fedcba9876543210fedcba9876543210".to_string());
|
||||
|
||||
assert_eq!(
|
||||
McpToolCallItemMetadata::from_tool_metadata(CODEX_APPS_MCP_SERVER_NAME, Some(&metadata),),
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: Some("asdk_app_0123456789abcdef0123456789abcdef".to_string()),
|
||||
link_id: Some("link_fedcba9876543210fedcba9876543210".to_string()),
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
}
|
||||
);
|
||||
assert_eq!(
|
||||
McpToolCallItemMetadata::from_tool_metadata("custom_server", Some(&metadata)),
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: None,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
async fn mcp_tool_call_item_includes_app_identity() {
|
||||
let (session, turn_context, rx_event) = make_session_and_context_with_rx().await;
|
||||
|
||||
notify_mcp_tool_call_started(
|
||||
@@ -1158,11 +1190,13 @@ async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
&turn_context,
|
||||
"call-plugin",
|
||||
McpInvocation {
|
||||
server: "sample".to_string(),
|
||||
server: CODEX_APPS_MCP_SERVER_NAME.to_string(),
|
||||
tool: "echo".to_string(),
|
||||
arguments: None,
|
||||
},
|
||||
McpToolCallItemMetadata {
|
||||
connector_id: Some("asdk_app_0123456789abcdef0123456789abcdef".to_string()),
|
||||
link_id: Some("link_fedcba9876543210fedcba9876543210".to_string()),
|
||||
mcp_app_resource_uri: None,
|
||||
plugin_id: Some("sample@test".to_string()),
|
||||
},
|
||||
@@ -1180,6 +1214,14 @@ async fn mcp_tool_call_item_includes_plugin_id() {
|
||||
panic!("expected MCP tool call item");
|
||||
};
|
||||
|
||||
assert_eq!(
|
||||
item.connector_id.as_deref(),
|
||||
Some("asdk_app_0123456789abcdef0123456789abcdef")
|
||||
);
|
||||
assert_eq!(
|
||||
item.link_id.as_deref(),
|
||||
Some("link_fedcba9876543210fedcba9876543210")
|
||||
);
|
||||
assert_eq!(item.plugin_id.as_deref(), Some("sample@test"));
|
||||
}
|
||||
|
||||
@@ -1193,6 +1235,7 @@ async fn codex_apps_tool_call_request_meta_includes_turn_metadata_and_codex_apps
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: None,
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
@@ -1661,6 +1704,7 @@ fn guardian_mcp_review_request_includes_annotations_when_present() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2326,6 +2370,7 @@ async fn approve_mode_skips_when_annotations_do_not_require_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2400,6 +2445,7 @@ async fn guardian_mode_skips_auto_when_annotations_do_not_require_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2457,6 +2503,7 @@ async fn permission_request_hook_allows_mcp_tool_call() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2593,6 +2640,7 @@ async fn permission_request_hook_runs_after_remembered_mcp_approval() {
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2680,6 +2728,7 @@ async fn guardian_mode_mcp_denial_returns_rationale_message() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2734,6 +2783,7 @@ async fn prompt_mode_waits_for_approval_when_annotations_do_not_require_approval
|
||||
/*open_world*/ None,
|
||||
)),
|
||||
connector_id: None,
|
||||
link_id: None,
|
||||
connector_name: None,
|
||||
connector_description: None,
|
||||
plugin_id: None,
|
||||
@@ -2789,6 +2839,7 @@ async fn full_access_mode_skips_mcp_tool_approval_for_all_approval_modes() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
@@ -2842,6 +2893,7 @@ async fn approve_mode_skips_guardian_in_every_permission_mode() {
|
||||
let metadata = McpToolApprovalMetadata {
|
||||
annotations: Some(annotations(Some(false), Some(true), Some(true))),
|
||||
connector_id: Some("calendar".to_string()),
|
||||
link_id: None,
|
||||
connector_name: Some("Calendar".to_string()),
|
||||
connector_description: Some("Manage events".to_string()),
|
||||
plugin_id: None,
|
||||
|
||||
@@ -203,7 +203,9 @@ async fn emit_tool_call_begin(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(Value::Null),
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
status: McpToolCallStatus::InProgress,
|
||||
result: None,
|
||||
@@ -242,7 +244,9 @@ async fn emit_tool_call_end(
|
||||
server,
|
||||
tool,
|
||||
arguments: arguments.unwrap_or(Value::Null),
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
status,
|
||||
result,
|
||||
|
||||
@@ -17,6 +17,7 @@ use wiremock::matchers::path;
|
||||
use wiremock::matchers::path_regex;
|
||||
|
||||
const CONNECTOR_ID: &str = "calendar";
|
||||
pub const LINK_ID: &str = "link_calendar";
|
||||
const CONNECTOR_NAME: &str = "Calendar";
|
||||
const DISCOVERABLE_CALENDAR_ID: &str = "connector_2128aebfecb84f64a069897515042a44";
|
||||
const DISCOVERABLE_GMAIL_ID: &str = "connector_68df038e0ba48191908c8434991bbac2";
|
||||
@@ -352,6 +353,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"openai/outputTemplate": CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_URI,
|
||||
@@ -378,6 +380,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"_codex_apps": {
|
||||
@@ -410,6 +413,7 @@ impl Respond for CodexAppsJsonRpcResponder {
|
||||
},
|
||||
"_meta": {
|
||||
"connector_id": CONNECTOR_ID,
|
||||
"link_id": LINK_ID,
|
||||
"connector_name": self.connector_name.clone(),
|
||||
"connector_description": self.connector_description.clone(),
|
||||
"openai/fileParams": ["file"],
|
||||
|
||||
@@ -1337,7 +1337,9 @@ async fn stdio_image_responses_round_trip() -> anyhow::Result<()> {
|
||||
tool: "image".to_string(),
|
||||
arguments: Some(json!({})),
|
||||
},
|
||||
connector_id: None,
|
||||
mcp_app_resource_uri: None,
|
||||
link_id: None,
|
||||
plugin_id: None,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -25,6 +25,7 @@ use core_test_support::apps_test_server::CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_
|
||||
use core_test_support::apps_test_server::CALENDAR_CREATE_EVENT_RESOURCE_URI;
|
||||
use core_test_support::apps_test_server::DIRECT_CALENDAR_CREATE_EVENT_TOOL as CALENDAR_CREATE_TOOL;
|
||||
use core_test_support::apps_test_server::DIRECT_CALENDAR_LIST_EVENTS_TOOL as CALENDAR_LIST_TOOL;
|
||||
use core_test_support::apps_test_server::LINK_ID;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_APP_ONLY_TOOL;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_CREATE_TOOL;
|
||||
use core_test_support::apps_test_server::SEARCH_CALENDAR_LIST_TOOL;
|
||||
@@ -559,10 +560,12 @@ async fn tool_search_returns_deferred_tools_without_follow_up_tool_injection() -
|
||||
unreachable!("event guard guarantees McpToolCallEnd");
|
||||
};
|
||||
assert_eq!(end.call_id, "calendar-call-1");
|
||||
assert_eq!(end.connector_id.as_deref(), Some("calendar"));
|
||||
assert_eq!(
|
||||
end.mcp_app_resource_uri.as_deref(),
|
||||
Some(CALENDAR_CREATE_EVENT_MCP_APP_RESOURCE_URI)
|
||||
);
|
||||
assert_eq!(end.link_id.as_deref(), Some(LINK_ID));
|
||||
assert_eq!(
|
||||
end.invocation,
|
||||
McpInvocation {
|
||||
|
||||
Reference in New Issue
Block a user