Count Codex background terminals

This commit is contained in:
iris-ai committed 2026-09-16 01:07:40 -04:00
1 parent cbae7ee8c0
commit 827a30768c
5 files changed
+361 -35

No files matched your search

+37 -18
View File
@@ -5,7 +5,7 @@
//! ignore the rest; an added Codex item must not make a live session go deaf.
use std::collections::{HashMap, HashSet};
use std::sync::Arc;
use std::sync::{Arc, Mutex};
use serde_json::{Value, json};
@@ -18,6 +18,7 @@ pub(super) struct Translator {
completed: bool,
limited: bool,
subagents: Option<Arc<Subagents>>,
background_processes: Option<Arc<Mutex<HashSet<String>>>>,
children: HashMap<String, Translator>,
prompts: HashMap<String, String>,
async_messages: HashSet<String>,
@@ -25,10 +26,16 @@ pub(super) struct Translator {
}
impl Translator {
pub(super) fn new(subagents: Arc<Subagents>, thread_id: Option<String>, in_turn: bool) -> Self {
pub(super) fn new(
subagents: Arc<Subagents>,
background_processes: Arc<Mutex<HashSet<String>>>,
thread_id: Option<String>,
in_turn: bool,
) -> Self {
Self {
thread_id,
subagents: Some(subagents),
background_processes: Some(background_processes),
in_turn,
..Self::default()
}
@@ -118,9 +125,14 @@ impl Translator {
}
fn background_task_count(&self) -> Option<usize> {
self.subagents
.as_ref()
.map(|subagents| subagents.open_count())
self.subagents.as_ref().map(|subagents| {
subagents.open_count()
+ self
.background_processes
.as_ref()
.map(|processes| processes.lock().unwrap().len())
.unwrap_or(0)
})
}
fn translate_line(&mut self, kind: Option<&str>, body: &Value, line: &Value) -> Vec<Event> {
@@ -242,11 +254,7 @@ impl Translator {
events.extend(self.failure(error));
}
events.push(Event::Status {
state: if self
.subagents
.as_ref()
.is_some_and(|subagents| subagents.any_open(true))
{
state: if self.background_task_count().is_some_and(|count| count > 0) {
SessionStatus::Waiting
} else {
SessionStatus::Idle
@@ -390,13 +398,7 @@ impl Translator {
subagents.finish(id);
}
self.prompts.remove(id);
if was_open
&& !self.in_turn
&& self
.subagents
.as_ref()
.is_some_and(|subagents| !subagents.any_open(true))
{
if was_open && !self.in_turn && self.background_task_count() == Some(0) {
vec![Event::Status {
state: SessionStatus::Idle,
}]
@@ -1216,8 +1218,10 @@ mod tests {
fn codex_subagents_get_their_own_transcripts_and_hold_the_parent_waiting() {
let dir = tempfile::tempdir().expect("tempdir");
let subagents = Arc::new(Subagents::new(dir.path().to_path_buf()));
let background_processes = Arc::new(Mutex::new(HashSet::new()));
let mut translator = Translator::new(
Arc::clone(&subagents),
Arc::clone(&background_processes),
Some("parent-thread".to_string()),
false,
);
@@ -1313,8 +1317,10 @@ mod tests {
fn codex_reports_each_change_to_its_live_background_count() {
let dir = tempfile::tempdir().expect("tempdir");
let subagents = Arc::new(Subagents::new(dir.path().to_path_buf()));
let background_processes = Arc::new(Mutex::new(HashSet::new()));
let mut translator = Translator::new(
Arc::clone(&subagents),
Arc::clone(&background_processes),
Some("parent-thread".to_string()),
false,
);
@@ -1335,7 +1341,11 @@ mod tests {
}));
assert_eq!(events.last(), Some(&Event::BackgroundTasks { count }));
}
for (child, count) in [("child-a", 1), ("child-b", 0)] {
background_processes
.lock()
.unwrap()
.insert("command-a".to_string());
for (child, count) in [("child-a", 2), ("child-b", 1)] {
let events = translator.translate(&json!({
"method": "item/completed",
"params": {
@@ -1350,6 +1360,14 @@ mod tests {
}
}));
assert_eq!(events.last(), Some(&Event::BackgroundTasks { count }));
assert!(!events.iter().any(|event| {
matches!(
event,
Event::Status {
state: SessionStatus::Idle
}
)
}));
}
}
@@ -1490,6 +1508,7 @@ mod tests {
subagents.start("child-thread", "child", Some("work"));
let mut translator = Translator::new(
Arc::clone(&subagents),
Arc::new(Mutex::new(HashSet::new())),
Some("parent-thread".to_string()),
true,
);