mirror of
https://github.com/openai/codex.git
synced 2026-10-25 18:28:38 +00:00
codex: clarify durable history preparation (#30618)
This commit is contained in:
@@ -12,7 +12,6 @@ mod client_common;
|
||||
mod realtime_context;
|
||||
mod realtime_conversation;
|
||||
mod realtime_prompt;
|
||||
mod response_item_history;
|
||||
mod responses_metadata;
|
||||
mod responses_retry;
|
||||
pub(crate) mod session;
|
||||
|
||||
@@ -208,6 +208,7 @@ mod input_queue;
|
||||
mod mcp;
|
||||
mod mcp_runtime;
|
||||
pub(crate) mod multi_agents;
|
||||
mod response_item_history;
|
||||
mod review;
|
||||
mod rollout_budget;
|
||||
mod rollout_reconstruction;
|
||||
@@ -2709,24 +2710,28 @@ impl Session {
|
||||
}
|
||||
}
|
||||
|
||||
/// Records conversation items: append to history, persist to rollout, and
|
||||
/// notify clients observing raw response items.
|
||||
pub(crate) fn prepare_conversation_items_for_history<'a>(
|
||||
/// Prepares the history and raw-response views used when recording conversation items.
|
||||
fn prepare_conversation_items_for_recording<'a>(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
items: &'a [ResponseItem],
|
||||
) -> Cow<'a, [ResponseItem]> {
|
||||
) -> (Cow<'a, [ResponseItem]>, Option<Vec<ResponseItem>>) {
|
||||
let mut items = Cow::Borrowed(items);
|
||||
prepare_response_items(items.to_mut());
|
||||
// Most response items get their passthrough turn ID at the durable history boundary.
|
||||
for item in items.to_mut() {
|
||||
item.set_turn_id_if_missing(&turn_context.sub_id);
|
||||
}
|
||||
if turn_context.config.features.enabled(Feature::ItemIds) {
|
||||
let raw_response_items = if turn_context.config.features.enabled(Feature::ItemIds) {
|
||||
Self::assign_missing_response_item_ids(items)
|
||||
} else {
|
||||
items
|
||||
}
|
||||
};
|
||||
let history_items = response_item_history::canonicalize_for_durable_history(
|
||||
&self.thread_id,
|
||||
raw_response_items.as_ref(),
|
||||
);
|
||||
(raw_response_items, history_items)
|
||||
}
|
||||
|
||||
fn assign_missing_response_item_ids(items: Cow<'_, [ResponseItem]>) -> Cow<'_, [ResponseItem]> {
|
||||
@@ -2777,23 +2782,20 @@ impl Session {
|
||||
turn_context: &TurnContext,
|
||||
items: &[ResponseItem],
|
||||
) {
|
||||
let raw_items = self.prepare_conversation_items_for_history(turn_context, items);
|
||||
let history_items = crate::response_item_history::prepare_for_durable_history(
|
||||
&self.thread_id,
|
||||
raw_items.as_ref(),
|
||||
);
|
||||
let (raw_items, history_items) =
|
||||
self.prepare_conversation_items_for_recording(turn_context, items);
|
||||
let history_items = history_items.as_deref().unwrap_or(raw_items.as_ref());
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
state
|
||||
.current_time_reminder
|
||||
.note_recorded_items(history_items.as_ref());
|
||||
.note_recorded_items(history_items);
|
||||
state.record_items(
|
||||
history_items.iter(),
|
||||
turn_context.model_info.truncation_policy.into(),
|
||||
);
|
||||
}
|
||||
self.persist_rollout_response_items(history_items.as_ref())
|
||||
.await;
|
||||
self.persist_rollout_response_items(history_items).await;
|
||||
self.send_raw_response_items(turn_context, raw_items.as_ref())
|
||||
.await;
|
||||
}
|
||||
@@ -2885,11 +2887,11 @@ impl Session {
|
||||
) {
|
||||
communication.set_turn_id_if_missing(&turn_context.sub_id);
|
||||
let response_item = communication.to_model_input_item();
|
||||
let items = self.prepare_conversation_items_for_history(
|
||||
let (raw_items, history_items) = self.prepare_conversation_items_for_recording(
|
||||
turn_context,
|
||||
std::slice::from_ref(&response_item),
|
||||
);
|
||||
let items = items.as_ref();
|
||||
let items = history_items.as_deref().unwrap_or(raw_items.as_ref());
|
||||
let response_item = items[0].clone();
|
||||
{
|
||||
let mut state = self.state.lock().await;
|
||||
@@ -2906,7 +2908,8 @@ impl Session {
|
||||
RolloutItem::ResponseItem(response_item),
|
||||
])
|
||||
.await;
|
||||
self.send_raw_response_items(turn_context, items).await;
|
||||
self.send_raw_response_items(turn_context, raw_items.as_ref())
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn maybe_warn_on_server_model_mismatch(
|
||||
|
||||
+10
-7
@@ -2,26 +2,29 @@ use codex_protocol::ThreadId;
|
||||
use codex_protocol::models::ResponseItem;
|
||||
use codex_protocol::models::SearchToolCallParams;
|
||||
use serde::Deserialize;
|
||||
use std::borrow::Cow;
|
||||
use tracing::warn;
|
||||
|
||||
const INVALID_TOOL_SEARCH_QUERY: &str = "[invalid tool_search arguments omitted]";
|
||||
|
||||
/// Applies response-item-specific normalization before model-visible history and persistence.
|
||||
pub(super) fn prepare_for_durable_history<'a>(
|
||||
/// Returns a canonical durable-history view when an item must differ from its raw event.
|
||||
///
|
||||
/// Client-executed tool search is the only case handled here because its arguments have a fixed
|
||||
/// schema that can be safely deserialized and reserialized. Function-call arguments and custom
|
||||
/// tool input are intentionally preserved as schema-specific or freeform strings.
|
||||
pub(super) fn canonicalize_for_durable_history(
|
||||
thread_id: &ThreadId,
|
||||
items: &'a [ResponseItem],
|
||||
) -> Cow<'a, [ResponseItem]> {
|
||||
items: &[ResponseItem],
|
||||
) -> Option<Vec<ResponseItem>> {
|
||||
if !items.iter().any(|item| {
|
||||
matches!(
|
||||
item,
|
||||
ResponseItem::ToolSearchCall { execution, .. } if execution == "client"
|
||||
)
|
||||
}) {
|
||||
return Cow::Borrowed(items);
|
||||
return None;
|
||||
}
|
||||
|
||||
Cow::Owned(
|
||||
Some(
|
||||
items
|
||||
.iter()
|
||||
.filter_map(|item| {
|
||||
Reference in New Issue
Block a user