Support original-detail metadata on MCP image outputs (#17714)

## Summary
- honor `_meta["codex/imageDetail"] == "original"` on MCP image content
and map it to `detail: "original"` where supported
- strip that detail back out when the active model does not support
original-detail image inputs
- update code-mode `image(...)` to accept individual MCP image blocks
- teach `js_repl` / `codex.emitImage(...)` to preserve the same hint
from raw MCP image outputs
- document the new `_meta` contract and add generic RMCP-backed coverage
across protocol, core, code-mode, and js_repl paths
This commit is contained in:
Curtis 'Fjord' Hawthorne
2026-04-15 14:43:33 -07:00
committed by GitHub
parent 17d94bd1e3
commit 9e2fc31854
20 changed files with 905 additions and 368 deletions
+18
View File
@@ -1,3 +1,4 @@
use codex_protocol::models::FunctionCallOutputContentItem;
use codex_protocol::models::ImageDetail;
use codex_protocol::openai_models::ModelInfo;
@@ -17,6 +18,23 @@ pub fn normalize_output_image_detail(
}
}
pub fn sanitize_original_image_detail(
can_request_original_image_detail: bool,
items: &mut [FunctionCallOutputContentItem],
) {
if can_request_original_image_detail {
return;
}
for item in items {
if let FunctionCallOutputContentItem::InputImage { detail, .. } = item
&& matches!(detail, Some(ImageDetail::Original))
{
*detail = None;
}
}
}
#[cfg(test)]
#[path = "image_detail_tests.rs"]
mod tests;
+37
View File
@@ -1,4 +1,5 @@
use super::*;
use codex_protocol::models::FunctionCallOutputContentItem;
use codex_protocol::models::ImageDetail;
use codex_protocol::openai_models::ModelInfo;
use pretty_assertions::assert_eq;
@@ -73,3 +74,39 @@ fn unsupported_non_original_detail_is_dropped() {
None
);
}
#[test]
fn sanitize_original_drops_original_without_support() {
let mut items = vec![
FunctionCallOutputContentItem::InputText {
text: "header".to_string(),
},
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,AAA".to_string(),
detail: Some(ImageDetail::Original),
},
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,BBB".to_string(),
detail: Some(ImageDetail::Low),
},
];
sanitize_original_image_detail(/*can_request_original_image_detail*/ false, &mut items);
assert_eq!(
items,
vec![
FunctionCallOutputContentItem::InputText {
text: "header".to_string(),
},
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,AAA".to_string(),
detail: None,
},
FunctionCallOutputContentItem::InputImage {
image_url: "data:image/png;base64,BBB".to_string(),
detail: Some(ImageDetail::Low),
},
]
);
}
+1
View File
@@ -53,6 +53,7 @@ pub use codex_protocol::ToolName;
pub use dynamic_tool::parse_dynamic_tool;
pub use image_detail::can_request_original_image_detail;
pub use image_detail::normalize_output_image_detail;
pub use image_detail::sanitize_original_image_detail;
pub use js_repl_tool::create_js_repl_reset_tool;
pub use js_repl_tool::create_js_repl_tool;
pub use json_schema::AdditionalProperties;