archetypes: build an archetype agent from its archetype's module on the hive
The hive reads the agent-archetype key when it provisions and rebuilds an agent and keeps it in swarm-agent-archetypes.json. For an archetype agent the meta flake has no agent-<name> input and mkAgent imports hyperhive.hyperhiveArchetypes.<name>.module; provisioning, rebuilds, the meta-input cascade, a deploy's rev and the startup migration skip the config repos. The harness gets HIVE_ARCHETYPE and the system prompt says the agent has no config repo. The create form sends the picked archetype. Adds the android-dev built-in. Refs #5386
This commit is contained in:
parent
b199c83899
commit
553ed8376c
24 changed files with 557 additions and 92 deletions
|
|
@ -230,8 +230,13 @@ pub async fn provision_container(name: &str, hive: &HiveEnv, paths: &AgentPaths)
|
|||
agent_web_port(name)
|
||||
);
|
||||
}
|
||||
setup_proposed(&paths.proposed, name).await?;
|
||||
setup_applied(&paths.applied, Some(&paths.proposed), name).await?;
|
||||
// Read before anything is seeded: an archetype agent gets no config
|
||||
// repo, and the meta render below builds it from the archetype.
|
||||
crate::archetypes::refresh(name).await?;
|
||||
if crate::archetypes::of(name)?.is_none() {
|
||||
setup_proposed(&paths.proposed, name).await?;
|
||||
setup_applied(&paths.applied, Some(&paths.proposed), name).await?;
|
||||
}
|
||||
ensure_agent_state_subvolume(name).await?;
|
||||
ensure_claude_dir(&paths.claude)?;
|
||||
ensure_state_dir(&paths.notes)?;
|
||||
|
|
@ -273,17 +278,20 @@ pub async fn prepare_rebuild_dirs(name: &str, paths: &AgentPaths) -> Result<()>
|
|||
agent_web_port(name)
|
||||
);
|
||||
}
|
||||
if !paths.applied.join(".git").exists()
|
||||
&& !crate::forge::fetch_config_main_into_applied(name).await
|
||||
{
|
||||
bail!(
|
||||
"applied repo at {} is missing its .git directory and could not be reseeded from \
|
||||
// An archetype agent has no applied repo to check or recover.
|
||||
if crate::archetypes::of(name)?.is_none() {
|
||||
if !paths.applied.join(".git").exists()
|
||||
&& !crate::forge::fetch_config_main_into_applied(name).await
|
||||
{
|
||||
bail!(
|
||||
"applied repo at {} is missing its .git directory and could not be reseeded from \
|
||||
the forge (agent-configs/{name} unreachable, has no `main` — never merged or \
|
||||
never seeded — or absent); destroy --purge and re-spawn this agent.",
|
||||
paths.applied.display()
|
||||
);
|
||||
paths.applied.display()
|
||||
);
|
||||
}
|
||||
setup_applied(&paths.applied, None, name).await?;
|
||||
}
|
||||
setup_applied(&paths.applied, None, name).await?;
|
||||
ensure_agent_state_subvolume(name).await?;
|
||||
ensure_claude_dir(&paths.claude)?;
|
||||
ensure_state_dir(&paths.notes)?;
|
||||
|
|
@ -319,12 +327,14 @@ pub async fn swap_update(
|
|||
/// handle the `Err` themselves with `.unwrap_or_default()`.
|
||||
async fn agents_for_meta(name_to_add: Option<&str>) -> Result<Vec<crate::meta::AgentSpec>> {
|
||||
let containers = list().await?;
|
||||
let archetypes = crate::archetypes::read_at(&crate::archetypes::path())?;
|
||||
let mut out: Vec<crate::meta::AgentSpec> = containers
|
||||
.into_iter()
|
||||
.filter_map(|c| {
|
||||
let name = c.strip_prefix(AGENT_PREFIX)?.to_owned();
|
||||
Some(crate::meta::AgentSpec {
|
||||
port: agent_web_port(&name),
|
||||
archetype: archetypes.get(&name).cloned(),
|
||||
name,
|
||||
})
|
||||
})
|
||||
|
|
@ -334,6 +344,7 @@ async fn agents_for_meta(name_to_add: Option<&str>) -> Result<Vec<crate::meta::A
|
|||
{
|
||||
out.push(crate::meta::AgentSpec {
|
||||
port: agent_web_port(extra),
|
||||
archetype: archetypes.get(extra).cloned(),
|
||||
name: extra.to_owned(),
|
||||
});
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue