Allow volatile World State sections to refresh after compaction (#58956)

## Why

Host-provided context such as budget reminders can become stale while compaction runs. Replaying a captured value or retaining its comparison snapshot can prevent the next step from emitting a fresh reminder, even when the remaining budget has changed.

## What changed

- Add `WorldStateSectionContribution::without_full_context()` to omit a section's fragment and comparison snapshot from initial and compacted context rebuilds while preserving ordinary step updates.
- Reset comparison state after prefix compaction for sections excluded at either capture or installation, including when their messages survive in the live suffix.
- Include step World State updates when building debug prompt input.

## Testing

Add regression coverage for budget reminders refreshing after remote compaction within the same threshold, unchanged request prefixes within a context window, refreshes with a retained live suffix, and step reminders in debug prompts.

GitOrigin-RevId: ea4456755e16c93b5d16e8c762b26a33f8571a86
This commit is contained in:
rhan-oai
2026-11-02 19:38:59 +00:00
committed by copyberry
parent 43ad1cbf30
commit 2fa67f03f3
10 changed files with 503 additions and 48 deletions
@@ -98,6 +98,7 @@ type LegacyFragmentMatcher = dyn Fn(&str, &str) -> bool + Send + Sync;
#[derive(Clone)]
pub struct WorldStateSectionContribution {
id: &'static str,
include_in_full_context: bool,
window_prefix: bool,
render_diff: Arc<RenderDiff>,
matches_legacy_fragment: Arc<LegacyFragmentMatcher>,
@@ -119,6 +120,7 @@ impl WorldStateSectionContribution {
) -> Self {
Self {
id,
include_in_full_context: true,
window_prefix: false,
render_diff: Arc::new(render_diff),
matches_legacy_fragment: Arc::new(|_, _| false),
@@ -126,6 +128,20 @@ impl WorldStateSectionContribution {
}
}
/// Recompute this section during ordinary step context updates instead of replaying
/// its captured value when initial or compacted context is rebuilt. Full rendering
/// omits both its fragment and comparison snapshot so a fresh contribution can emit.
/// After prefix compaction, the next diff receives [`PreviousWorldStateSection::Unknown`]
/// if the section's legacy matcher recognizes text in the retained suffix.
pub fn without_full_context(mut self) -> Self {
self.include_in_full_context = false;
self
}
pub fn include_in_full_context(&self) -> bool {
self.include_in_full_context
}
pub fn with_legacy_matcher(
mut self,
matcher: impl Fn(&str, &str) -> bool + Send + Sync + 'static,