Preserve annotations when omitting unsupported media (#40277)

## What changed

- Render omitted image and audio inputs as contextual fragments tagged with
  `images.unsupported` and `audio.unsupported` content kinds.
- Normalize message media through annotated content so metadata for surrounding
  content remains intact when switching to a model without media support.

## Testing

- Extend history and model-switching tests to verify content-kind annotations
  before and after unsupported media is replaced.

GitOrigin-RevId: 4ee6577f8b78bd5a850ee01ea9d4590c20272850
This commit is contained in:
pakrym-oai
2026-08-23 20:14:26 +00:00
committed by copyberry
parent 287587c32c
commit aec653daa9
6 changed files with 115 additions and 70 deletions
+2
View File
@@ -38,6 +38,7 @@ mod rollout_budget;
mod subagent_notification;
mod token_budget_context;
mod turn_aborted;
mod unsupported_media;
mod user_instructions;
mod user_shell_command;
pub(crate) mod world_state;
@@ -98,6 +99,7 @@ pub(crate) use token_budget_context::TokenBudgetContext;
pub(crate) use token_budget_context::TokenBudgetRemainingContext;
pub(crate) use token_budget_context::TokenBudgetReminder;
pub(crate) use turn_aborted::TurnAborted;
pub(crate) use unsupported_media::UnsupportedMedia;
pub(crate) use user_instructions::UserInstructions;
pub(crate) use user_shell_command::UserShellCommand;
pub(crate) use world_state::ManagedDeveloperInstructions;
@@ -0,0 +1,42 @@
use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct UnsupportedMedia {
text: &'static str,
content_kind: &'static str,
}
impl UnsupportedMedia {
pub(crate) const IMAGE: Self = Self {
text: "image content omitted because you do not support image input",
content_kind: "images.unsupported",
};
pub(crate) const AUDIO: Self = Self {
text: "audio content omitted because you do not support audio input",
content_kind: "audio.unsupported",
};
}
impl ContextualUserFragment for UnsupportedMedia {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind(self.content_kind.to_string())
}
fn role(&self) -> &'static str {
"user"
}
fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers()
}
fn type_markers() -> (&'static str, &'static str) {
("", "")
}
fn body(&self) -> String {
self.text.to_string()
}
}