mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
[codex] simplify token budget context (#29295)
## Why The token-budget feature currently adds remaining-token messages whenever usage crosses the 25%, 50%, and 75% thresholds. Those periodic inserts create prompt churn without requiring action, while the near-compaction reminder and explicit `get_context_remaining` tool already cover actionable and on-demand budget information. The context-window lineage block is also easier to scan as plain labeled text than as a `<token_budget>`-wrapped fragment. ## What changed - Stop recording automatic remaining-token messages at percentage thresholds. - Render context-window lineage in `First`, `Current`, `Previous` order with colon-separated labels. - Omit the `Previous` line for the first context window. - Remove `<token_budget>` wrappers from newly rendered lineage, near-compaction reminders, and `get_context_remaining` output. - Keep recognizing legacy wrapped fragments so existing rollouts remain compatible. - Remove the post-sampling token snapshot that was only needed by the periodic threshold path. ## Testing - `just test -p codex-core token_budget` (11 tests passed)
This commit is contained in:
committed by
GitHub
Unverified
parent
6df037d47f
commit
aaf737fa59
@@ -39,24 +39,25 @@ impl ContextualUserFragment for TokenBudgetContext {
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<token_budget>\n", "\n</token_budget>")
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
let thread_id = self.thread_id;
|
||||
let first_window_id = self.first_window_id;
|
||||
let previous_window_id = self
|
||||
.previous_window_id
|
||||
.map_or_else(|| "none".to_string(), |window_id| window_id.to_string());
|
||||
let window_id = self.window_id;
|
||||
let mcp_result = self
|
||||
.mcp_result
|
||||
.as_deref()
|
||||
.map(|result| format!("\n{result}"))
|
||||
.unwrap_or_default();
|
||||
format!(
|
||||
"Thread id {thread_id}.\nFirst context window id {first_window_id}.\nPrevious context window id {previous_window_id}.\nCurrent context window id {window_id}.{mcp_result}"
|
||||
)
|
||||
let mut lines = vec![
|
||||
format!("Thread id {thread_id}."),
|
||||
format!("First context window id: {first_window_id}"),
|
||||
format!("Current context window id: {window_id}"),
|
||||
];
|
||||
if let Some(previous_window_id) = self.previous_window_id {
|
||||
lines.push(format!("Previous context window id: {previous_window_id}"));
|
||||
}
|
||||
if let Some(mcp_result) = &self.mcp_result {
|
||||
lines.push(mcp_result.clone());
|
||||
}
|
||||
lines.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +88,7 @@ impl ContextualUserFragment for TokenBudgetRemainingContext {
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<token_budget>\n", "\n</token_budget>")
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
@@ -123,7 +124,7 @@ impl ContextualUserFragment for TokenBudgetReminder {
|
||||
}
|
||||
|
||||
fn type_markers() -> (&'static str, &'static str) {
|
||||
("<token_budget>\n", "\n</token_budget>")
|
||||
("", "")
|
||||
}
|
||||
|
||||
fn body(&self) -> String {
|
||||
|
||||
@@ -34,6 +34,7 @@ const CONTEXTUAL_DEVELOPER_PREFIXES: &[&str] = &[
|
||||
REALTIME_CONVERSATION_OPEN_TAG,
|
||||
SKILLS_INSTRUCTIONS_OPEN_TAG,
|
||||
"<personality_spec>",
|
||||
// Keep recognizing token-budget wrappers persisted by older versions.
|
||||
"<token_budget>",
|
||||
"<rollout_budget>",
|
||||
];
|
||||
|
||||
@@ -29,7 +29,7 @@ fn recognizes_skills_instructions_as_contextual_developer_content() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn recognizes_token_budget_as_contextual_developer_content() {
|
||||
fn recognizes_legacy_token_budget_as_contextual_developer_content() {
|
||||
let content = vec![ContentItem::InputText {
|
||||
text: "<token_budget>\nYou have 710 tokens left in this context window.\n</token_budget>"
|
||||
.to_string(),
|
||||
|
||||
@@ -3,63 +3,35 @@ use super::turn_context::TurnContext;
|
||||
use crate::context::ContextualUserFragment;
|
||||
use codex_features::Feature;
|
||||
|
||||
const TOKEN_BUDGET_USAGE_THRESHOLDS: [i64; 3] = [25, 50, 75];
|
||||
|
||||
pub(super) async fn maybe_record(
|
||||
sess: &Session,
|
||||
turn_context: &TurnContext,
|
||||
tokens_before_sampling: i64,
|
||||
tokens_after_sampling: i64,
|
||||
tokens_until_compaction: i64,
|
||||
) {
|
||||
if !turn_context.config.features.enabled(Feature::TokenBudget) {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut response_items = Vec::new();
|
||||
if let Some(model_context_window) = turn_context.model_context_window()
|
||||
&& model_context_window > 0
|
||||
&& tokens_after_sampling > tokens_before_sampling
|
||||
{
|
||||
let tokens_before_sampling = tokens_before_sampling.max(0);
|
||||
let tokens_after_sampling = tokens_after_sampling.max(0);
|
||||
let crossed_threshold = TOKEN_BUDGET_USAGE_THRESHOLDS.iter().any(|threshold| {
|
||||
tokens_before_sampling.saturating_mul(100)
|
||||
< model_context_window.saturating_mul(*threshold)
|
||||
&& tokens_after_sampling.saturating_mul(100)
|
||||
>= model_context_window.saturating_mul(*threshold)
|
||||
});
|
||||
if crossed_threshold {
|
||||
let tokens_left = model_context_window
|
||||
.saturating_sub(tokens_after_sampling)
|
||||
.max(0);
|
||||
response_items.push(ContextualUserFragment::into(
|
||||
crate::context::TokenBudgetRemainingContext::new(tokens_left),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(config) = turn_context.config.token_budget.as_ref().filter(|config| {
|
||||
let Some(config) = turn_context.config.token_budget.as_ref().filter(|config| {
|
||||
config
|
||||
.reminder_threshold_tokens
|
||||
.is_some_and(|threshold| tokens_until_compaction <= threshold)
|
||||
}) {
|
||||
let reminder_due = {
|
||||
let mut state = sess.state.lock().await;
|
||||
state.claim_token_budget_reminder()
|
||||
};
|
||||
if reminder_due {
|
||||
response_items.push(ContextualUserFragment::into(
|
||||
crate::context::TokenBudgetReminder::new(
|
||||
&config.reminder_message_template,
|
||||
tokens_until_compaction,
|
||||
),
|
||||
));
|
||||
}
|
||||
}) else {
|
||||
return;
|
||||
};
|
||||
|
||||
let reminder_due = {
|
||||
let mut state = sess.state.lock().await;
|
||||
state.claim_token_budget_reminder()
|
||||
};
|
||||
if !reminder_due {
|
||||
return;
|
||||
}
|
||||
|
||||
if !response_items.is_empty() {
|
||||
sess.record_conversation_items(turn_context, &response_items)
|
||||
.await;
|
||||
}
|
||||
let response_item = ContextualUserFragment::into(crate::context::TokenBudgetReminder::new(
|
||||
&config.reminder_message_template,
|
||||
tokens_until_compaction,
|
||||
));
|
||||
sess.record_conversation_items(turn_context, std::slice::from_ref(&response_item))
|
||||
.await;
|
||||
}
|
||||
|
||||
@@ -254,8 +254,7 @@ pub(crate) async fn run_turn(
|
||||
window_id,
|
||||
CodexResponsesRequestKind::Turn,
|
||||
);
|
||||
let tokens_before_sampling = sess.get_total_token_usage().await;
|
||||
let (sampling_request_output, sampling_request_input) = run_sampling_request(
|
||||
run_sampling_request(
|
||||
Arc::clone(&sess),
|
||||
Arc::clone(&turn_context),
|
||||
Arc::clone(&turn_extension_data),
|
||||
@@ -265,17 +264,11 @@ pub(crate) async fn run_turn(
|
||||
sampling_request_input,
|
||||
cancellation_token.child_token(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok((
|
||||
tokens_before_sampling,
|
||||
sampling_request_output,
|
||||
sampling_request_input,
|
||||
))
|
||||
.await
|
||||
}
|
||||
.await;
|
||||
match sampling_request_result {
|
||||
Ok((tokens_before_sampling, sampling_request_output, sampling_request_input)) => {
|
||||
Ok((sampling_request_output, sampling_request_input)) => {
|
||||
let SamplingRequestResult {
|
||||
needs_follow_up: model_needs_follow_up,
|
||||
last_agent_message: sampling_request_last_agent_message,
|
||||
@@ -326,8 +319,6 @@ pub(crate) async fn run_turn(
|
||||
super::token_budget::maybe_record(
|
||||
sess.as_ref(),
|
||||
turn_context.as_ref(),
|
||||
tokens_before_sampling,
|
||||
tokens_after_sampling,
|
||||
tokens_until_compaction,
|
||||
)
|
||||
.await;
|
||||
|
||||
Reference in New Issue
Block a user