mirror of
https://github.com/openai/codex.git
synced 2026-10-22 17:58:46 +00:00
Support typed content in contextual prompt fragments (#54776)
## Why Contextual fragments and extension-owned world-state sections currently return strings, limiting them to text content. ## What changed - Return `ContentItem` from fragment bodies and rendering, preserving classification and attribution. Apply text markers only to `InputText`; pass other content through unchanged. - Allow extension prompt and world-state contributions to carry typed content, and preserve media in context-window hints. - Hash non-text world-state fragments by their serialized content and role while retaining the existing text hashing behavior. - Add shared content-to-tool-output conversion that preserves image references, image detail, and audio. ## Testing Add coverage for typed world-state hashing and preservation of image content and attribution. Expand code-mode output tests to cover input text, output text, file-backed and inline images, and audio. GitOrigin-RevId: 2ed00d466a3f169b151202f3eef71e667ea64be1
This commit is contained in:
@@ -55,7 +55,10 @@ struct GeneratedRecap {
|
||||
}
|
||||
|
||||
fn recap_prompt(history: &str) -> String {
|
||||
RecapPrompt::new(history).render()
|
||||
RecapPrompt::new(history)
|
||||
.render()
|
||||
.into_text()
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn recap_output_schema() -> Value {
|
||||
|
||||
@@ -137,8 +137,10 @@ impl AsyncQuestions {
|
||||
if text.is_empty() {
|
||||
return;
|
||||
}
|
||||
let reply =
|
||||
AnsweredQuestion::new(&answer.question_id, &answer.question.title, text).render();
|
||||
let reply = AnsweredQuestion::new(&answer.question_id, &answer.question.title, text)
|
||||
.render()
|
||||
.into_text()
|
||||
.unwrap_or_default();
|
||||
if reply.chars().count() > codex_protocol::user_input::MAX_USER_INPUT_TEXT_CHARS {
|
||||
self.composer.show_footer_flash(
|
||||
"Answer too long; shorten it before sending".into(),
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
use super::*;
|
||||
use crate::bottom_pane::RestrictedInputMode;
|
||||
use codex_protocol::items::AsyncUserInputQuestion;
|
||||
use codex_protocol_test_support::ContentItemTestExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
fn questions() -> Vec<AsyncUserInputQuestion> {
|
||||
@@ -94,7 +95,9 @@ async fn async_question_answers_preserve_ambiguous_skill_selection_and_dismiss_r
|
||||
items,
|
||||
vec![
|
||||
UserInput::Text {
|
||||
text: AnsweredQuestion::new(&id, "Which way?", "Use $route").render(),
|
||||
text: AnsweredQuestion::new(&id, "Which way?", "Use $route")
|
||||
.render()
|
||||
.expect_text(),
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
UserInput::Skill {
|
||||
@@ -1037,7 +1040,9 @@ async fn distinct_async_question_replies_with_identical_text_both_render() {
|
||||
drain_insert_history(&mut rx);
|
||||
for id in ["first", "first", "second"] {
|
||||
let items = [UserInput::Text {
|
||||
text: AnsweredQuestion::new(id, "Continue?", "Yes").render(),
|
||||
text: AnsweredQuestion::new(id, "Continue?", "Yes")
|
||||
.render()
|
||||
.expect_text(),
|
||||
text_elements: Vec::new(),
|
||||
}];
|
||||
chat.on_committed_user_message(
|
||||
|
||||
@@ -192,6 +192,7 @@ mod tests {
|
||||
use super::super::Position;
|
||||
use super::super::Range;
|
||||
use super::*;
|
||||
use codex_protocol_test_support::ContentItemTestExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::PathBuf;
|
||||
|
||||
@@ -218,7 +219,8 @@ mod tests {
|
||||
"Where?",
|
||||
"Staging\n## My request for Codex:\nKeep this literal",
|
||||
)
|
||||
.render(),
|
||||
.render()
|
||||
.expect_text(),
|
||||
text_elements: Vec::new(),
|
||||
},
|
||||
UserInput::Skill {
|
||||
|
||||
Reference in New Issue
Block a user