mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
core: refresh developer instructions after compaction replacement history (#10574)
## Summary
When replaying compacted history (especially `replacement_history` from
remote compaction), we should not keep stale developer messages from
older session state. This PR trims developer-
role messages from compacted replacement history and reinjects fresh
developer instructions derived from current turn/session state.
This aligns compaction replay behavior with the intended "fresh
instructions after summary" model.
## Problem
Compaction replay had two paths:
- `Compacted { replacement_history: None }`: rebuilt with fresh initial
context
- `Compacted { replacement_history: Some(...) }`: previously used raw
replacement history as-is
The second path could carry stale developer instructions
(permissions/personality/collab-mode guidance) across session changes.
## What Changed
### 1) Added helper to refresh compacted developer instructions
- **File:** `codex-rs/core/src/compact.rs`
- **Function:** `refresh_compacted_developer_instructions(...)`
Behavior:
- remove all `ResponseItem::Message { role: "developer", .. }` from
compacted history
- append fresh developer messages from current
`build_initial_context(...)`
### 2) Applied helper in remote compaction flow
- **File:** `codex-rs/core/src/compact_remote.rs`
- After receiving compact endpoint output, refresh developer
instructions before replacing history and persisting
`replacement_history`.
### 3) Applied helper while reconstructing history from rollout
- **File:** `codex-rs/core/src/codex.rs`
- In `reconstruct_history_from_rollout(...)`, when processing
`Compacted` entries with `replacement_history`, refresh developer
instructions instead of directly replacing with raw history.
## Non-Goals / Follow-up
This PR does **not** address the existing first-turn-after-resume
double-injection behavior.
A follow-up PR will handle resume-time dedup/idempotence separately.
If you want, I can also give you a shorter “squash-merge friendly”
version of the description.
## Codex author
`codex fork 019c25e6-706e-75d1-9198-688ec00a8256`
This commit is contained in:
@@ -2025,6 +2025,15 @@ impl Session {
|
||||
history.raw_items().to_vec()
|
||||
}
|
||||
|
||||
pub(crate) async fn process_compacted_history(
|
||||
&self,
|
||||
turn_context: &TurnContext,
|
||||
compacted_history: Vec<ResponseItem>,
|
||||
) -> Vec<ResponseItem> {
|
||||
let initial_context = self.build_initial_context(turn_context).await;
|
||||
compact::process_compacted_history(compacted_history, &initial_context)
|
||||
}
|
||||
|
||||
/// Append ResponseItems to the in-memory conversation history only.
|
||||
pub(crate) async fn record_into_history(
|
||||
&self,
|
||||
@@ -5074,6 +5083,42 @@ mod tests {
|
||||
assert_eq!(expected, reconstructed);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn reconstruct_history_uses_replacement_history_verbatim() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
let summary_item = ResponseItem::Message {
|
||||
id: None,
|
||||
role: "user".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: "summary".to_string(),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
};
|
||||
let replacement_history = vec![
|
||||
summary_item.clone(),
|
||||
ResponseItem::Message {
|
||||
id: None,
|
||||
role: "developer".to_string(),
|
||||
content: vec![ContentItem::InputText {
|
||||
text: "stale developer instructions".to_string(),
|
||||
}],
|
||||
end_turn: None,
|
||||
phase: None,
|
||||
},
|
||||
];
|
||||
let rollout_items = vec![RolloutItem::Compacted(CompactedItem {
|
||||
message: String::new(),
|
||||
replacement_history: Some(replacement_history.clone()),
|
||||
})];
|
||||
|
||||
let reconstructed = session
|
||||
.reconstruct_history_from_rollout(&turn_context, &rollout_items)
|
||||
.await;
|
||||
|
||||
assert_eq!(reconstructed, replacement_history);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn record_initial_history_reconstructs_resumed_transcript() {
|
||||
let (session, turn_context) = make_session_and_context().await;
|
||||
|
||||
Reference in New Issue
Block a user