Simplify turn metadata state ownership (#36727)

## What changed

- Store synchronization primitives directly in `TurnMetadataState` instead of
  wrapping each field in its own `Arc`.
- Require an `Arc<TurnMetadataState>` when spawning Git enrichment so the
  background task retains the complete state.
- Update Git enrichment tests to use the shared state container.

GitOrigin-RevId: 745ca6504c0a6533cb7726d045905472e51726df
This commit is contained in:
jif
2026-08-03 10:14:34 +00:00
committed by copyberry
parent 1b594980f3
commit dae2122214
2 changed files with 21 additions and 21 deletions
+15 -15
View File
@@ -86,7 +86,7 @@ pub async fn detached_memory_responses_metadata(
}
}
#[derive(Clone, Debug)]
#[derive(Debug)]
pub(crate) struct TurnMetadataState {
cwd: AbsolutePathBuf,
repo_root: Option<String>,
@@ -100,12 +100,12 @@ pub(crate) struct TurnMetadataState {
thread_source: Option<ThreadSource>,
turn_id: String,
sandbox: Option<String>,
enriched_workspaces: Arc<RwLock<Option<BTreeMap<String, TurnMetadataWorkspace>>>>,
code_mode_tool_names: Arc<RwLock<Option<BTreeMap<String, ToolName>>>>,
turn_started_at_unix_ms: Arc<RwLock<Option<i64>>>,
responsesapi_client_metadata: Arc<RwLock<BTreeMap<String, String>>>,
user_input_requested_during_turn: Arc<AtomicBool>,
enrichment_task: Arc<Mutex<Option<JoinHandle<()>>>>,
enriched_workspaces: RwLock<Option<BTreeMap<String, TurnMetadataWorkspace>>>,
code_mode_tool_names: RwLock<Option<BTreeMap<String, ToolName>>>,
turn_started_at_unix_ms: RwLock<Option<i64>>,
responsesapi_client_metadata: RwLock<BTreeMap<String, String>>,
user_input_requested_during_turn: AtomicBool,
enrichment_task: Mutex<Option<JoinHandle<()>>>,
}
impl TurnMetadataState {
@@ -145,12 +145,12 @@ impl TurnMetadataState {
thread_source,
turn_id,
sandbox,
enriched_workspaces: Arc::new(RwLock::new(None)),
code_mode_tool_names: Arc::new(RwLock::new(None)),
turn_started_at_unix_ms: Arc::new(RwLock::new(None)),
responsesapi_client_metadata: Arc::new(RwLock::new(BTreeMap::new())),
user_input_requested_during_turn: Arc::new(AtomicBool::new(false)),
enrichment_task: Arc::new(Mutex::new(None)),
enriched_workspaces: RwLock::new(None),
code_mode_tool_names: RwLock::new(None),
turn_started_at_unix_ms: RwLock::new(None),
responsesapi_client_metadata: RwLock::new(BTreeMap::new()),
user_input_requested_during_turn: AtomicBool::new(false),
enrichment_task: Mutex::new(None),
}
}
@@ -303,7 +303,7 @@ impl TurnMetadataState {
.unwrap_or_else(std::sync::PoisonError::into_inner) = Some(turn_started_at_unix_ms);
}
pub(crate) fn spawn_git_enrichment_task(&self) {
pub(crate) fn spawn_git_enrichment_task(self: &Arc<Self>) {
if self.repo_root.is_none() {
return;
}
@@ -316,7 +316,7 @@ impl TurnMetadataState {
return;
}
let state = self.clone();
let state = Arc::clone(self);
*task_guard = Some(tokio::spawn(async move {
let workspace_git_metadata = state.fetch_workspace_git_metadata().await;
let Some(repo_root) = state.repo_root.clone() else {
+6 -6
View File
@@ -800,7 +800,7 @@ async fn turn_metadata_state_preserves_lineage_after_git_enrichment() {
let permission_profile = PermissionProfile::read_only();
let parent_thread_id =
ThreadId::from_string("66666666-6666-4666-8666-666666666666").expect("thread id");
let state = TurnMetadataState::new(
let state = Arc::new(TurnMetadataState::new(
"session-a".to_string(),
"thread-a".to_string(),
Some(parent_thread_id),
@@ -818,7 +818,7 @@ async fn turn_metadata_state_preserves_lineage_after_git_enrichment() {
&permission_profile,
WindowsSandboxLevel::Disabled,
/*enforce_managed_network*/ false,
);
));
state.spawn_git_enrichment_task();
let json = wait_for_git_enrichment(&state).await;
@@ -901,7 +901,7 @@ async fn turn_metadata_state_coalesces_concurrent_git_enrichment() {
async fn turn_metadata_state_git_enrichment_cancellation_is_retryable_and_errors_stay_empty() {
let (_temp_dir, repo_path) = create_clean_git_repo("repo").await;
let permission_profile = PermissionProfile::read_only();
let state = TurnMetadataState::new(
let state = Arc::new(TurnMetadataState::new(
"session-a".to_string(),
"thread-a".to_string(),
/*forked_from_thread_id*/ None,
@@ -913,7 +913,7 @@ async fn turn_metadata_state_git_enrichment_cancellation_is_retryable_and_errors
&permission_profile,
WindowsSandboxLevel::Disabled,
/*enforce_managed_network*/ false,
);
));
state.spawn_git_enrichment_task();
state.cancel_git_enrichment_task();
assert!(
@@ -934,7 +934,7 @@ async fn turn_metadata_state_git_enrichment_cancellation_is_retryable_and_errors
let invalid_repo = TempDir::new().expect("invalid repo");
std::fs::create_dir(invalid_repo.path().join(".git")).expect("invalid git directory");
let invalid_state = TurnMetadataState::new(
let invalid_state = Arc::new(TurnMetadataState::new(
"session-a".to_string(),
"thread-a".to_string(),
/*forked_from_thread_id*/ None,
@@ -946,7 +946,7 @@ async fn turn_metadata_state_git_enrichment_cancellation_is_retryable_and_errors
&permission_profile,
WindowsSandboxLevel::Disabled,
/*enforce_managed_network*/ false,
);
));
invalid_state.spawn_git_enrichment_task();
tokio::time::timeout(Duration::from_secs(2), async {
loop {