mirror of
https://github.com/openai/codex.git
synced 2026-10-28 18:58:46 +00:00
Support window prefixes for extension world-state sections (#57276)
## What changed Add `WorldStateSectionContribution::with_window_prefix()` to render extension developer fragments as separate messages before retained history when building a context window, including after compaction. Updates within an existing window still append to history. Ignore fragments with other roles for sections that opt in. ## Testing Add a unit test for prefix placement and duplicate avoidance, plus local and remote compaction scenarios covering live updates, persisted replacement history, and rejection of non-developer fragments. GitOrigin-RevId: 8621457c6eec17f1585ca8e6fa154b1bf3257330
This commit is contained in:
committed by
copyberry
parent
166aed9854
commit
d416d8a0ff
@@ -271,6 +271,55 @@ fn compacted_user_message<'a>(text: &str, original: &'a ResponseItem) -> Compact
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn extension_window_prefix_precedes_retained_turns_and_is_not_repeated() {
|
||||
use codex_extension_api::PreviousWorldStateSection;
|
||||
use codex_extension_api::RenderedWorldStateFragment;
|
||||
use codex_extension_api::WorldStateSectionContribution;
|
||||
|
||||
let (session, turn) = crate::session::tests::make_session_and_context().await;
|
||||
let step = StepContext::for_test(Arc::new(turn));
|
||||
let mut world = WorldState::default();
|
||||
world.add_extension_section(
|
||||
WorldStateSectionContribution::new("example", |previous| {
|
||||
let fragment = (!matches!(previous, PreviousWorldStateSection::Known(_))).then(|| {
|
||||
RenderedWorldStateFragment::new(
|
||||
"developer",
|
||||
("<example>", "</example>"),
|
||||
codex_protocol::models::input_text("active policy"),
|
||||
)
|
||||
});
|
||||
(Some(json!("active policy")), fragment)
|
||||
})
|
||||
.with_window_prefix()
|
||||
.with_retained_fragment_matcher(|role, text| {
|
||||
role == "developer" && text == "<example>active policy</example>"
|
||||
}),
|
||||
);
|
||||
let retained = vec![user_message("earlier turn"), user_message("latest turn")];
|
||||
let (replacement, snapshot) =
|
||||
build_compaction_replacement_history(&session, &step, &world, annotated(retained.clone()))
|
||||
.await;
|
||||
let items = raw(replacement);
|
||||
let ResponseItem::Message { role, content, .. } = &items[0] else {
|
||||
panic!("expected a separate developer prefix");
|
||||
};
|
||||
assert_eq!(role, "developer");
|
||||
assert_eq!(
|
||||
content,
|
||||
&[codex_protocol::models::input_text(
|
||||
"<example>active policy</example>"
|
||||
)]
|
||||
);
|
||||
assert_eq!(items[1], retained[0]);
|
||||
assert!(
|
||||
world
|
||||
.render_history_diff(Some(&snapshot), &items)
|
||||
.1
|
||||
.is_empty()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn content_items_to_text_joins_non_empty_segments() {
|
||||
let items = vec![
|
||||
|
||||
@@ -247,11 +247,20 @@ impl ErasedWorldStateSection for ExtensionWorldStateSection {
|
||||
});
|
||||
let updates = fragment
|
||||
.into_iter()
|
||||
.filter(|fragment| !self.0.is_window_prefix() || fragment.role() == "developer")
|
||||
.map(|fragment| {
|
||||
WorldStateUpdate::fragment(WorldStateContextFragment {
|
||||
let update = WorldStateUpdate::fragment(WorldStateContextFragment {
|
||||
fragment,
|
||||
content_kind: ContentItemKind(format!("{}.instructions", self.0.id())),
|
||||
})
|
||||
});
|
||||
if self.0.is_window_prefix() {
|
||||
WorldStateUpdate {
|
||||
placement: Placement::Prefix,
|
||||
..update
|
||||
}
|
||||
} else {
|
||||
update
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
(snapshot, updates)
|
||||
|
||||
Reference in New Issue
Block a user