Merge fix/prepare-ergonomics — auto-gen agent-id for dogfood workflow
This commit is contained in:
commit
3095b325d2
1 changed files with 32 additions and 11 deletions
|
|
@ -18,6 +18,7 @@ use crate::role::resolve_role;
|
|||
use anyhow::{anyhow, Context, Result};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
/// Everything the orchestrator needs to hand the Claude `Agent` tool.
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
|
|
@ -41,11 +42,14 @@ pub fn prepare(task: &TaskSpec, kit_root: &Path) -> Result<AgentInvocation> {
|
|||
if task.task.role.is_empty() {
|
||||
return Err(anyhow!("task.role is empty"));
|
||||
}
|
||||
if task.task.agent_id.is_empty() {
|
||||
return Err(anyhow!(
|
||||
"task.agent-id is empty — orchestrator must allocate via kei-ledger"
|
||||
));
|
||||
}
|
||||
// Auto-generate agent-id if absent. Format: `ag-<role-slug>-<unix-ms-hex>-<4hex-rand>`
|
||||
// Orchestrator can still pre-allocate via `kei-ledger fork` and write explicit
|
||||
// agent-id into task.toml for deterministic id; auto-gen is the ergonomic default.
|
||||
let agent_id = if task.task.agent_id.is_empty() {
|
||||
autogen_agent_id(&task.task.role)
|
||||
} else {
|
||||
task.task.agent_id.clone()
|
||||
};
|
||||
let role_file = load_role_meta(kit_root, &task.task.role)?;
|
||||
if !role_file.role.spawnable {
|
||||
return Err(anyhow!(
|
||||
|
|
@ -62,12 +66,16 @@ pub fn prepare(task: &TaskSpec, kit_root: &Path) -> Result<AgentInvocation> {
|
|||
.clone()
|
||||
.unwrap_or_else(|| default_subagent_type(&task.task.role));
|
||||
let isolation = default_isolation(&task.task.role);
|
||||
let description = build_description(&task.task.role, &task.task.agent_id);
|
||||
let verify_command = build_verify_command(&task.task.agent_id);
|
||||
let ledger_row = build_ledger_row(task);
|
||||
let dna = Dna::compose(task, &resolved).render();
|
||||
let description = build_description(&task.task.role, &agent_id);
|
||||
let verify_command = build_verify_command(&agent_id);
|
||||
let ledger_row = build_ledger_row_with_id(task, &agent_id);
|
||||
// DNA uses effective agent-id; if auto-generated we inject it into a clone
|
||||
// of TaskSpec so Dna::compose sees the resolved id.
|
||||
let mut task_for_dna = task.clone();
|
||||
task_for_dna.task.agent_id = agent_id.clone();
|
||||
let dna = Dna::compose(&task_for_dna, &resolved).render();
|
||||
Ok(AgentInvocation {
|
||||
agent_id: task.task.agent_id.clone(),
|
||||
agent_id,
|
||||
role: task.task.role.clone(),
|
||||
prompt,
|
||||
subagent_type,
|
||||
|
|
@ -79,6 +87,15 @@ pub fn prepare(task: &TaskSpec, kit_root: &Path) -> Result<AgentInvocation> {
|
|||
})
|
||||
}
|
||||
|
||||
fn autogen_agent_id(role: &str) -> String {
|
||||
let ts_ms = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_millis())
|
||||
.unwrap_or(0);
|
||||
let rand_hex = format!("{:04x}", rand::random::<u16>());
|
||||
format!("ag-{}-{:x}-{}", role, ts_ms, rand_hex)
|
||||
}
|
||||
|
||||
/// Human-readable block — copy into Claude Code's Agent-tool dialog.
|
||||
pub fn render_human(inv: &AgentInvocation) -> String {
|
||||
let iso = inv.isolation.as_deref().unwrap_or("<none>");
|
||||
|
|
@ -141,6 +158,10 @@ fn build_verify_command(agent_id: &str) -> String {
|
|||
}
|
||||
|
||||
fn build_ledger_row(task: &TaskSpec) -> String {
|
||||
build_ledger_row_with_id(task, &task.task.agent_id)
|
||||
}
|
||||
|
||||
fn build_ledger_row_with_id(task: &TaskSpec, agent_id: &str) -> String {
|
||||
let parent = task
|
||||
.task
|
||||
.parent_agent
|
||||
|
|
@ -149,7 +170,7 @@ fn build_ledger_row(task: &TaskSpec) -> String {
|
|||
.unwrap_or("none");
|
||||
format!(
|
||||
"running agent-id={} role={} parent={}",
|
||||
task.task.agent_id, task.task.role, parent
|
||||
agent_id, task.task.role, parent
|
||||
)
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue