mirror of
https://github.com/openai/codex.git
synced 2026-11-09 00:39:32 +00:00
## What changed Add `ComposedContext::enforce_budget` to fit evidence within the input token allowance after reserving existing context. Preserve required content and message boundaries, reserve an omission notice, and return an error if required evidence cannot fit. Carry retention policies through transcript rendering and composition. Protect user messages, protected messages, and the newest five tool entries. Remove oversized optional items first, then evict commentary, older tool evidence, and images in priority order. Add image admission support and record omitted content in truncation observations. ## Testing Add tests for existing-context reservations, required-message preservation, image omission, framing costs, and protection of the newest five tool entries in both context profiles. GitOrigin-RevId: 8a0f245bad82f562323b4533442385ddbcb6e541
99 lines
3.2 KiB
Rust
99 lines
3.2 KiB
Rust
//! Profile retention keeps the existing sync and async evidence priorities.
|
|
|
|
use super::*;
|
|
use pretty_assertions::assert_eq;
|
|
|
|
#[test]
|
|
fn profiles_preserve_distinct_retention_and_original_numbering() {
|
|
let entries = [
|
|
(ConversationTranscriptEntryKind::User, "inspect only"),
|
|
(
|
|
ConversationTranscriptEntryKind::Developer,
|
|
"approved action",
|
|
),
|
|
(ConversationTranscriptEntryKind::Assistant, "working"),
|
|
]
|
|
.into_iter()
|
|
.map(|(kind, text)| ConversationTranscriptEntry {
|
|
kind,
|
|
text: text.to_owned(),
|
|
original_bytes: text.len(),
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let mut sync = ContextProfile::synchronous();
|
|
sync.retention.max_recent_non_user_entries = 1;
|
|
let mut asynchronous = ContextProfile::asynchronous();
|
|
asynchronous.retention.max_recent_non_user_entries = 1;
|
|
let sync = sync.render_transcript(&entries, /*entry_number_offset*/ 7);
|
|
let asynchronous = asynchronous.render_transcript(&entries, /*entry_number_offset*/ 0);
|
|
assert_eq!(
|
|
(sync.items, sync.omission_note),
|
|
(
|
|
vec![
|
|
Budgeted::required("[8] user: inspect only".to_owned()),
|
|
Budgeted::optional(
|
|
"[10] assistant: working".to_owned(),
|
|
BudgetPriority::Commentary
|
|
)
|
|
],
|
|
Some("Some conversation entries were omitted.".to_owned()),
|
|
),
|
|
);
|
|
assert_eq!(
|
|
(asynchronous.items, asynchronous.omission_note),
|
|
(
|
|
vec![
|
|
Budgeted::required("[1] user: inspect only\n".to_owned()),
|
|
Budgeted::required("[2] developer: approved action\n".to_owned())
|
|
],
|
|
None,
|
|
),
|
|
);
|
|
assert_eq!(
|
|
asynchronous
|
|
.truncations
|
|
.into_iter()
|
|
.map(|observation| (
|
|
observation.component,
|
|
observation.original_bytes,
|
|
observation.retained_bytes,
|
|
))
|
|
.collect::<Vec<_>>(),
|
|
vec![("transcript_message", "working".len(), 0)],
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn profiles_reserve_the_newest_five_tool_entries_for_aggregate_enforcement() {
|
|
let entries = (0..8)
|
|
.map(|index| ConversationTranscriptEntry {
|
|
kind: ConversationTranscriptEntryKind::ToolOutput("tool result".to_owned()),
|
|
text: format!("result {index}"),
|
|
original_bytes: 8,
|
|
})
|
|
.collect::<Vec<_>>();
|
|
for profile in [
|
|
ContextProfile::synchronous(),
|
|
ContextProfile::asynchronous(),
|
|
] {
|
|
let transcript = profile.render_transcript(&entries, /*entry_number_offset*/ 0);
|
|
assert_eq!(
|
|
transcript
|
|
.items
|
|
.iter()
|
|
.map(|item| item.retention)
|
|
.collect::<Vec<_>>(),
|
|
vec![
|
|
Retention::Optional(BudgetPriority::Tool),
|
|
Retention::Optional(BudgetPriority::Tool),
|
|
Retention::Optional(BudgetPriority::Tool),
|
|
Retention::Required,
|
|
Retention::Required,
|
|
Retention::Required,
|
|
Retention::Required,
|
|
Retention::Required
|
|
]
|
|
);
|
|
}
|
|
}
|