feat: preserve custom ecc2 harness labels

This commit is contained in:
Affaan Mustafa 2026-04-10 08:57:59 -07:00
parent bcd869d520
commit 4a1f3cbd3f
5 changed files with 172 additions and 26 deletions

View File

@ -1230,8 +1230,8 @@ async fn main() -> Result<()> {
for s in sessions {
let harness = harnesses
.get(&s.id)
.map(|info| info.primary.to_string())
.unwrap_or_else(|| "unknown".to_string());
.map(|info| info.primary_label.clone())
.unwrap_or_else(|| session::SessionHarnessInfo::runner_key(&s.agent_type));
println!("{} [{}] [{}] {}", s.id, s.state, harness, s.task);
}
}

View File

@ -2004,10 +2004,11 @@ pub async fn delete_session(db: &StateStore, id: &str) -> Result<()> {
fn agent_program(cfg: &Config, agent_type: &str) -> Result<PathBuf> {
let harness = HarnessKind::from_agent_type(agent_type);
if let Some(runner) = cfg.harness_runner(harness.as_str()) {
let runner_key = SessionHarnessInfo::runner_key(agent_type);
if let Some(runner) = cfg.harness_runner(&runner_key) {
let program = runner.program.trim();
if program.is_empty() {
anyhow::bail!("Configured harness runner for {harness} is missing a program");
anyhow::bail!("Configured harness runner for {runner_key} is missing a program");
}
return Ok(PathBuf::from(program));
}
@ -2685,7 +2686,7 @@ fn build_agent_command(
profile: Option<&SessionAgentProfile>,
) -> Command {
let harness = HarnessKind::from_agent_type(agent_type);
if let Some(runner) = cfg.harness_runner(harness.as_str()) {
if let Some(runner) = cfg.harness_runner(&SessionHarnessInfo::runner_key(agent_type)) {
return build_configured_harness_command(
runner,
agent_program,
@ -3327,7 +3328,7 @@ impl fmt::Display for SessionStatus {
writeln!(f, "Session: {}", s.id)?;
writeln!(f, "Task: {}", s.task)?;
writeln!(f, "Agent: {}", s.agent_type)?;
writeln!(f, "Harness: {}", self.harness.primary)?;
writeln!(f, "Harness: {}", self.harness.primary_label)?;
writeln!(f, "Detected: {}", self.harness.detected_summary())?;
writeln!(f, "State: {}", s.state)?;
if let Some(profile) = self.profile.as_ref() {
@ -3880,6 +3881,24 @@ mod tests {
Ok(())
}
#[test]
fn agent_program_uses_configured_runner_for_unknown_custom_harness() -> Result<()> {
let mut cfg = Config::default();
cfg.harness_runners.insert(
"acme-runner".to_string(),
crate::config::HarnessRunnerConfig {
program: "acme-agent".to_string(),
..Default::default()
},
);
assert_eq!(
agent_program(&cfg, "acme-runner")?,
PathBuf::from("acme-agent")
);
Ok(())
}
#[test]
fn build_agent_command_uses_configured_runner_for_cursor() {
let mut cfg = Config::default();

View File

@ -109,11 +109,38 @@ impl fmt::Display for HarnessKind {
#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
pub struct SessionHarnessInfo {
pub primary: HarnessKind,
pub primary_label: String,
pub detected: Vec<HarnessKind>,
}
impl SessionHarnessInfo {
pub fn runner_key(agent_type: &str) -> String {
let canonical = HarnessKind::canonical_agent_type(agent_type);
match HarnessKind::from_agent_type(&canonical) {
HarnessKind::Unknown if canonical.is_empty() => {
HarnessKind::Unknown.as_str().to_string()
}
HarnessKind::Unknown => canonical,
harness => harness.as_str().to_string(),
}
}
fn primary_label_for(agent_type: &str, primary: HarnessKind) -> String {
match primary {
HarnessKind::Unknown => {
let label = Self::runner_key(agent_type);
if label.is_empty() {
HarnessKind::Unknown.as_str().to_string()
} else {
label
}
}
harness => harness.as_str().to_string(),
}
}
pub fn detect(agent_type: &str, working_dir: &Path) -> Self {
let runner_key = Self::runner_key(agent_type);
let detected = [
HarnessKind::Claude,
HarnessKind::Codex,
@ -132,12 +159,43 @@ impl SessionHarnessInfo {
})
.collect::<Vec<_>>();
let primary = match HarnessKind::from_agent_type(agent_type) {
HarnessKind::Unknown => detected.first().copied().unwrap_or(HarnessKind::Unknown),
let primary = match HarnessKind::from_agent_type(&runner_key) {
HarnessKind::Unknown if runner_key == HarnessKind::Unknown.as_str() => {
detected.first().copied().unwrap_or(HarnessKind::Unknown)
}
HarnessKind::Unknown => HarnessKind::Unknown,
harness => harness,
};
Self { primary, detected }
Self {
primary,
primary_label: Self::primary_label_for(agent_type, primary),
detected,
}
}
pub fn from_persisted(
harness_label: &str,
agent_type: &str,
working_dir: &Path,
detected: Vec<HarnessKind>,
) -> Self {
let primary = HarnessKind::from_db_value(harness_label);
if primary == HarnessKind::Unknown && detected.is_empty() && harness_label.trim().is_empty()
{
return Self::detect(agent_type, working_dir);
}
let normalized_label = harness_label.trim().to_ascii_lowercase();
Self {
primary,
primary_label: if normalized_label.is_empty() {
Self::primary_label_for(agent_type, primary)
} else {
normalized_label
},
detected,
}
}
pub fn detected_summary(&self) -> String {
@ -510,6 +568,7 @@ mod tests {
let harness = SessionHarnessInfo::detect("claude", repo.path());
assert_eq!(harness.primary, HarnessKind::Claude);
assert_eq!(harness.primary_label, "claude");
assert_eq!(
harness.detected,
vec![HarnessKind::Claude, HarnessKind::Codex]
@ -519,13 +578,14 @@ mod tests {
}
#[test]
fn detect_session_harness_falls_back_to_project_markers_for_unknown_agent(
fn detect_session_harness_falls_back_to_project_markers_when_agent_unspecified(
) -> Result<(), Box<dyn std::error::Error>> {
let repo = TestDir::new("session-harness-markers")?;
fs::create_dir_all(repo.path().join(".gemini"))?;
let harness = SessionHarnessInfo::detect("custom-runner", repo.path());
let harness = SessionHarnessInfo::detect("", repo.path());
assert_eq!(harness.primary, HarnessKind::Gemini);
assert_eq!(harness.primary_label, "gemini");
assert_eq!(harness.detected, vec![HarnessKind::Gemini]);
Ok(())
}
@ -543,4 +603,38 @@ mod tests {
"custom-runner"
);
}
#[test]
fn detect_session_harness_preserves_custom_agent_label_without_markers() {
let harness = SessionHarnessInfo::detect(" custom-runner ", Path::new("."));
assert_eq!(harness.primary, HarnessKind::Unknown);
assert_eq!(harness.primary_label, "custom-runner");
assert!(harness.detected.is_empty());
}
#[test]
fn detect_session_harness_preserves_custom_agent_label_with_project_markers(
) -> Result<(), Box<dyn std::error::Error>> {
let repo = TestDir::new("session-harness-custom-markers")?;
fs::create_dir_all(repo.path().join(".claude"))?;
fs::create_dir_all(repo.path().join(".codex"))?;
let harness = SessionHarnessInfo::detect("custom-runner", repo.path());
assert_eq!(harness.primary, HarnessKind::Unknown);
assert_eq!(harness.primary_label, "custom-runner");
assert_eq!(
harness.detected,
vec![HarnessKind::Claude, HarnessKind::Codex]
);
Ok(())
}
#[test]
fn runner_key_uses_canonical_label_for_unknown_harnesses() {
assert_eq!(
SessionHarnessInfo::runner_key(" custom-runner "),
"custom-runner"
);
assert_eq!(SessionHarnessInfo::runner_key("claude-code"), "claude");
}
}

View File

@ -706,7 +706,7 @@ impl StateStore {
rusqlite::params![
session_id,
canonical_agent_type,
harness.primary.to_string(),
harness.primary_label,
detected_json
],
)?;
@ -728,7 +728,7 @@ impl StateStore {
session.project,
session.task_group,
session.agent_type,
harness.primary.to_string(),
harness.primary_label,
detected_json,
session.working_dir.to_string_lossy().to_string(),
session.state.to_string(),
@ -1763,16 +1763,17 @@ impl StateStore {
let harnesses = stmt
.query_map([], |row| {
let session_id: String = row.get(0)?;
let primary = HarnessKind::from_db_value(&row.get::<_, String>(1)?);
let harness_label: String = row.get(1)?;
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(2)?)
.unwrap_or_default();
let agent_type: String = row.get(3)?;
let working_dir = PathBuf::from(row.get::<_, String>(4)?);
let info = if primary == HarnessKind::Unknown && detected.is_empty() {
SessionHarnessInfo::detect(&agent_type, &working_dir)
} else {
SessionHarnessInfo { primary, detected }
};
let info = SessionHarnessInfo::from_persisted(
&harness_label,
&agent_type,
&working_dir,
detected,
);
Ok((session_id, info))
})?
.collect::<std::result::Result<HashMap<_, _>, _>>()?;
@ -1788,16 +1789,17 @@ impl StateStore {
)?;
stmt.query_row([session_id], |row| {
let primary = HarnessKind::from_db_value(&row.get::<_, String>(0)?);
let harness_label: String = row.get(0)?;
let detected = serde_json::from_str::<Vec<HarnessKind>>(&row.get::<_, String>(1)?)
.unwrap_or_default();
let agent_type: String = row.get(2)?;
let working_dir = PathBuf::from(row.get::<_, String>(3)?);
let info = if primary == HarnessKind::Unknown && detected.is_empty() {
SessionHarnessInfo::detect(&agent_type, &working_dir)
} else {
SessionHarnessInfo { primary, detected }
};
let info = SessionHarnessInfo::from_persisted(
&harness_label,
&agent_type,
&working_dir,
detected,
);
Ok(info)
})
.optional()
@ -4191,10 +4193,41 @@ mod tests {
.get_session_harness_info("sess-legacy")?
.expect("legacy row should be backfilled");
assert_eq!(harness.primary, HarnessKind::Gemini);
assert_eq!(harness.primary_label, "gemini");
assert_eq!(harness.detected, vec![HarnessKind::Codex]);
Ok(())
}
#[test]
fn insert_session_preserves_custom_harness_label_for_unknown_agent_types() -> Result<()> {
let tempdir = TestDir::new("store-custom-harness-label")?;
let db = StateStore::open(&tempdir.path().join("state.db"))?;
let now = Utc::now();
db.insert_session(&Session {
id: "sess-custom".to_string(),
task: "Run custom harness".to_string(),
project: "ecc".to_string(),
task_group: "compat".to_string(),
agent_type: "acme-runner".to_string(),
working_dir: PathBuf::from(tempdir.path()),
state: SessionState::Pending,
pid: None,
worktree: None,
created_at: now,
updated_at: now,
last_heartbeat_at: now,
metrics: SessionMetrics::default(),
})?;
let harness = db
.get_session_harness_info("sess-custom")?
.expect("custom session should have harness info");
assert_eq!(harness.primary, HarnessKind::Unknown);
assert_eq!(harness.primary_label, "acme-runner");
Ok(())
}
#[test]
fn session_profile_round_trips_with_launch_settings() -> Result<()> {
let tempdir = TestDir::new("store-session-profile")?;

View File

@ -6347,7 +6347,7 @@ impl Dashboard {
if let Some(harness) = self.session_harnesses.get(&session.id) {
lines.push(format!(
"Harness {} | Detected {}",
harness.primary,
harness.primary_label,
harness.detected_summary()
));
}