mirror of
https://github.com/openai/codex.git
synced 2026-05-28 15:00:16 +00:00
[codex] preserve MCP result meta in McpToolCallItemResult (#22946)
## Summary https://openai.slack.com/archives/C0ARA9UAQEA/p1778890981647319?thread_ts=1778888537.934319&cid=C0ARA9UAQEA - Add `_meta` to exec JSONL MCP tool call result events. - Copy MCP result metadata through the JSONL event conversion. - Add a focused test that verifies `_meta` is serialized as `_meta` and not `meta`. ## Verification https://www.notion.so/openai/Miaolin-0516-_meta-population-debug-3628e50b62b08074b365e0ce1ffb8f74
This commit is contained in:
@@ -223,6 +223,7 @@ impl EventProcessorWithJsonOutput {
|
||||
arguments,
|
||||
result: result.map(|result| McpToolCallItemResult {
|
||||
content: result.content,
|
||||
meta: result.meta,
|
||||
structured_content: result.structured_content,
|
||||
}),
|
||||
error: error.map(|error| McpToolCallItemError {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use super::*;
|
||||
use pretty_assertions::assert_eq;
|
||||
use serde_json::json;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
@@ -57,3 +58,53 @@ fn failed_turn_does_not_overwrite_output_last_message_file() {
|
||||
"keep existing contents"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn mcp_tool_call_result_preserves_meta_in_jsonl_event() {
|
||||
let mut processor = EventProcessorWithJsonOutput::new(/*last_message_path*/ None);
|
||||
|
||||
let collected = processor.collect_thread_events(ServerNotification::ItemCompleted(
|
||||
codex_app_server_protocol::ItemCompletedNotification {
|
||||
item: ThreadItem::McpToolCall {
|
||||
id: "mcp-1".to_string(),
|
||||
server: "search service".to_string(),
|
||||
tool: "web_run".to_string(),
|
||||
status: McpToolCallStatus::Completed,
|
||||
arguments: json!({"search_query": [{"q": "OpenAI Codex CLI documentation"}]}),
|
||||
mcp_app_resource_uri: None,
|
||||
result: Some(Box::new(codex_app_server_protocol::McpToolCallResult {
|
||||
content: vec![json!({"type": "text", "text": "search result"})],
|
||||
structured_content: None,
|
||||
meta: Some(json!({"raw_messages": [{"ref_id": "turn0search0"}]})),
|
||||
})),
|
||||
error: None,
|
||||
duration_ms: Some(42),
|
||||
},
|
||||
thread_id: "thread-1".to_string(),
|
||||
turn_id: "turn-1".to_string(),
|
||||
completed_at_ms: 0,
|
||||
},
|
||||
));
|
||||
|
||||
assert_eq!(collected.status, CodexStatus::Running);
|
||||
assert_eq!(collected.events.len(), 1);
|
||||
|
||||
let ThreadEvent::ItemCompleted(ItemCompletedEvent { item }) = &collected.events[0] else {
|
||||
panic!("expected item.completed event");
|
||||
};
|
||||
let ThreadItemDetails::McpToolCall(item) = &item.details else {
|
||||
panic!("expected MCP tool call item");
|
||||
};
|
||||
let result = item.result.as_ref().expect("expected MCP tool result");
|
||||
assert_eq!(
|
||||
result.meta,
|
||||
Some(json!({"raw_messages": [{"ref_id": "turn0search0"}]}))
|
||||
);
|
||||
|
||||
let serialized = serde_json::to_value(&collected.events[0]).expect("serialize event");
|
||||
assert_eq!(
|
||||
serialized["item"]["result"]["_meta"],
|
||||
json!({"raw_messages": [{"ref_id": "turn0search0"}]})
|
||||
);
|
||||
assert!(serialized["item"]["result"].get("meta").is_none());
|
||||
}
|
||||
|
||||
@@ -266,6 +266,9 @@ pub struct McpToolCallItemResult {
|
||||
// representations). Using `JsonValue` keeps the payload wire-shaped and
|
||||
// easy to export.
|
||||
pub content: Vec<JsonValue>,
|
||||
#[serde(rename = "_meta", skip_serializing_if = "Option::is_none")]
|
||||
#[ts(optional)]
|
||||
pub meta: Option<JsonValue>,
|
||||
pub structured_content: Option<JsonValue>,
|
||||
}
|
||||
|
||||
|
||||
@@ -540,6 +540,7 @@ fn mcp_tool_call_begin_and_end_emit_item_events() {
|
||||
arguments: json!({ "key": "value" }),
|
||||
result: Some(McpToolCallItemResult {
|
||||
content: Vec::new(),
|
||||
meta: None,
|
||||
structured_content: None,
|
||||
}),
|
||||
error: None,
|
||||
@@ -681,6 +682,7 @@ fn mcp_tool_call_defaults_arguments_and_preserves_structured_content() {
|
||||
"type": "text",
|
||||
"text": "done",
|
||||
})],
|
||||
meta: None,
|
||||
structured_content: Some(json!({ "status": "ok" })),
|
||||
}),
|
||||
error: None,
|
||||
|
||||
@@ -60,6 +60,7 @@ export type McpToolCallItem = {
|
||||
/** Result payload returned by the MCP server for successful calls. */
|
||||
result?: {
|
||||
content: McpContentBlock[];
|
||||
_meta?: unknown;
|
||||
structured_content: unknown;
|
||||
};
|
||||
/** Error message reported for failed calls. */
|
||||
|
||||
Reference in New Issue
Block a user