huskies: merge 1015

This commit is contained in:
dave
2026-05-13 23:33:30 +00:00
parent 69b207872a
commit 5ed1438ab9
22 changed files with 227 additions and 73 deletions
+6 -5
View File
@@ -4,6 +4,7 @@
pub mod agent_name;
pub use agent_name::AgentName;
use crate::agents::AgentModel;
use crate::slog;
use serde::Deserialize;
use std::collections::HashSet;
@@ -22,12 +23,12 @@ pub struct ProjectConfig {
/// Per-story `qa` front matter overrides this. Default: "server".
#[serde(default = "default_qa")]
pub default_qa: String,
/// Default model for coder-stage agents (e.g. "sonnet").
/// Default model for coder-stage agents (e.g. `Sonnet`).
/// When set, `find_free_agent_for_stage` only considers coder agents whose
/// model matches this value, so opus agents are only used when explicitly
/// requested via story front matter `agent:` field.
#[serde(default)]
pub default_coder_model: Option<String>,
pub default_coder_model: Option<AgentModel>,
/// Maximum number of concurrent coder-stage agents.
/// When set, `auto_assign_available_work` will not start more than this many
/// coder agents at once. Stories wait in `2_current/` until a slot frees up.
@@ -240,7 +241,7 @@ pub struct AgentConfig {
#[serde(default = "default_agent_prompt")]
pub prompt: String,
#[serde(default)]
pub model: Option<String>,
pub model: Option<AgentModel>,
#[serde(default)]
pub allowed_tools: Option<Vec<String>>,
#[serde(default)]
@@ -312,7 +313,7 @@ struct LegacyProjectConfig {
#[serde(default = "default_qa")]
default_qa: String,
#[serde(default)]
default_coder_model: Option<String>,
default_coder_model: Option<AgentModel>,
#[serde(default)]
max_coders: Option<usize>,
#[serde(default = "default_max_retries")]
@@ -583,7 +584,7 @@ impl ProjectConfig {
// Append structured CLI flags
if let Some(ref model) = agent.model {
args.push("--model".to_string());
args.push(model.clone());
args.push(model.as_str().to_string());
}
if let Some(ref tools) = agent.allowed_tools
&& !tools.is_empty()
+22 -7
View File
@@ -39,7 +39,7 @@ max_budget_usd = 5.00
assert_eq!(config.agent.len(), 2);
assert_eq!(config.agent[0].name, "supervisor");
assert_eq!(config.agent[0].role, "Coordinates work");
assert_eq!(config.agent[0].model, Some("opus".to_string()));
assert_eq!(config.agent[0].model, Some(crate::agents::AgentModel::Opus));
assert_eq!(config.agent[0].max_turns, Some(50));
assert_eq!(config.agent[0].max_budget_usd, Some(10.0));
assert_eq!(
@@ -47,7 +47,10 @@ max_budget_usd = 5.00
Some("You are a senior engineer".to_string())
);
assert_eq!(config.agent[1].name, "coder-1");
assert_eq!(config.agent[1].model, Some("sonnet".to_string()));
assert_eq!(
config.agent[1].model,
Some(crate::agents::AgentModel::Sonnet)
);
assert_eq!(config.component.len(), 1);
}
@@ -237,7 +240,10 @@ model = "sonnet"
assert_eq!(config.component[1].setup, vec!["pnpm install"]);
assert_eq!(config.agent.len(), 1);
assert_eq!(config.agent[0].name, "main");
assert_eq!(config.agent[0].model, Some("sonnet".to_string()));
assert_eq!(
config.agent[0].model,
Some(crate::agents::AgentModel::Sonnet)
);
}
#[test]
@@ -269,7 +275,7 @@ model = "opus"
let config = ProjectConfig::load(tmp.path()).unwrap();
assert_eq!(config.agent.len(), 1);
assert_eq!(config.agent[0].name, "from-agents-toml");
assert_eq!(config.agent[0].model, Some("opus".to_string()));
assert_eq!(config.agent[0].model, Some(crate::agents::AgentModel::Opus));
}
#[test]
@@ -438,7 +444,10 @@ stage = "coder"
model = "opus"
"#;
let config = ProjectConfig::parse(toml_str).unwrap();
assert_eq!(config.default_coder_model, Some("sonnet".to_string()));
assert_eq!(
config.default_coder_model,
Some(crate::agents::AgentModel::Sonnet)
);
assert_eq!(config.max_coders, Some(3));
}
@@ -459,7 +468,10 @@ fn project_toml_has_default_coder_model_and_max_coders() {
let manifest_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"));
let project_root = manifest_dir.parent().unwrap();
let config = ProjectConfig::load(project_root).unwrap();
assert_eq!(config.default_coder_model, Some("sonnet".to_string()));
assert_eq!(
config.default_coder_model,
Some(crate::agents::AgentModel::Sonnet)
);
assert_eq!(config.max_coders, Some(3));
}
@@ -617,7 +629,10 @@ fn project_toml_has_three_sonnet_coders() {
let sonnet_coders: Vec<_> = config
.agent
.iter()
.filter(|a| a.stage.as_deref() == Some("coder") && a.model.as_deref() == Some("sonnet"))
.filter(|a| {
a.stage.as_deref() == Some("coder")
&& a.model.as_ref() == Some(&crate::agents::AgentModel::Sonnet)
})
.collect();
assert_eq!(