use std::path::{Component, Path};
use crate::models::Provider;
pub(crate) const SUBAGENTS_DIR: &str = "subagents";
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct SpawnOrigin {
pub parent_session_id: String,
pub run_suffix: String,
}
impl SpawnOrigin {
pub(crate) fn session_id(&self) -> String {
format!("{}/{}", self.parent_session_id, self.run_suffix)
}
pub(crate) fn parent_link(&self, provider: Provider) -> String {
parent_link(provider, &self.parent_session_id)
}
}
pub(crate) fn parent_link(provider: Provider, parent_provider_session_id: &str) -> String {
format!("{provider}:{parent_provider_session_id}")
}
pub(crate) fn subagents_dir_origin(path: &Path) -> Option<SpawnOrigin> {
let mut parent_session_id: Option<String> = None;
let mut nested: Vec<&str> = Vec::new();
let mut previous: Option<&str> = None;
for component in path.components() {
let Component::Normal(name) = component else {
previous = None;
continue;
};
let name = name.to_str()?;
if parent_session_id.is_some() {
nested.push(name);
} else if name == SUBAGENTS_DIR {
parent_session_id = Some(previous?.to_string());
}
previous = Some(name);
}
let parent_session_id = parent_session_id?;
let file = nested.pop()?;
let stem = Path::new(file).file_stem()?.to_str()?;
nested.push(stem);
Some(SpawnOrigin {
parent_session_id,
run_suffix: nested.join("/"),
})
}
#[cfg(test)]
mod tests {
use super::*;
use std::path::PathBuf;
#[test]
fn subagents_sharing_an_agent_id_under_different_parents_stay_separate() {
let first = PathBuf::from(
"/p/-Users-x/a2f3f693-e77f-4212-9e71-2b2331565fd4/subagents/agent-a0e105ee7f1fe2c65.jsonl",
);
let second = PathBuf::from(
"/p/-Users-x/f2c5b7c7-c4bc-4ab3-bb21-7c381637b8ce/subagents/agent-a0e105ee7f1fe2c65.jsonl",
);
let first = subagents_dir_origin(&first).expect("a subagents/ path has an origin");
let second = subagents_dir_origin(&second).expect("a subagents/ path has an origin");
assert_eq!(
first.session_id(),
"a2f3f693-e77f-4212-9e71-2b2331565fd4/agent-a0e105ee7f1fe2c65",
"a run is identified by its parent plus what distinguishes it under that parent"
);
assert_eq!(
second.session_id(),
"f2c5b7c7-c4bc-4ab3-bb21-7c381637b8ce/agent-a0e105ee7f1fe2c65",
"the second run keeps its own parent; sharing an agent id must not merge the rows"
);
assert_eq!(
first.parent_session_id,
"a2f3f693-e77f-4212-9e71-2b2331565fd4"
);
assert_eq!(
second.parent_session_id,
"f2c5b7c7-c4bc-4ab3-bb21-7c381637b8ce"
);
}
#[test]
fn a_workflow_agent_keeps_the_workflow_in_its_run_suffix() {
let path = PathBuf::from(
"/p/-Users-x/77f26fc7-6ca3-4a98-a8b5-32f1963941ab/subagents/workflows/wf_4b4d88ab-f99/agent-ae4f8452cb555e0bd.jsonl",
);
let origin = subagents_dir_origin(&path).expect("nested runs have an origin too");
assert_eq!(
origin.parent_session_id,
"77f26fc7-6ca3-4a98-a8b5-32f1963941ab"
);
assert_eq!(
origin.run_suffix,
"workflows/wf_4b4d88ab-f99/agent-ae4f8452cb555e0bd"
);
}
#[test]
fn a_path_without_a_subagents_component_has_no_origin() {
let path = PathBuf::from("/p/-Users-x/7e745098-c299-4cf5-bdbe-5cdb1fb5a62d.jsonl");
assert_eq!(subagents_dir_origin(&path), None);
}
#[test]
fn a_subagents_directory_with_no_parent_before_it_has_no_origin() {
assert_eq!(
subagents_dir_origin(Path::new("subagents/agent-a068fa11.jsonl")),
None
);
assert_eq!(
subagents_dir_origin(Path::new("/subagents/agent-a068fa11.jsonl")),
None
);
}
#[test]
fn a_subagents_directory_with_no_file_under_it_has_no_origin() {
assert_eq!(
subagents_dir_origin(Path::new("/p/-Users-x/7e745098/subagents")),
None
);
}
}