Use the live parent history mode when forking agents (#34779)

## What changed

- Require the parent thread to be live before forking its history.
- Read the history mode and multi-agent usage hints from that live parent so
  the fork loads and filters history using the active configuration.
- Verify that forking a legacy parent keeps the child in legacy history mode.

GitOrigin-RevId: 79416b78544467a1801f21300d3fe8db4fef59df
This commit is contained in:
Owen Lin
2026-07-22 16:05:52 +00:00
committed by copyberry
parent ff8d521ba1
commit c5779ed6bb
2 changed files with 23 additions and 40 deletions

View File

@@ -594,26 +594,17 @@ impl AgentControl {
};
let parent_thread_id = *parent_thread_id;
let parent_thread = state.get_thread(parent_thread_id).await.ok();
if let Some(parent_thread) = parent_thread.as_ref() {
// `record_conversation_items` only queues persistence writes asynchronously.
// Flush before snapshotting store history for a fork.
parent_thread.ensure_rollout_materialized().await;
parent_thread.flush_rollout().await?;
}
let parent_metadata = state
.read_stored_thread(ReadThreadParams {
thread_id: parent_thread_id,
include_archived: true,
include_history: false,
})
.await?;
let parent_thread = state.get_thread(parent_thread_id).await?;
let parent_history_mode = parent_thread.config_snapshot().await.history_mode;
// `record_conversation_items` only queues persistence writes asynchronously.
// Flush before snapshotting store history for a fork.
parent_thread.ensure_rollout_materialized().await;
parent_thread.flush_rollout().await?;
let destination_history_mode =
matches!(parent_metadata.history_mode, ThreadHistoryMode::Paginated)
.then_some(ThreadHistoryMode::Paginated);
let destination_history_mode = matches!(parent_history_mode, ThreadHistoryMode::Paginated)
.then_some(ThreadHistoryMode::Paginated);
let mut forked_rollout_items =
load_agent_model_context(state, parent_thread_id, parent_metadata.history_mode)
load_agent_model_context(state, parent_thread_id, parent_history_mode)
.await?
.ok_or_else(|| {
CodexErr::Fatal(format!(
@@ -635,29 +626,17 @@ impl AgentControl {
truncate_rollout_to_last_n_fork_turns(&forked_rollout_items, *last_n_turns);
}
let multi_agent_v2_usage_hint_texts_to_filter: Vec<String> =
if let Some(parent_thread) = parent_thread.as_ref() {
if multi_agent_version == MultiAgentVersion::V2 {
let parent_config = parent_thread.session.get_config().await;
[
parent_config
.multi_agent_v2
.root_agent_usage_hint_text
.clone(),
parent_config
.multi_agent_v2
.subagent_usage_hint_text
.clone(),
]
.into_iter()
.flatten()
.collect()
} else {
Vec::new()
}
} else if multi_agent_version == MultiAgentVersion::V2 {
if multi_agent_version == MultiAgentVersion::V2 {
let parent_config = parent_thread.session.get_config().await;
[
config.multi_agent_v2.root_agent_usage_hint_text.clone(),
config.multi_agent_v2.subagent_usage_hint_text.clone(),
parent_config
.multi_agent_v2
.root_agent_usage_hint_text
.clone(),
parent_config
.multi_agent_v2
.subagent_usage_hint_text
.clone(),
]
.into_iter()
.flatten()

View File

@@ -1323,6 +1323,10 @@ async fn spawn_agent_can_fork_parent_thread_history_with_sanitized_items() {
.await
.expect("child thread should be registered");
assert_ne!(child_thread_id, parent_thread_id);
assert_eq!(
child_thread.config_snapshot().await.history_mode,
ThreadHistoryMode::Legacy
);
let history = child_thread.session.clone_history().await;
let mut expected_final_answer =
assistant_message("parent final answer", Some(MessagePhase::FinalAnswer));