mirror of
https://github.com/openai/codex.git
synced 2026-11-14 21:40:39 +00:00
Add per-item retention policies for injected history (#61344)
## What changed Allow `thread/inject_items` to accept wrapped items with `retention: "default"` or `retention: "always"`, while preserving support for raw response items. Persist explicit policies separately from legacy client-authored metadata. Carry explicitly retained items through local and remote compaction, context-window changes, and child-agent creation, subject to retention budgets. Preserve history order and keep retained tool exchanges together; require matching calls and outputs to be adjacent in the injection request and both marked `always`. Update Quinn dependencies and record exceptions for additional Hickory DNSSEC advisories where DNSSEC is disabled. ## Testing Update injection tests for explicit retention metadata and extend the compaction scenario to cover a retained tool exchange across repeated compaction and restart. GitOrigin-RevId: 1195a4ed62dc162a62e58bc2ad733262fbabea27
This commit is contained in:
@@ -10,6 +10,7 @@ use crate::protocol::W3cTraceContext;
|
||||
use crate::user_input::UserInput;
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde::Deserializer;
|
||||
use serde::Serialize;
|
||||
use serde_json::Value;
|
||||
use std::collections::BTreeMap;
|
||||
@@ -52,6 +53,55 @@ pub struct ResponseItemAnnotations {
|
||||
pub retain: bool,
|
||||
}
|
||||
|
||||
/// A Responses item for history injection. Wrapped items must specify a policy.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct InjectedResponseItem {
|
||||
pub item: ResponseItem,
|
||||
pub retention: ItemRetention,
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for InjectedResponseItem {
|
||||
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
|
||||
#[derive(Deserialize)]
|
||||
struct WrappedItem {
|
||||
item: ResponseItem,
|
||||
retention: ItemRetention,
|
||||
}
|
||||
|
||||
let value = Value::deserialize(deserializer)?;
|
||||
if value.get("type").is_some() {
|
||||
return ResponseItem::deserialize(value)
|
||||
.map(Self::from)
|
||||
.map_err(serde::de::Error::custom);
|
||||
}
|
||||
|
||||
let WrappedItem { item, retention } =
|
||||
WrappedItem::deserialize(value).map_err(serde::de::Error::custom)?;
|
||||
Ok(Self { item, retention })
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub enum ItemRetention {
|
||||
/// Raw items use the thread's configured retention rules.
|
||||
#[serde(skip)]
|
||||
Unspecified,
|
||||
/// Apply ordinary history rules even when the thread retains client developer messages.
|
||||
Default,
|
||||
/// Carry the item into later context windows and newly spawned children.
|
||||
Always,
|
||||
}
|
||||
|
||||
impl From<ResponseItem> for InjectedResponseItem {
|
||||
fn from(item: ResponseItem) -> Self {
|
||||
Self {
|
||||
item,
|
||||
retention: ItemRetention::Unspecified,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// One turn input and the context that follows it through submission.
|
||||
///
|
||||
/// Callers choose start-or-steer, idle-start, or steer-only behavior through
|
||||
|
||||
Reference in New Issue
Block a user