mirror of
https://github.com/openai/codex.git
synced 2026-10-29 00:06:55 +00:00
Add audio variants to user input protocols (#33923)
## What changed - Add remote and local audio variants to core and app-server user inputs, including generated JSON and TypeScript schemas. - Preserve audio fields when converting app-server inputs and response content into thread items. - Keep unsupported audio out of model requests, TUI rendering, text extraction, and truncated tool output, using explicit text placeholders where audio is submitted as a model input. ## Testing - Cover app-server media conversion, unsupported-input placeholders, TUI omission, and tool-output truncation. GitOrigin-RevId: 16152bf3af674575ce569764a8b472e032e7569d
This commit is contained in:
@@ -750,6 +750,10 @@ pub(crate) fn render_input_preview(input: &[UserInput]) -> String {
|
||||
UserInput::LocalImage { path, .. } => {
|
||||
format!("[local_image:{}]", path.display())
|
||||
}
|
||||
UserInput::Audio { .. } => "[audio]".to_string(),
|
||||
UserInput::LocalAudio { path } => {
|
||||
format!("[local_audio:{}]", path.display())
|
||||
}
|
||||
UserInput::Skill { name, path, .. } => {
|
||||
format!("[skill:${name}]({})", path.display())
|
||||
}
|
||||
|
||||
@@ -252,7 +252,7 @@ fn has_subagent_notification(history_items: &[ResponseItem]) -> bool {
|
||||
ContentItem::InputText { text } | ContentItem::OutputText { text } => {
|
||||
SubagentNotification::matches_text(text)
|
||||
}
|
||||
ContentItem::InputImage { .. } => false,
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => false,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -267,7 +267,7 @@ fn history_contains_text(history_items: &[ResponseItem], needle: &str) -> bool {
|
||||
ContentItem::InputText { text } | ContentItem::OutputText { text } => {
|
||||
text.contains(needle)
|
||||
}
|
||||
ContentItem::InputImage { .. } => false,
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => false,
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -290,7 +290,9 @@ fn history_contains_assistant_inter_agent_communication(
|
||||
.as_ref()
|
||||
== Some(expected)
|
||||
}
|
||||
ContentItem::InputText { .. } | ContentItem::InputImage { .. } => false,
|
||||
ContentItem::InputText { .. }
|
||||
| ContentItem::InputImage { .. }
|
||||
| ContentItem::InputAudio { .. } => false,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -484,7 +484,7 @@ pub fn content_items_to_text(content: &[ContentItem]) -> Option<String> {
|
||||
pieces.push(text.as_str());
|
||||
}
|
||||
}
|
||||
ContentItem::InputImage { .. } => {}
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => {}
|
||||
}
|
||||
}
|
||||
if pieces.is_empty() {
|
||||
|
||||
@@ -516,7 +516,7 @@ fn message_text_token_count(item: &ResponseItem) -> usize {
|
||||
ContentItem::InputText { text } | ContentItem::OutputText { text } => {
|
||||
approx_token_count(text)
|
||||
}
|
||||
ContentItem::InputImage { .. } => 0,
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => 0,
|
||||
})
|
||||
.sum()
|
||||
}
|
||||
@@ -556,7 +556,9 @@ fn truncate_message_text_to_token_budget(
|
||||
truncated_content.push(content_item);
|
||||
}
|
||||
}
|
||||
ContentItem::InputImage { .. } => truncated_content.push(content_item),
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => {
|
||||
truncated_content.push(content_item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,11 @@ fn parse_user_message(message: &[ContentItem]) -> Option<UserMessageItem> {
|
||||
detail: *detail,
|
||||
});
|
||||
}
|
||||
ContentItem::InputAudio { audio_url } => {
|
||||
content.push(UserInput::Audio {
|
||||
audio_url: audio_url.clone(),
|
||||
});
|
||||
}
|
||||
ContentItem::OutputText { text } => {
|
||||
warn!("Output text in user message: {}", text);
|
||||
}
|
||||
|
||||
@@ -345,7 +345,7 @@ fn response_item_contains_message_text(item: &ResponseItem, needle: &str) -> boo
|
||||
};
|
||||
content.iter().any(|item| match item {
|
||||
ContentItem::InputText { text } | ContentItem::OutputText { text } => text.contains(needle),
|
||||
ContentItem::InputImage { .. } => false,
|
||||
ContentItem::InputImage { .. } | ContentItem::InputAudio { .. } => false,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -844,7 +844,9 @@ mod tests {
|
||||
.iter()
|
||||
.map(|item| match item {
|
||||
ContentItem::InputText { text } => text.as_str(),
|
||||
ContentItem::InputImage { .. } | ContentItem::OutputText { .. } => {
|
||||
ContentItem::InputImage { .. }
|
||||
| ContentItem::InputAudio { .. }
|
||||
| ContentItem::OutputText { .. } => {
|
||||
panic!("expected input text content, got {item:?}")
|
||||
}
|
||||
})
|
||||
|
||||
@@ -559,10 +559,14 @@ fn create_collab_input_items_schema() -> JsonSchema {
|
||||
"image_url".to_string(),
|
||||
JsonSchema::string(Some("Image URL when type is image.".to_string())),
|
||||
),
|
||||
(
|
||||
"audio_url".to_string(),
|
||||
JsonSchema::string(Some("Audio URL when type is audio.".to_string())),
|
||||
),
|
||||
(
|
||||
"path".to_string(),
|
||||
JsonSchema::string(Some(
|
||||
"Path when type is local_image/skill, or structured mention target such as app://<connector-id> or plugin://<plugin-name>@<marketplace-name> when type is mention."
|
||||
"Path when type is local_image/local_audio/skill, or structured mention target such as app://<connector-id> or plugin://<plugin-name>@<marketplace-name> when type is mention."
|
||||
.to_string(),
|
||||
)),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user