mirror of
https://github.com/openai/codex.git
synced 2026-10-19 17:28:46 +00:00
Require data URLs for code-mode image output (#33659)
## What changed - Accept image output from `image()` and `generatedImage()` only when its URL uses the `data:` scheme. - Preserve the dedicated error for remote HTTP URLs and report other malformed or unsupported image URLs as invalid image output. ## Testing - Add service-level coverage for rejecting invalid output from both image helpers. - Add an end-to-end code-mode test that verifies the tool call fails instead of returning an invalid image item. GitOrigin-RevId: beaf8c8830574150e8166b6ff5daf7f6dc4dc0a1
This commit is contained in:
@@ -6,6 +6,8 @@ use codex_code_mode_protocol::ImageDetail;
|
||||
|
||||
const IMAGE_HELPER_EXPECTS_MESSAGE: &str = "image expects a non-empty image URL string, an object with image_url and optional detail, or a raw MCP image block";
|
||||
const REMOTE_IMAGE_URL_ERROR: &str = "Tool call failed: remote image URLs are not supported in tool outputs. Pass a base64 data URI instead";
|
||||
const INVALID_IMAGE_URL_ERROR: &str =
|
||||
"Tool call failed: invalid image output. Pass a base64 data URI instead";
|
||||
const CODEX_IMAGE_DETAIL_META_KEY: &str = "codex/imageDetail";
|
||||
|
||||
pub(super) fn serialize_output_text(
|
||||
@@ -59,10 +61,15 @@ pub(super) fn normalize_output_image(
|
||||
if image_url.is_empty() {
|
||||
return Err(IMAGE_HELPER_EXPECTS_MESSAGE.to_string());
|
||||
}
|
||||
let lower = image_url.to_ascii_lowercase();
|
||||
if lower.starts_with("http://") || lower.starts_with("https://") {
|
||||
let Some((scheme, _)) = image_url.split_once(':') else {
|
||||
return Err(INVALID_IMAGE_URL_ERROR.to_string());
|
||||
};
|
||||
if scheme.eq_ignore_ascii_case("http") || scheme.eq_ignore_ascii_case("https") {
|
||||
return Err(REMOTE_IMAGE_URL_ERROR.to_string());
|
||||
}
|
||||
if !scheme.eq_ignore_ascii_case("data") {
|
||||
return Err(INVALID_IMAGE_URL_ERROR.to_string());
|
||||
}
|
||||
|
||||
let detail = detail_override.or(detail);
|
||||
let detail = match detail {
|
||||
|
||||
@@ -873,6 +873,40 @@ async fn image_helpers_reject_remote_urls() {
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn image_helpers_reject_invalid_image_outputs() {
|
||||
let image_url =
|
||||
"Error executing tool exec: Expected at least one message to convert to CallToolResult";
|
||||
for source in [
|
||||
format!("image({image_url:?}, \"original\");"),
|
||||
format!("generatedImage({{ image_url: {image_url:?} }});"),
|
||||
] {
|
||||
let service = InProcessCodeModeSession::new();
|
||||
|
||||
let response = execute(
|
||||
&service,
|
||||
ExecuteRequest {
|
||||
source,
|
||||
yield_time_ms: None,
|
||||
..execute_request("")
|
||||
},
|
||||
)
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
response,
|
||||
RuntimeResponse::Result {
|
||||
cell_id: cell_id("1"),
|
||||
content_items: Vec::new(),
|
||||
error_text: Some(
|
||||
"Tool call failed: invalid image output. Pass a base64 data URI instead"
|
||||
.to_string(),
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn image_helper_rejects_unsupported_detail() {
|
||||
let service = InProcessCodeModeSession::new();
|
||||
|
||||
Reference in New Issue
Block a user