Classify contextual fragments with content kinds (#40180)

## What changed

- Require each `ContextualUserFragment` to provide a stable `<feature>.<name>`
  `ContentItemKind`.
- Add `AnnotatedContent` and `RenderedFragment` so rendered text, its role, and
  its classification can travel together to API boundaries.
- Derive extension-owned world-state classifications from the extension ID and
  keep the skills catalog classification with its fragment implementation.

## Testing

- Verify that an extension-owned world-state section renders with an
  `<extension-id>.instructions` content kind.

GitOrigin-RevId: e46b74a0bb41e0b6112667c9d36bc9e7f2714451
This commit is contained in:
pakrym-oai authored and copyberry committed 2026-08-23 03:44:21 +00:00
1 parent a1d4aea265
commit 422239eb4b
48 files changed
+375 -15

No files matched your search

@@ -1,3 +1,4 @@
use codex_protocol::models::ContentItemKind;
use codex_utils_string::truncate_middle_with_token_budget; use codex_utils_string::truncate_middle_with_token_budget;
use crate::ContextualUserFragment; use crate::ContextualUserFragment;
@@ -23,6 +24,10 @@ impl ContextualUserFragment for AdditionalContextUserFragment {
"user" "user"
} }
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.user_additional_context".to_string())
}
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers() Self::type_markers()
} }
@@ -69,6 +74,10 @@ impl ContextualUserFragment for AdditionalContextDeveloperFragment {
"developer" "developer"
} }
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.developer_additional_context".to_string())
}
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers() Self::type_markers()
} }
@@ -0,0 +1,36 @@
use codex_protocol::models::ContentItem;
use codex_protocol::models::ContentItemKind;
/// Model-visible content paired with its harness-owned classification.
#[derive(Clone, Debug, PartialEq)]
pub struct AnnotatedContent {
content: ContentItem,
kind: ContentItemKind,
}
impl AnnotatedContent {
/// Creates content and its classification together.
pub fn new(content: ContentItem, kind: ContentItemKind) -> Self {
Self { content, kind }
}
/// Creates model-visible input text and its classification together.
pub fn input_text(text: impl Into<String>, kind: ContentItemKind) -> Self {
Self::new(ContentItem::InputText { text: text.into() }, kind)
}
/// Returns the model-visible content.
pub fn content(&self) -> &ContentItem {
&self.content
}
/// Returns the classification associated with the content.
pub fn kind(&self) -> &ContentItemKind {
&self.kind
}
/// Separates the content from its classification at an API boundary.
pub fn into_parts(self) -> (ContentItem, ContentItemKind) {
(self.content, self.kind)
}
}
@@ -1,7 +1,33 @@
use crate::AnnotatedContent;
use codex_protocol::models::ContentItem; use codex_protocol::models::ContentItem;
use codex_protocol::models::ContentItemKind;
use codex_protocol::models::ResponseInputItem; use codex_protocol::models::ResponseInputItem;
use codex_protocol::models::ResponseItem; use codex_protocol::models::ResponseItem;
/// A rendered contextual fragment and the role that owns its annotated content.
#[derive(Clone, Debug, PartialEq)]
pub struct RenderedFragment {
role: &'static str,
content: AnnotatedContent,
}
impl RenderedFragment {
/// Returns the response role associated with this fragment.
pub fn role(&self) -> &'static str {
self.role
}
/// Returns this fragment's model-visible content and classification.
pub fn annotated_content(&self) -> &AnnotatedContent {
&self.content
}
/// Separates the role and annotated content at an API boundary.
pub fn into_parts(self) -> (&'static str, AnnotatedContent) {
(self.role, self.content)
}
}
/// Context payload that is injected as a message fragment. /// Context payload that is injected as a message fragment.
/// ///
/// Implementations own the response role and provide the exact fragment body. /// Implementations own the response role and provide the exact fragment body.
@@ -14,6 +40,9 @@ use codex_protocol::models::ResponseItem;
pub trait ContextualUserFragment { pub trait ContextualUserFragment {
fn role(&self) -> &'static str; fn role(&self) -> &'static str;
/// Returns a stable `<feature>.<name>` classification, using `generic` for shared fragments.
fn content_kind(&self) -> ContentItemKind;
/// Whether this fragment must be recorded as its own response item. /// Whether this fragment must be recorded as its own response item.
fn requires_separate_message(&self) -> bool { fn requires_separate_message(&self) -> bool {
false false
@@ -45,6 +74,14 @@ pub trait ContextualUserFragment {
format!("{start_marker}{body}{end_marker}") format!("{start_marker}{body}{end_marker}")
} }
/// Renders the role, model-visible content, and classification together.
fn render_fragment(&self) -> RenderedFragment {
RenderedFragment {
role: self.role(),
content: AnnotatedContent::input_text(self.render(), self.content_kind()),
}
}
fn into(self) -> ResponseItem fn into(self) -> ResponseItem
where where
Self: Sized, Self: Sized,
+3
View File
@@ -1,6 +1,9 @@
mod additional_context; mod additional_context;
mod annotated_content;
mod fragment; mod fragment;
pub use additional_context::AdditionalContextDeveloperFragment; pub use additional_context::AdditionalContextDeveloperFragment;
pub use additional_context::AdditionalContextUserFragment; pub use additional_context::AdditionalContextUserFragment;
pub use annotated_content::AnnotatedContent;
pub use fragment::ContextualUserFragment; pub use fragment::ContextualUserFragment;
pub use fragment::RenderedFragment;
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
pub(crate) const APPROVED_COMMAND_PREFIX_SAVED_MESSAGE_PREFIX: &str = pub(crate) const APPROVED_COMMAND_PREFIX_SAVED_MESSAGE_PREFIX: &str =
"Approved command prefix saved:"; "Approved command prefix saved:";
@@ -17,6 +18,10 @@ impl ApprovedCommandPrefixSaved {
} }
impl ContextualUserFragment for ApprovedCommandPrefixSaved { impl ContextualUserFragment for ApprovedCommandPrefixSaved {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("permissions.approved_command_prefix_saved".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -3,11 +3,16 @@ use codex_protocol::protocol::APPS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG; use codex_protocol::protocol::APPS_INSTRUCTIONS_OPEN_TAG;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct AppsInstructions; pub(crate) struct AppsInstructions;
impl ContextualUserFragment for AppsInstructions { impl ContextualUserFragment for AppsInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("apps.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -2,11 +2,16 @@ use codex_protocol::protocol::PLUGINS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::PLUGINS_INSTRUCTIONS_OPEN_TAG; use codex_protocol::protocol::PLUGINS_INSTRUCTIONS_OPEN_TAG;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct AvailablePluginsInstructions; pub(crate) struct AvailablePluginsInstructions;
impl ContextualUserFragment for AvailablePluginsInstructions { impl ContextualUserFragment for AvailablePluginsInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("plugins.usage_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -2,6 +2,7 @@ use chrono::DateTime;
use chrono::Utc; use chrono::Utc;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
pub(crate) struct CurrentTimeReminder { pub(crate) struct CurrentTimeReminder {
current_time: DateTime<Utc>, current_time: DateTime<Utc>,
@@ -20,6 +21,10 @@ impl CurrentTimeReminder {
} }
impl ContextualUserFragment for CurrentTimeReminder { impl ContextualUserFragment for CurrentTimeReminder {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("current_time.reminder".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -2,10 +2,15 @@ use codex_protocol::protocol::ENVIRONMENTS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::ENVIRONMENTS_INSTRUCTIONS_OPEN_TAG; use codex_protocol::protocol::ENVIRONMENTS_INSTRUCTIONS_OPEN_TAG;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
pub(crate) struct EnvironmentsInstructions; pub(crate) struct EnvironmentsInstructions;
impl ContextualUserFragment for EnvironmentsInstructions { impl ContextualUserFragment for EnvironmentsInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("environments.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,9 +1,14 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct GuardianFollowupReviewReminder; pub(crate) struct GuardianFollowupReviewReminder;
impl ContextualUserFragment for GuardianFollowupReviewReminder { impl ContextualUserFragment for GuardianFollowupReviewReminder {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("guardian.followup_review_reminder".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,9 +1,14 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct GuardianNodeReplPolicy; pub(crate) struct GuardianNodeReplPolicy;
impl ContextualUserFragment for GuardianNodeReplPolicy { impl ContextualUserFragment for GuardianNodeReplPolicy {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("guardian.node_repl_policy".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -8,6 +8,7 @@ use serde_json::json;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use crate::codex_thread::GuardianAuthorizationVersion; use crate::codex_thread::GuardianAuthorizationVersion;
use crate::guardian::guardian_truncate_text; use crate::guardian::guardian_truncate_text;
use codex_protocol::models::ContentItemKind;
const MAX_RETAINED_REVIEWS: usize = 8; const MAX_RETAINED_REVIEWS: usize = 8;
// Including markers, each rendered fragment stays below 1,000 approximate tokens. // Including markers, each rendered fragment stays below 1,000 approximate tokens.
@@ -108,6 +109,10 @@ pub struct GuardianReviewEvidenceFragment {
} }
impl ContextualUserFragment for GuardianReviewEvidenceFragment { impl ContextualUserFragment for GuardianReviewEvidenceFragment {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("guardian.review_evidence".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct HookAdditionalContext { pub(crate) struct HookAdditionalContext {
@@ -12,6 +13,10 @@ impl HookAdditionalContext {
} }
impl ContextualUserFragment for HookAdditionalContext { impl ContextualUserFragment for HookAdditionalContext {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("hooks.additional_context".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum ImageResizeNoticeSource { pub(crate) enum ImageResizeNoticeSource {
@@ -32,6 +33,10 @@ impl ImageResizeNotice {
} }
impl ContextualUserFragment for ImageResizeNotice { impl ContextualUserFragment for ImageResizeNotice {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("images.resize_notice".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,6 +1,7 @@
use codex_protocol::AgentPath; use codex_protocol::AgentPath;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct InterAgentCompletionMessage { pub(crate) struct InterAgentCompletionMessage {
@@ -20,6 +21,10 @@ impl InterAgentCompletionMessage {
} }
impl ContextualUserFragment for InterAgentCompletionMessage { impl ContextualUserFragment for InterAgentCompletionMessage {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.inter_agent_completion_message".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"assistant" "assistant"
} }
@@ -1,6 +1,7 @@
use codex_protocol::AgentPath; use codex_protocol::AgentPath;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, Copy, PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum InterAgentMessageType { pub(crate) enum InterAgentMessageType {
@@ -42,6 +43,10 @@ impl InterAgentMessage {
} }
impl ContextualUserFragment for InterAgentMessage { impl ContextualUserFragment for InterAgentMessage {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.inter_agent_message".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"assistant" "assistant"
} }
@@ -1,6 +1,7 @@
//! Hidden user-context fragment for extension-owned model steering. //! Hidden user-context fragment for extension-owned model steering.
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
use std::error::Error; use std::error::Error;
use std::fmt; use std::fmt;
@@ -76,6 +77,10 @@ impl InternalModelContextFragment {
} }
impl ContextualUserFragment for InternalModelContextFragment { impl ContextualUserFragment for InternalModelContextFragment {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.internal_model_context".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,10 +1,15 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
// This warning is not produced anymore but fragment definition is used to filter messaged from old sessions // This warning is not produced anymore but fragment definition is used to filter messaged from old sessions
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct LegacyApplyPatchExecCommandWarning; pub(crate) struct LegacyApplyPatchExecCommandWarning;
impl ContextualUserFragment for LegacyApplyPatchExecCommandWarning { impl ContextualUserFragment for LegacyApplyPatchExecCommandWarning {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("apply_patch.legacy_exec_command_warning".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,10 +1,15 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
// This warning is not produced anymore but fragment definition is used to filter messaged from old sessions // This warning is not produced anymore but fragment definition is used to filter messaged from old sessions
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct LegacyModelMismatchWarning; pub(crate) struct LegacyModelMismatchWarning;
impl ContextualUserFragment for LegacyModelMismatchWarning { impl ContextualUserFragment for LegacyModelMismatchWarning {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("model_switch.legacy_mismatch_warning".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,10 +1,15 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
// This warning is not produced anymore but fragment definition is used to filter messaged from old sessions // This warning is not produced anymore but fragment definition is used to filter messaged from old sessions
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct LegacyUnifiedExecProcessLimitWarning; pub(crate) struct LegacyUnifiedExecProcessLimitWarning;
impl ContextualUserFragment for LegacyUnifiedExecProcessLimitWarning { impl ContextualUserFragment for LegacyUnifiedExecProcessLimitWarning {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("unified_exec.legacy_process_limit_warning".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct ModelSwitchInstructions { pub(crate) struct ModelSwitchInstructions {
@@ -14,6 +15,10 @@ impl ModelSwitchInstructions {
} }
impl ContextualUserFragment for ModelSwitchInstructions { impl ContextualUserFragment for ModelSwitchInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("model_switch.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,5 +1,6 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::config_types::MultiAgentMode; use codex_protocol::config_types::MultiAgentMode;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::MULTI_AGENT_MODE_CLOSE_TAG; use codex_protocol::protocol::MULTI_AGENT_MODE_CLOSE_TAG;
use codex_protocol::protocol::MULTI_AGENT_MODE_OPEN_TAG; use codex_protocol::protocol::MULTI_AGENT_MODE_OPEN_TAG;
@@ -25,6 +26,10 @@ impl MultiAgentModeInstructions {
} }
impl ContextualUserFragment for MultiAgentModeInstructions { impl ContextualUserFragment for MultiAgentModeInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.mode_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct MultiAgentRoleInstructions { pub(crate) struct MultiAgentRoleInstructions {
@@ -23,6 +24,10 @@ impl MultiAgentRoleInstructions {
} }
impl ContextualUserFragment for MultiAgentRoleInstructions { impl ContextualUserFragment for MultiAgentRoleInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.role_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
/// Configured multi-agent instructions emitted as a standalone developer message. /// Configured multi-agent instructions emitted as a standalone developer message.
#[derive(Clone, Debug, PartialEq, Eq)] #[derive(Clone, Debug, PartialEq, Eq)]
@@ -15,6 +16,10 @@ impl MultiAgentUsageHint {
} }
impl ContextualUserFragment for MultiAgentUsageHint { impl ContextualUserFragment for MultiAgentUsageHint {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.usage_hint".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,6 +1,7 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::approvals::NetworkPolicyAmendment; use codex_protocol::approvals::NetworkPolicyAmendment;
use codex_protocol::approvals::NetworkPolicyRuleAction; use codex_protocol::approvals::NetworkPolicyRuleAction;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct NetworkRuleSaved { pub(crate) struct NetworkRuleSaved {
@@ -18,6 +19,10 @@ impl NetworkRuleSaved {
} }
impl ContextualUserFragment for NetworkRuleSaved { impl ContextualUserFragment for NetworkRuleSaved {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("network_proxy.rule_saved".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -6,6 +6,7 @@ use std::sync::PoisonError;
use codex_features::Feature; use codex_features::Feature;
use codex_protocol::models::ContentItem; use codex_protocol::models::ContentItem;
use codex_protocol::models::ContentItemKind;
use codex_protocol::user_input::UserInput; use codex_protocol::user_input::UserInput;
use codex_protocol::user_input::UserInput::Image; use codex_protocol::user_input::UserInput::Image;
use codex_protocol::user_input::UserInput::Text; use codex_protocol::user_input::UserInput::Text;
@@ -358,6 +359,10 @@ impl NodeReplReviewEvidenceFragment {
} }
impl ContextualUserFragment for NodeReplReviewEvidenceFragment { impl ContextualUserFragment for NodeReplReviewEvidenceFragment {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("guardian.node_repl_review_evidence".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct PersonalitySpecInstructions { pub(crate) struct PersonalitySpecInstructions {
@@ -12,6 +13,10 @@ impl PersonalitySpecInstructions {
} }
impl ContextualUserFragment for PersonalitySpecInstructions { impl ContextualUserFragment for PersonalitySpecInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("personality.spec_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct PluginInstructions { pub(crate) struct PluginInstructions {
@@ -12,6 +13,10 @@ impl PluginInstructions {
} }
impl ContextualUserFragment for PluginInstructions { impl ContextualUserFragment for PluginInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("plugins.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
const MAX_REALTIME_DELEGATION_FIELD_BYTES: usize = 4 * 1024; const MAX_REALTIME_DELEGATION_FIELD_BYTES: usize = 4 * 1024;
const TRUNCATION_MARKER: &str = "…"; const TRUNCATION_MARKER: &str = "…";
@@ -31,6 +32,10 @@ impl<'a> RealtimeDelegation<'a> {
} }
impl ContextualUserFragment for RealtimeDelegation<'_> { impl ContextualUserFragment for RealtimeDelegation<'_> {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("realtime_conversation.delegation".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,5 +1,6 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_prompts::END_INSTRUCTIONS; use codex_prompts::END_INSTRUCTIONS;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG;
use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG;
@@ -21,6 +22,10 @@ impl RealtimeEndInstructions {
} }
impl ContextualUserFragment for RealtimeEndInstructions { impl ContextualUserFragment for RealtimeEndInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("realtime_conversation.end_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,5 +1,6 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_prompts::START_INSTRUCTIONS; use codex_prompts::START_INSTRUCTIONS;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG;
use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG;
@@ -7,6 +8,10 @@ use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG;
pub(crate) struct RealtimeStartInstructions; pub(crate) struct RealtimeStartInstructions;
impl ContextualUserFragment for RealtimeStartInstructions { impl ContextualUserFragment for RealtimeStartInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("realtime_conversation.start_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_CLOSE_TAG;
use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG; use codex_protocol::protocol::REALTIME_CONVERSATION_OPEN_TAG;
@@ -16,6 +17,10 @@ impl RealtimeStartWithInstructions {
} }
impl ContextualUserFragment for RealtimeStartWithInstructions { impl ContextualUserFragment for RealtimeStartWithInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("realtime_conversation.custom_start_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
use codex_tools::DiscoverableTool; use codex_tools::DiscoverableTool;
const RECOMMENDED_PLUGINS_INTRO: &str = const RECOMMENDED_PLUGINS_INTRO: &str =
@@ -26,6 +27,10 @@ impl RecommendedPluginsInstructions {
} }
impl ContextualUserFragment for RecommendedPluginsInstructions { impl ContextualUserFragment for RecommendedPluginsInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("plugins.recommendations".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq, Eq)] #[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct RolloutBudgetContext { pub(crate) struct RolloutBudgetContext {
@@ -6,6 +7,10 @@ pub(crate) struct RolloutBudgetContext {
} }
impl ContextualUserFragment for RolloutBudgetContext { impl ContextualUserFragment for RolloutBudgetContext {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("rollout_budget.remaining_tokens".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,3 +1,4 @@
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::AgentStatus; use codex_protocol::protocol::AgentStatus;
use super::ContextualUserFragment; use super::ContextualUserFragment;
@@ -18,6 +19,10 @@ impl SubagentNotification {
} }
impl ContextualUserFragment for SubagentNotification { impl ContextualUserFragment for SubagentNotification {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("multi_agent.subagent_notification".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -2,6 +2,7 @@ use super::ContextualUserFragment;
use super::world_state::PreviousSectionState; use super::world_state::PreviousSectionState;
use super::world_state::WorldStateSection; use super::world_state::WorldStateSection;
use codex_protocol::AgentPath; use codex_protocol::AgentPath;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::CONTEXT_WINDOW_CLOSE_TAG; use codex_protocol::protocol::CONTEXT_WINDOW_CLOSE_TAG;
use codex_protocol::protocol::CONTEXT_WINDOW_GUIDANCE_CLOSE_TAG; use codex_protocol::protocol::CONTEXT_WINDOW_GUIDANCE_CLOSE_TAG;
use codex_protocol::protocol::CONTEXT_WINDOW_GUIDANCE_OPEN_TAG; use codex_protocol::protocol::CONTEXT_WINDOW_GUIDANCE_OPEN_TAG;
@@ -36,6 +37,10 @@ impl TokenBudgetContext {
} }
impl ContextualUserFragment for TokenBudgetContext { impl ContextualUserFragment for TokenBudgetContext {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("token_budget.context_window".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -101,6 +106,10 @@ impl ContextWindowGuidance {
} }
impl ContextualUserFragment for ContextWindowGuidance { impl ContextualUserFragment for ContextWindowGuidance {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("token_budget.context_window_guidance".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -139,6 +148,10 @@ impl TokenBudgetRemainingContext {
} }
impl ContextualUserFragment for TokenBudgetRemainingContext { impl ContextualUserFragment for TokenBudgetRemainingContext {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("token_budget.remaining_tokens".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -175,6 +188,10 @@ impl TokenBudgetReminder {
} }
impl ContextualUserFragment for TokenBudgetReminder { impl ContextualUserFragment for TokenBudgetReminder {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("token_budget.reminder".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -206,6 +223,10 @@ impl AutoCompactFallbackPrompt {
} }
impl ContextualUserFragment for AutoCompactFallbackPrompt { impl ContextualUserFragment for AutoCompactFallbackPrompt {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("compaction.auto_fallback_prompt".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct TurnAborted { pub(crate) struct TurnAborted {
@@ -17,6 +18,10 @@ impl TurnAborted {
} }
impl ContextualUserFragment for TurnAborted { impl ContextualUserFragment for TurnAborted {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.turn_aborted".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,4 +1,5 @@
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct UserInstructions { pub(crate) struct UserInstructions {
@@ -7,6 +8,10 @@ pub(crate) struct UserInstructions {
} }
impl ContextualUserFragment for UserInstructions { impl ContextualUserFragment for UserInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("agents_md.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -1,6 +1,7 @@
use std::time::Duration; use std::time::Duration;
use super::ContextualUserFragment; use super::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub(crate) struct UserShellCommand { pub(crate) struct UserShellCommand {
@@ -27,6 +28,10 @@ impl UserShellCommand {
} }
impl ContextualUserFragment for UserShellCommand { impl ContextualUserFragment for UserShellCommand {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("shell.user_command".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -4,6 +4,7 @@ use super::WorldStateSection;
use crate::context::ContextualUserFragment; use crate::context::ContextualUserFragment;
use codex_protocol::config_types::CollaborationMode; use codex_protocol::config_types::CollaborationMode;
use codex_protocol::config_types::ModeKind; use codex_protocol::config_types::ModeKind;
use codex_protocol::models::ContentItemKind;
use codex_protocol::openai_models::CollaborationModeMessages; use codex_protocol::openai_models::CollaborationModeMessages;
use codex_protocol::protocol::COLLABORATION_MODE_CLOSE_TAG; use codex_protocol::protocol::COLLABORATION_MODE_CLOSE_TAG;
use codex_protocol::protocol::COLLABORATION_MODE_OPEN_TAG; use codex_protocol::protocol::COLLABORATION_MODE_OPEN_TAG;
@@ -125,6 +126,10 @@ struct CollaborationModeInstructions {
} }
impl ContextualUserFragment for CollaborationModeInstructions { impl ContextualUserFragment for CollaborationModeInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("collaboration_mode.instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
@@ -6,6 +6,7 @@ use crate::context::environment_context::NetworkContext;
use crate::context::environment_context::push_xml_escaped_text; use crate::context::environment_context::push_xml_escaped_text;
use crate::environment_selection::TurnEnvironmentSnapshot; use crate::environment_selection::TurnEnvironmentSnapshot;
use crate::session::turn_context::TurnContext; use crate::session::turn_context::TurnContext;
use codex_protocol::models::ContentItemKind;
use codex_utils_path_uri::PathUri; use codex_utils_path_uri::PathUri;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@@ -154,6 +155,10 @@ impl WorldStateSection for EnvironmentsState {
} }
impl ContextualUserFragment for EnvironmentsState { impl ContextualUserFragment for EnvironmentsState {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("environments.environment_context".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -188,6 +193,10 @@ enum EnvironmentUpdate {
} }
impl ContextualUserFragment for RenderedEnvironments { impl ContextualUserFragment for RenderedEnvironments {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("environments.environment_context".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -3,6 +3,7 @@ use super::WorldStateHash;
use super::WorldStateSection; use super::WorldStateSection;
use crate::context::ContextualUserFragment; use crate::context::ContextualUserFragment;
use codex_config::Sourced; use codex_config::Sourced;
use codex_protocol::models::ContentItemKind;
use codex_utils_string::approx_bytes_for_tokens; use codex_utils_string::approx_bytes_for_tokens;
use codex_utils_string::approx_tokens_from_byte_count; use codex_utils_string::approx_tokens_from_byte_count;
use serde::Deserialize; use serde::Deserialize;
@@ -21,6 +22,10 @@ pub(crate) struct ManagedDeveloperInstructions {
} }
impl ContextualUserFragment for ManagedDeveloperInstructions { impl ContextualUserFragment for ManagedDeveloperInstructions {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("managed_config.developer_instructions".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"developer" "developer"
} }
+18 -7
View File
@@ -22,6 +22,7 @@ use codex_extension_api::PreviousWorldStateSection;
use codex_extension_api::RenderedWorldStateFragment; use codex_extension_api::RenderedWorldStateFragment;
use codex_extension_api::WorldStateSectionContribution; use codex_extension_api::WorldStateSectionContribution;
use codex_protocol::models::ContentItem; use codex_protocol::models::ContentItem;
use codex_protocol::models::ContentItemKind;
use codex_protocol::models::ResponseItem; use codex_protocol::models::ResponseItem;
use indexmap::IndexMap; use indexmap::IndexMap;
use serde::Deserialize; use serde::Deserialize;
@@ -167,25 +168,35 @@ impl ErasedWorldStateSection for ExtensionWorldStateSection {
PreviousSectionState::Unknown => PreviousWorldStateSection::Unknown, PreviousSectionState::Unknown => PreviousWorldStateSection::Unknown,
PreviousSectionState::Known(previous) => PreviousWorldStateSection::Known(previous), PreviousSectionState::Known(previous) => PreviousWorldStateSection::Known(previous),
}; };
self.0 self.0.render_diff(previous).map(|fragment| {
.render_diff(previous) Box::new(WorldStateContextFragment {
.map(|fragment| Box::new(WorldStateContextFragment(fragment)) as _) fragment,
content_kind: ContentItemKind(format!("{}.instructions", self.0.id())),
}) as _
})
} }
} }
struct WorldStateContextFragment(RenderedWorldStateFragment); struct WorldStateContextFragment {
fragment: RenderedWorldStateFragment,
content_kind: ContentItemKind,
}
impl ContextualUserFragment for WorldStateContextFragment { impl ContextualUserFragment for WorldStateContextFragment {
fn content_kind(&self) -> ContentItemKind {
self.content_kind.clone()
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
self.0.role() self.fragment.role()
} }
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
self.0.markers() self.fragment.markers()
} }
fn body(&self) -> String { fn body(&self) -> String {
self.0.body().to_string() self.fragment.body().to_string()
} }
fn type_markers() -> (&'static str, &'static str) { fn type_markers() -> (&'static str, &'static str) {
@@ -4,6 +4,7 @@ use super::WorldStateSection;
use crate::context::ContextualUserFragment; use crate::context::ContextualUserFragment;
use crate::context::environment_context::push_xml_escaped_text; use crate::context::environment_context::push_xml_escaped_text;
use codex_extension_api::RenderedWorldStateFragment; use codex_extension_api::RenderedWorldStateFragment;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::TOOLS_CLOSE_TAG; use codex_protocol::protocol::TOOLS_CLOSE_TAG;
use codex_protocol::protocol::TOOLS_OPEN_TAG; use codex_protocol::protocol::TOOLS_OPEN_TAG;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@@ -97,9 +98,14 @@ impl WorldStateSection for ToolsState {
) )
} }
}; };
Some(Box::new(WorldStateContextFragment( Some(Box::new(WorldStateContextFragment {
RenderedWorldStateFragment::new("developer", (TOOLS_OPEN_TAG, TOOLS_CLOSE_TAG), body), fragment: RenderedWorldStateFragment::new(
))) "developer",
(TOOLS_OPEN_TAG, TOOLS_CLOSE_TAG),
body,
),
content_kind: ContentItemKind("tools.deferred_namespaces".to_string()),
}))
} }
} }
@@ -1,4 +1,6 @@
use super::*; use super::*;
use codex_context_fragments::AnnotatedContent;
use codex_protocol::models::ContentItemKind;
use pretty_assertions::assert_eq; use pretty_assertions::assert_eq;
use serde::Deserialize; use serde::Deserialize;
use serde::Serialize; use serde::Serialize;
@@ -36,6 +38,10 @@ impl WorldStateSection for TestSection {
struct TestFragment(String); struct TestFragment(String);
impl ContextualUserFragment for TestFragment { impl ContextualUserFragment for TestFragment {
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.test".to_string())
}
fn role(&self) -> &'static str { fn role(&self) -> &'static str {
"user" "user"
} }
@@ -157,6 +163,38 @@ fn extension_owned_section_uses_its_snapshot_and_renderer() {
); );
} }
#[test]
fn extension_owned_section_uses_its_stable_id_as_content_kind_feature() {
let mut world_state = WorldState::default();
world_state.add_extension_section(WorldStateSectionContribution::new(
"extension_test",
json!({"value": "after"}),
|_| {
Some(RenderedWorldStateFragment::new(
"developer",
("<extension_test>", "</extension_test>"),
"after",
))
},
));
let rendered = world_state.render_diff(&WorldStateSnapshot::default());
assert_eq!(
rendered
.into_iter()
.map(|fragment| fragment.render_fragment().into_parts())
.collect::<Vec<_>>(),
vec![(
"developer",
AnnotatedContent::input_text(
"<extension_test>after</extension_test>",
ContentItemKind("extension_test.instructions".to_string()),
),
)]
);
}
#[test] #[test]
fn missing_retained_fragment_is_rendered_again() { fn missing_retained_fragment_is_rendered_again() {
let mut world_state = WorldState::default(); let mut world_state = WorldState::default();
+1 -5
View File
@@ -9,7 +9,6 @@ use codex_exec_server::FileSystemSandboxContext;
use codex_exec_server::LOCAL_ENVIRONMENT_ID; use codex_exec_server::LOCAL_ENVIRONMENT_ID;
use codex_exec_server::ResolvedSelectedCapabilityRoot; use codex_exec_server::ResolvedSelectedCapabilityRoot;
use codex_extension_api::ConfigContributor; use codex_extension_api::ConfigContributor;
use codex_extension_api::ContentItemKind;
use codex_extension_api::ContextContributor; use codex_extension_api::ContextContributor;
use codex_extension_api::ContextualUserFragment; use codex_extension_api::ContextualUserFragment;
use codex_extension_api::ExtensionData; use codex_extension_api::ExtensionData;
@@ -238,10 +237,7 @@ where
rendered rendered
.fragment .fragment
.map(|fragment| { .map(|fragment| {
PromptFragment::developer_capability( PromptFragment::developer_capability(fragment.render(), fragment.content_kind())
fragment.render(),
ContentItemKind("skills.catalog".to_string()),
)
}) })
.into_iter() .into_iter()
.collect() .collect()
+9
View File
@@ -1,4 +1,5 @@
use codex_extension_api::ContextualUserFragment; use codex_extension_api::ContextualUserFragment;
use codex_protocol::models::ContentItemKind;
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG; use codex_protocol::protocol::SKILLS_INSTRUCTIONS_CLOSE_TAG;
use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG; use codex_protocol::protocol::SKILLS_INSTRUCTIONS_OPEN_TAG;
@@ -40,6 +41,10 @@ impl ContextualUserFragment for AvailableSkillsInstructions {
"developer" "developer"
} }
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("skills.catalog".to_string())
}
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers() Self::type_markers()
} }
@@ -73,6 +78,10 @@ impl ContextualUserFragment for SkillInstructions {
"user" "user"
} }
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("skills.selected_skill_instructions".to_string())
}
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers() Self::type_markers()
} }
@@ -2,6 +2,7 @@ use codex_context_fragments::ContextualUserFragment;
use codex_execpolicy::Policy; use codex_execpolicy::Policy;
use codex_protocol::config_types::ApprovalsReviewer; use codex_protocol::config_types::ApprovalsReviewer;
use codex_protocol::config_types::SandboxMode; use codex_protocol::config_types::SandboxMode;
use codex_protocol::models::ContentItemKind;
use codex_protocol::models::PermissionProfile; use codex_protocol::models::PermissionProfile;
use codex_protocol::models::format_allow_prefixes; use codex_protocol::models::format_allow_prefixes;
use codex_protocol::openai_models::ApprovalMessages; use codex_protocol::openai_models::ApprovalMessages;
@@ -177,6 +178,10 @@ impl ContextualUserFragment for PermissionsInstructions {
"developer" "developer"
} }
fn content_kind(&self) -> ContentItemKind {
ContentItemKind("generic.permissions_instructions".to_string())
}
fn markers(&self) -> (&'static str, &'static str) { fn markers(&self) -> (&'static str, &'static str) {
Self::type_markers() Self::type_markers()
} }