mirror of
https://github.com/openai/codex.git
synced 2026-10-23 18:08:45 +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:
@@ -11,7 +11,7 @@ use codex_protocol::models::ContentItemMetadata;
|
||||
pub enum PromptSlot {
|
||||
DeveloperPolicy,
|
||||
DeveloperCapabilities,
|
||||
/// Text inside the context-window message, supplied by `contribute_thread_context`.
|
||||
/// Content inside the context-window message, supplied by `contribute_thread_context`.
|
||||
ContextWindow,
|
||||
}
|
||||
|
||||
@@ -22,16 +22,12 @@ pub struct PromptFragment {
|
||||
}
|
||||
|
||||
impl PromptFragment {
|
||||
/// Places a contextual fragment in the prompt, preserving its text, kind, and source.
|
||||
/// Places a contextual fragment in the prompt, preserving its content, kind, and source.
|
||||
/// The slot determines placement within the developer message, regardless of its original role.
|
||||
pub fn from_fragment(slot: PromptSlot, fragment: &impl ContextualUserFragment) -> Self {
|
||||
Self {
|
||||
slot,
|
||||
content: AnnotatedContent::text(
|
||||
fragment.render(),
|
||||
fragment.content_kind(),
|
||||
fragment.content_metadata(),
|
||||
),
|
||||
content: fragment.render_fragment().into_parts().1,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -75,15 +71,12 @@ impl PromptFragment {
|
||||
self.slot
|
||||
}
|
||||
|
||||
/// Returns the model-visible text.
|
||||
pub fn text(&self) -> &str {
|
||||
let ContentItem::InputText { text } = self.content.content() else {
|
||||
unreachable!("prompt fragments contain text");
|
||||
};
|
||||
text
|
||||
/// Returns the model-visible content.
|
||||
pub fn content(&self) -> &ContentItem {
|
||||
self.content.content()
|
||||
}
|
||||
|
||||
/// Returns the producer-owned classification of the model-visible text.
|
||||
/// Returns the producer-owned classification of the model-visible content.
|
||||
pub fn content_kind(&self) -> &ContentItemKind {
|
||||
self.content.kind()
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ use codex_exec_server_protocol::ExecutorCapabilityDiscoverySnapshot;
|
||||
use codex_exec_server_protocol::ExecutorCapabilityDiscoveryV2Snapshot;
|
||||
use codex_protocol::ThreadId;
|
||||
use codex_protocol::capabilities::SelectedCapabilityRoot;
|
||||
use codex_protocol::models::ContentItem;
|
||||
use codex_protocol::models::ContentItemMetadata;
|
||||
use codex_protocol::openai_models::ModelInfo;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
@@ -45,12 +46,15 @@ pub enum PreviousWorldStateSection<'a> {
|
||||
Known(&'a Value),
|
||||
}
|
||||
|
||||
/// Plain model-visible data rendered by an extension-owned World State section.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
/// Model-visible content rendered by an extension-owned World State section.
|
||||
/// Markers apply only to `InputText` bodies.
|
||||
/// The producer owns size bounds for the content; rendering does not truncate it.
|
||||
/// Non-text user-role bodies are currently classified as ordinary user media.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct RenderedWorldStateFragment {
|
||||
role: &'static str,
|
||||
markers: (&'static str, &'static str),
|
||||
body: String,
|
||||
body: ContentItem,
|
||||
metadata: ContentItemMetadata,
|
||||
}
|
||||
|
||||
@@ -58,12 +62,12 @@ impl RenderedWorldStateFragment {
|
||||
pub fn new(
|
||||
role: &'static str,
|
||||
markers: (&'static str, &'static str),
|
||||
body: impl Into<String>,
|
||||
body: ContentItem,
|
||||
) -> Self {
|
||||
Self {
|
||||
role,
|
||||
markers,
|
||||
body: body.into(),
|
||||
body,
|
||||
metadata: ContentItemMetadata::harness(),
|
||||
}
|
||||
}
|
||||
@@ -86,7 +90,7 @@ impl RenderedWorldStateFragment {
|
||||
self.markers
|
||||
}
|
||||
|
||||
pub fn body(&self) -> &str {
|
||||
pub fn body(&self) -> &ContentItem {
|
||||
&self.body
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,8 +22,10 @@ pub use capabilities::ResponseItemInjector;
|
||||
pub use codex_context_fragments::ContextualUserFragment;
|
||||
pub use codex_mcp::McpProtocolMode;
|
||||
pub use codex_mcp::ToolInfo as McpToolInfo;
|
||||
pub use codex_protocol::models::ContentItem;
|
||||
pub use codex_protocol::models::ContentItemKind;
|
||||
pub use codex_protocol::models::ResponseItem;
|
||||
pub use codex_protocol::models::input_text;
|
||||
pub use codex_protocol::security_risk::SecurityRiskScore;
|
||||
pub use codex_tools::ConversationHistory;
|
||||
pub use codex_tools::ExtensionTurnItem;
|
||||
|
||||
Reference in New Issue
Block a user