Store generated image items as attachment references (#54398)

## What changed

- Upload generated images to the attachment store and expose `fileId` in image-generation items when available, with inline `result` fallback on upload or decoding failure.
- Preserve file references through legacy events, persisted rollouts, thread history, and task output summaries. Keep model-facing image preparation separate.
- Add attachment request tags and mark generated-image uploads with `usage=image_gen`, preserving the thread's ephemeral setting.
- Update public schemas and SDK types to accept either image representation, retain the Python `ImageGenerationThreadItem` alias, and prefer `fileId` when reading records containing both fields.

## Testing

Add coverage for file-backed generation and rollout persistence, legacy history replay, inline and transitional serialization, task output visibility, and Python SDK alias compatibility.

GitOrigin-RevId: f7a2bb5707e2f277348a547a988bc33c8e96d891
This commit is contained in:
Krish Chainani
2026-10-15 19:51:22 +00:00
committed by copyberry
parent 1ef30bcbe7
commit aabf13307a
64 changed files with 1229 additions and 125 deletions
+3
View File
@@ -1,3 +1,5 @@
use std::collections::HashMap;
use crate::config::ManagedFeatures;
use crate::context::ContextualUserFragment;
use crate::context::ImageResizeNotice;
@@ -370,6 +372,7 @@ async fn prepare_image(
thread_id: origin.thread_id.to_owned(),
ephemeral: origin.ephemeral,
file_name: None,
tags: HashMap::new(),
data: prepared.encoded.bytes.to_vec(),
};
*image = match image_store.upload(request).await {
@@ -212,6 +212,8 @@ async fn to_extension_call<'a>(
session: Arc::downgrade(&invocation.session),
turn: Arc::downgrade(&invocation.turn),
}),
attachment_store: Arc::clone(&invocation.session.services.image_store),
ephemeral: invocation.turn.config.ephemeral,
environments,
payload: invocation.payload.clone(),
}
@@ -222,6 +224,7 @@ mod tests {
use std::sync::Arc;
use codex_extension_items::ExtensionItem;
use codex_extension_items::image_generation::GeneratedImageRef;
use codex_extension_items::image_generation::ImageGenerationItem;
use codex_extension_items::web_search::WebSearchItem;
use codex_protocol::items::TurnItem;
@@ -567,7 +570,9 @@ mod tests {
id: "call-image".to_string(),
status: "in_progress".to_string(),
revised_prompt: None,
result: String::new(),
image: GeneratedImageRef::Inline {
result: String::new(),
},
transparent_background: None,
failure: None,
saved_path: None,
@@ -578,7 +583,9 @@ mod tests {
id: "call-image".to_string(),
status: "completed".to_string(),
revised_prompt: Some("A tiny blue square".to_string()),
result: "cG5n".to_string(),
image: GeneratedImageRef::Inline {
result: "cG5n".to_string(),
},
transparent_background: Some(true),
failure: None,
saved_path: Some(expected_path.clone()),
@@ -603,7 +610,9 @@ mod tests {
call_id: "call-image".to_string(),
status: "completed".to_string(),
revised_prompt: Some("A tiny blue square".to_string()),
result: "cG5n".to_string(),
image: GeneratedImageRef::Inline {
result: "cG5n".to_string(),
},
transparent_background: Some(true),
failure: None,
saved_path: Some(expected_path.clone()),