Expose image generation usage-limit failures (#38024)

## What changed

- Add structured `usageLimitExceeded` metadata to failed image-generation
  items, including the image limit ID and optional reset timestamp.
- Preserve the failure metadata in completion events, app-server thread
  history, thread reads and resumes, and migrated legacy rollouts.
- Export the new failure type in the generated JSON and TypeScript schemas.

## Testing

- Cover usage-limit responses through item completion, persistence, and thread
  resume.
- Verify legacy rollout migration retains image-generation failure metadata.

GitOrigin-RevId: 91c31a2a47456b6b916ee03002ff314b05946dd4
This commit is contained in:
arun eswara authored and copyberry committed 2026-08-11 15:40:52 +00:00
1 parent 4c5fc230a9
commit edcec13372
41 files changed
+1104 -18

No files matched your search

@@ -863,6 +863,7 @@ impl ThreadHistoryBuilder {
revised_prompt: None,
result: String::new(),
transparent_background: None,
failure: None,
saved_path: None,
});
self.upsert_item_in_current_turn(item);
@@ -875,6 +876,7 @@ impl ThreadHistoryBuilder {
revised_prompt: payload.revised_prompt.clone(),
result: payload.result.clone(),
transparent_background: payload.transparent_background,
failure: payload.failure.clone(),
saved_path: payload.saved_path.clone(),
});
self.upsert_item_in_current_turn(item);
@@ -2079,6 +2081,7 @@ mod tests {
revised_prompt: Some("A blue square".to_string()),
result: "cG5n".to_string(),
transparent_background: Some(true),
failure: None,
saved_path: Some(saved_path.clone()),
},
)),
@@ -2110,6 +2113,7 @@ mod tests {
revised_prompt: Some("A blue square".to_string()),
result: "cG5n".to_string(),
transparent_background: Some(true),
failure: None,
saved_path: Some(saved_path),
})]
);
@@ -2373,6 +2377,12 @@ mod tests {
revised_prompt: Some("final prompt".into()),
result: "Zm9v".into(),
transparent_background: Some(true),
failure: Some(
codex_extension_items::image_generation::ImageGenerationFailure::UsageLimitExceeded {
limit_id: "image_gen".into(),
resets_at: Some(1_786_150_800),
},
),
saved_path: Some(test_path_buf("/tmp/ig_123.png").abs()),
})),
RolloutItem::EventMsg(EventMsg::TurnComplete(TurnCompleteEvent {
@@ -2413,6 +2423,12 @@ mod tests {
revised_prompt: Some("final prompt".into()),
result: "Zm9v".into(),
transparent_background: Some(true),
failure: Some(
codex_extension_items::image_generation::ImageGenerationFailure::UsageLimitExceeded {
limit_id: "image_gen".into(),
resets_at: Some(1_786_150_800),
},
),
saved_path: Some(test_path_buf("/tmp/ig_123.png").abs()),
}),
],
@@ -15,6 +15,7 @@ use crate::protocol::item_builders::convert_patch_changes;
use crate::protocol::item_builders::review_output_text;
use codex_experimental_api_macros::ExperimentalApi;
use codex_extension_items::ExtensionItem;
pub use codex_extension_items::image_generation::ImageGenerationFailure;
pub use codex_extension_items::image_generation::ImageGenerationItem;
pub use codex_extension_items::sleep::SleepItem;
pub use codex_extension_items::web_search::WebSearchAction;
@@ -929,6 +930,7 @@ impl From<CoreTurnItem> for ThreadItem {
revised_prompt: image.revised_prompt,
result: image.result,
transparent_background: None,
failure: None,
saved_path: image.saved_path,
})
}