mirror of
https://github.com/openai/codex.git
synced 2026-10-29 19:08:43 +00:00
## Why The token-budget context currently identifies a context window by its thread-local sequence number. A UUIDv7 gives the model a stable opaque identity that remains fixed for a window and rotates when compaction or `new_context` starts the next one. ## What changed - Preserve the existing monotonic value as `window_number` and add a UUIDv7 `window_id` to `CompactedItem`. - Generate and rotate the UUID with auto-compaction window state, persist it alongside the number, and reconstruct it on resume and rollback. - Accept legacy compacted rollout records where the numeric `window_id` represented the window number. - Use the UUID only in token-budget context; existing request headers and metadata continue using `thread_id:window_number`. ## Testing - `just test -p codex-protocol compacted_item::tests` - `just test -p codex-core token_budget`
95 lines
2.6 KiB
Rust
95 lines
2.6 KiB
Rust
use crate::models::ResponseItem;
|
|
use crate::protocol::CompactedItem;
|
|
use serde::Deserialize;
|
|
|
|
// Before `window_number` was introduced, the numeric window number was serialized as
|
|
// `window_id`. Accept that shape so existing rollouts remain resumable.
|
|
impl<'de> Deserialize<'de> for CompactedItem {
|
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
|
where
|
|
D: serde::Deserializer<'de>,
|
|
{
|
|
let serialized = SerializedCompactedItem::deserialize(deserializer)?;
|
|
let mut window_number = serialized.window_number;
|
|
let window_id = match serialized.window_id {
|
|
Some(SerializedWindowId::Id(window_id)) => Some(window_id),
|
|
Some(SerializedWindowId::LegacyWindowNumber(legacy_window_number)) => {
|
|
window_number.get_or_insert(legacy_window_number);
|
|
None
|
|
}
|
|
None => None,
|
|
};
|
|
Ok(Self {
|
|
message: serialized.message,
|
|
replacement_history: serialized.replacement_history,
|
|
window_number,
|
|
window_id,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
struct SerializedCompactedItem {
|
|
message: String,
|
|
#[serde(default)]
|
|
replacement_history: Option<Vec<ResponseItem>>,
|
|
#[serde(default)]
|
|
window_number: Option<u64>,
|
|
#[serde(default)]
|
|
window_id: Option<SerializedWindowId>,
|
|
}
|
|
|
|
#[derive(Deserialize)]
|
|
#[serde(untagged)]
|
|
enum SerializedWindowId {
|
|
Id(String),
|
|
LegacyWindowNumber(u64),
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
use anyhow::Result;
|
|
use pretty_assertions::assert_eq;
|
|
use serde_json::json;
|
|
|
|
#[test]
|
|
fn serializes_window_number_and_id() -> Result<()> {
|
|
let item = CompactedItem {
|
|
message: "summary".to_string(),
|
|
replacement_history: None,
|
|
window_number: Some(3),
|
|
window_id: Some("019b3f6e-7a10-7cc3-8b6e-1d09e2f7a001".to_string()),
|
|
};
|
|
|
|
assert_eq!(
|
|
serde_json::to_value(item)?,
|
|
json!({
|
|
"message": "summary",
|
|
"window_number": 3,
|
|
"window_id": "019b3f6e-7a10-7cc3-8b6e-1d09e2f7a001",
|
|
})
|
|
);
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn migrates_legacy_numeric_window_id() -> Result<()> {
|
|
let item = serde_json::from_value::<CompactedItem>(json!({
|
|
"message": "summary",
|
|
"window_id": 3,
|
|
}))?;
|
|
|
|
assert_eq!(
|
|
item,
|
|
CompactedItem {
|
|
message: "summary".to_string(),
|
|
replacement_history: None,
|
|
window_number: Some(3),
|
|
window_id: None,
|
|
}
|
|
);
|
|
Ok(())
|
|
}
|
|
}
|