mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-09 22:33:37 +00:00
Simplify -v flag from two verbosity levels to a single boolean
The `-vv` (full detail) mode was not useful in practice. This collapses the two-tier `-v`/`-vv` into a single `--verbose` boolean and removes the now-dead `format_event_detail` function and its tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
1fa26aa1ec
commit
effe165f31
5 changed files with 16 additions and 439 deletions
|
|
@ -106,7 +106,7 @@ pub async fn serve_command(args: ServeArgs, styles: &'static Styles) -> anyhow::
|
|||
Some(Box::new(AgentApiBackend::new(
|
||||
model.clone(),
|
||||
provider_enum,
|
||||
0,
|
||||
false,
|
||||
styles,
|
||||
)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,14 +25,14 @@ use crate::outcome::StageUsage;
|
|||
pub struct AgentApiBackend {
|
||||
model: String,
|
||||
provider: Provider,
|
||||
verbose: u8,
|
||||
verbose: bool,
|
||||
styles: &'static Styles,
|
||||
sessions: Mutex<HashMap<String, Session>>,
|
||||
}
|
||||
|
||||
impl AgentApiBackend {
|
||||
#[must_use]
|
||||
pub fn new(model: String, provider: Provider, verbose: u8, styles: &'static Styles) -> Self {
|
||||
pub fn new(model: String, provider: Provider, verbose: bool, styles: &'static Styles) -> Self {
|
||||
Self {
|
||||
model,
|
||||
provider,
|
||||
|
|
@ -283,7 +283,7 @@ impl CodergenBackend for AgentApiBackend {
|
|||
}
|
||||
|
||||
// Verbose stderr printing (gated on verbosity)
|
||||
if verbose >= 1 {
|
||||
if verbose {
|
||||
match &event.event {
|
||||
AgentEvent::ToolCallStarted {
|
||||
tool_name,
|
||||
|
|
@ -299,21 +299,6 @@ impl CodergenBackend for AgentApiBackend {
|
|||
args = format_tool_args(arguments),
|
||||
);
|
||||
}
|
||||
AgentEvent::ToolCallCompleted {
|
||||
tool_name,
|
||||
output,
|
||||
is_error,
|
||||
..
|
||||
} if verbose >= 2 => {
|
||||
let label = if *is_error { "error" } else { "result" };
|
||||
eprintln!(
|
||||
"{dim}[{node_id}] [{label}] {tool_name}:{reset}\n{}",
|
||||
serde_json::to_string_pretty(output)
|
||||
.unwrap_or_else(|_| output.to_string()),
|
||||
dim = styles.dim,
|
||||
reset = styles.reset,
|
||||
);
|
||||
}
|
||||
AgentEvent::Error { error } => {
|
||||
eprintln!(
|
||||
"{dim}[{node_id}]{reset} {red}\u{2717} {error}{reset}",
|
||||
|
|
@ -379,7 +364,7 @@ impl CodergenBackend for AgentApiBackend {
|
|||
stage_usage.cost = super::compute_stage_cost(&stage_usage);
|
||||
|
||||
// Print session summary to stderr.
|
||||
if self.verbose >= 1 {
|
||||
if self.verbose {
|
||||
let total_tokens = total_usage.input_tokens + total_usage.output_tokens;
|
||||
let token_str = if total_tokens >= 1000 {
|
||||
format!("{}k tokens", total_tokens / 1000)
|
||||
|
|
@ -469,10 +454,10 @@ mod tests {
|
|||
#[test]
|
||||
fn agent_backend_stores_config() {
|
||||
let styles = Box::leak(Box::new(Styles::new(false)));
|
||||
let backend = AgentApiBackend::new("claude-opus-4-6".to_string(), Provider::OpenAi, 2, styles);
|
||||
let backend = AgentApiBackend::new("claude-opus-4-6".to_string(), Provider::OpenAi, true, styles);
|
||||
assert_eq!(backend.model, "claude-opus-4-6");
|
||||
assert_eq!(backend.provider, Provider::OpenAi);
|
||||
assert_eq!(backend.verbose, 2);
|
||||
assert!(backend.verbose);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -481,7 +466,7 @@ mod tests {
|
|||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
Provider::Anthropic,
|
||||
0,
|
||||
false,
|
||||
styles,
|
||||
);
|
||||
assert!(backend.sessions.lock().unwrap().is_empty());
|
||||
|
|
@ -493,7 +478,7 @@ mod tests {
|
|||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
Provider::Anthropic,
|
||||
0,
|
||||
false,
|
||||
styles,
|
||||
);
|
||||
let mut profile = backend.build_profile();
|
||||
|
|
|
|||
|
|
@ -106,9 +106,9 @@ pub struct RunArgs {
|
|||
#[arg(long)]
|
||||
pub provider: Option<String>,
|
||||
|
||||
/// Verbosity level (-v summary, -vv full details)
|
||||
#[arg(short, long, action = clap::ArgAction::Count)]
|
||||
pub verbose: u8,
|
||||
/// Enable verbose output
|
||||
#[arg(short, long)]
|
||||
pub verbose: bool,
|
||||
|
||||
/// Sandbox for agent tools
|
||||
#[arg(long, value_enum)]
|
||||
|
|
@ -571,353 +571,6 @@ pub fn format_event_summary(event: &WorkflowRunEvent, styles: &Styles) -> String
|
|||
format!("{dim}{body}{reset}", dim = styles.dim, reset = styles.reset)
|
||||
}
|
||||
|
||||
/// Multi-line detail view of a workflow run event for `-vv` output.
|
||||
/// Box-drawing is dimmed; values are normal.
|
||||
#[must_use]
|
||||
pub fn format_event_detail(event: &WorkflowRunEvent, styles: &Styles) -> String {
|
||||
let d = styles.dim;
|
||||
let r = styles.reset;
|
||||
|
||||
match event {
|
||||
WorkflowRunEvent::WorkflowRunStarted { name, run_id, .. } => {
|
||||
format!(
|
||||
"{d}── WORKFLOW_RUN_STARTED ─────────────────────────{r}\n {d}name:{r} {name}\n {d}id:{r} {run_id}\n"
|
||||
)
|
||||
}
|
||||
WorkflowRunEvent::WorkflowRunCompleted {
|
||||
duration_ms,
|
||||
artifact_count,
|
||||
total_cost,
|
||||
..
|
||||
} => {
|
||||
let mut s = format!("{d}── WORKFLOW_RUN_COMPLETED ───────────────────────{r}\n {d}duration_ms:{r} {duration_ms}\n {d}artifact_count:{r} {artifact_count}\n");
|
||||
if let Some(cost) = total_cost {
|
||||
s.push_str(&format!(" {d}total_cost:{r} {}\n", format_cost(*cost)));
|
||||
}
|
||||
s
|
||||
}
|
||||
WorkflowRunEvent::WorkflowRunFailed { error, duration_ms, .. } => {
|
||||
format!("{d}── WORKFLOW_RUN_FAILED ──────────────────────────{r}\n {d}error:{r} {error}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::StageStarted { name, index, handler_type, attempt, max_attempts } => {
|
||||
let mut s = format!(
|
||||
"{d}── STAGE_STARTED ────────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n"
|
||||
);
|
||||
if let Some(ht) = handler_type {
|
||||
s.push_str(&format!(" {d}handler_type:{r} {ht}\n"));
|
||||
}
|
||||
s.push_str(&format!(" {d}attempt:{r} {attempt}/{max_attempts}\n"));
|
||||
s
|
||||
}
|
||||
WorkflowRunEvent::StageCompleted {
|
||||
name,
|
||||
index,
|
||||
duration_ms,
|
||||
status,
|
||||
preferred_label,
|
||||
suggested_next_ids,
|
||||
usage,
|
||||
failure_reason,
|
||||
notes,
|
||||
files_touched,
|
||||
attempt,
|
||||
max_attempts,
|
||||
failure_class,
|
||||
} => {
|
||||
let mut s = format!("{d}── STAGE_COMPLETED ──────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n {d}status:{r} {status}\n");
|
||||
if let Some(label) = preferred_label {
|
||||
s.push_str(&format!(" {d}preferred_label:{r} {label}\n"));
|
||||
}
|
||||
if !suggested_next_ids.is_empty() {
|
||||
s.push_str(&format!(" {d}suggested_next_ids:{r} {}\n", suggested_next_ids.join(", ")));
|
||||
}
|
||||
if let Some(u) = usage {
|
||||
let total = u.input_tokens + u.output_tokens;
|
||||
s.push_str(&format!(" {d}model:{r} {}\n", u.model));
|
||||
s.push_str(&format!(" {d}tokens:{r} {} ({} in / {} out)\n",
|
||||
format_tokens_human(total),
|
||||
format_tokens_human(u.input_tokens),
|
||||
format_tokens_human(u.output_tokens),
|
||||
));
|
||||
if let Some(cache_read) = u.cache_read_tokens {
|
||||
s.push_str(&format!(" {d}cache_read:{r} {}\n", format_tokens_human(cache_read)));
|
||||
}
|
||||
if let Some(cache_write) = u.cache_write_tokens {
|
||||
s.push_str(&format!(" {d}cache_write:{r} {}\n", format_tokens_human(cache_write)));
|
||||
}
|
||||
if let Some(reasoning) = u.reasoning_tokens {
|
||||
s.push_str(&format!(" {d}reasoning:{r} {}\n", format_tokens_human(reasoning)));
|
||||
}
|
||||
if let Some(cost) = compute_stage_cost(u) {
|
||||
s.push_str(&format!(" {d}cost:{r} {}\n", format_cost(cost)));
|
||||
}
|
||||
}
|
||||
if !files_touched.is_empty() {
|
||||
s.push_str(&format!(" {d}files_touched:{r} {} files\n", files_touched.len()));
|
||||
}
|
||||
if let Some(reason) = failure_reason {
|
||||
s.push_str(&format!(" {d}failure_reason:{r} {reason}\n"));
|
||||
}
|
||||
if let Some(n) = notes {
|
||||
s.push_str(&format!(" {d}notes:{r} {n}\n"));
|
||||
}
|
||||
s.push_str(&format!(" {d}attempt:{r} {attempt}/{max_attempts}\n"));
|
||||
if let Some(fc) = failure_class {
|
||||
s.push_str(&format!(" {d}failure_class:{r} {fc}\n"));
|
||||
}
|
||||
s
|
||||
}
|
||||
WorkflowRunEvent::StageFailed {
|
||||
name,
|
||||
index,
|
||||
error,
|
||||
will_retry,
|
||||
failure_reason,
|
||||
failure_class,
|
||||
} => {
|
||||
let mut s = format!("{d}── STAGE_FAILED ─────────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}error:{r} {error}\n {d}will_retry:{r} {will_retry}\n");
|
||||
if let Some(reason) = failure_reason {
|
||||
s.push_str(&format!(" {d}failure_reason:{r} {reason}\n"));
|
||||
}
|
||||
if let Some(fc) = failure_class {
|
||||
s.push_str(&format!(" {d}failure_class:{r} {fc}\n"));
|
||||
}
|
||||
s
|
||||
}
|
||||
WorkflowRunEvent::StageRetrying {
|
||||
name,
|
||||
index,
|
||||
attempt,
|
||||
max_attempts,
|
||||
delay_ms,
|
||||
} => {
|
||||
format!("{d}── STAGE_RETRYING ───────────────────────────{r}\n {d}name:{r} {name}\n {d}index:{r} {index}\n {d}attempt:{r} {attempt}/{max_attempts}\n {d}delay_ms:{r} {delay_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::ParallelStarted { branch_count, join_policy, error_policy } => {
|
||||
format!("{d}── PARALLEL_STARTED ─────────────────────────{r}\n {d}branch_count:{r} {branch_count}\n {d}join_policy:{r} {join_policy}\n {d}error_policy:{r} {error_policy}\n")
|
||||
}
|
||||
WorkflowRunEvent::ParallelBranchStarted { branch, index } => {
|
||||
format!("{d}── PARALLEL_BRANCH_STARTED ──────────────────{r}\n {d}branch:{r} {branch}\n {d}index:{r} {index}\n")
|
||||
}
|
||||
WorkflowRunEvent::ParallelBranchCompleted {
|
||||
branch,
|
||||
index,
|
||||
duration_ms,
|
||||
status,
|
||||
} => {
|
||||
format!("{d}── PARALLEL_BRANCH_COMPLETED ────────────────{r}\n {d}branch:{r} {branch}\n {d}index:{r} {index}\n {d}duration_ms:{r} {duration_ms}\n {d}status:{r} {status}\n")
|
||||
}
|
||||
WorkflowRunEvent::ParallelCompleted {
|
||||
duration_ms,
|
||||
success_count,
|
||||
failure_count,
|
||||
} => {
|
||||
format!("{d}── PARALLEL_COMPLETED ───────────────────────{r}\n {d}duration_ms:{r} {duration_ms}\n {d}success_count:{r} {success_count}\n {d}failure_count:{r} {failure_count}\n")
|
||||
}
|
||||
WorkflowRunEvent::InterviewStarted { question, stage, question_type } => {
|
||||
format!("{d}── INTERVIEW_STARTED ────────────────────────{r}\n {d}stage:{r} {stage}\n {d}question:{r} {question}\n {d}question_type:{r} {question_type}\n")
|
||||
}
|
||||
WorkflowRunEvent::InterviewCompleted {
|
||||
question,
|
||||
answer,
|
||||
duration_ms,
|
||||
} => {
|
||||
format!("{d}── INTERVIEW_COMPLETED ──────────────────────{r}\n {d}question:{r} {question}\n {d}answer:{r} {answer}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::InterviewTimeout {
|
||||
question,
|
||||
stage,
|
||||
duration_ms,
|
||||
} => {
|
||||
format!("{d}── INTERVIEW_TIMEOUT ────────────────────────{r}\n {d}question:{r} {question}\n {d}stage:{r} {stage}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::CheckpointSaved { node_id } => {
|
||||
format!(
|
||||
"{d}── CHECKPOINT_SAVED ─────────────────────────{r}\n {d}node_id:{r} {node_id}\n"
|
||||
)
|
||||
}
|
||||
WorkflowRunEvent::GitCheckpoint { run_id, node_id, status, git_commit_sha } => {
|
||||
format!(
|
||||
"{d}── GIT_CHECKPOINT ───────────────────────────{r}\n {d}run_id:{r} {run_id}\n {d}node_id:{r} {node_id}\n {d}status:{r} {status}\n {d}sha:{r} {git_commit_sha}\n"
|
||||
)
|
||||
}
|
||||
WorkflowRunEvent::EdgeSelected { from_node, to_node, label, condition } => {
|
||||
let mut s = format!("{d}── EDGE_SELECTED ────────────────────────────{r}\n {d}from:{r} {from_node}\n {d}to:{r} {to_node}\n");
|
||||
if let Some(l) = label {
|
||||
s.push_str(&format!(" {d}label:{r} {l}\n"));
|
||||
}
|
||||
if let Some(c) = condition {
|
||||
s.push_str(&format!(" {d}condition:{r} {c}\n"));
|
||||
}
|
||||
s
|
||||
}
|
||||
WorkflowRunEvent::LoopRestart { from_node, to_node } => {
|
||||
format!("{d}── LOOP_RESTART ─────────────────────────────{r}\n {d}from:{r} {from_node}\n {d}to:{r} {to_node}\n")
|
||||
}
|
||||
WorkflowRunEvent::Prompt { stage, text } => {
|
||||
format!("{d}── PROMPT ───────────────────────────────────{r}\n {d}stage:{r} {stage}\n {d}text:{r}\n{text}\n")
|
||||
}
|
||||
WorkflowRunEvent::Agent { stage, event } => match event {
|
||||
AgentEvent::AssistantMessage { text, model, usage, tool_call_count } => {
|
||||
let total = usage.input_tokens + usage.output_tokens;
|
||||
let truncated = if text.len() > 200 { &text[..200] } else { text.as_str() };
|
||||
let mut s = format!("{d}── ASSISTANT_MESSAGE ────────────────────────{r}\n {d}stage:{r} {stage}\n {d}model:{r} {model}\n {d}tokens:{r} {} ({} in / {} out)\n {d}tool_calls:{r} {tool_call_count}\n",
|
||||
format_tokens_human(total),
|
||||
format_tokens_human(usage.input_tokens),
|
||||
format_tokens_human(usage.output_tokens),
|
||||
);
|
||||
if let Some(cache_read) = usage.cache_read_tokens {
|
||||
s.push_str(&format!(" {d}cache_read:{r} {}\n", format_tokens_human(cache_read)));
|
||||
}
|
||||
if let Some(cache_write) = usage.cache_write_tokens {
|
||||
s.push_str(&format!(" {d}cache_write:{r} {}\n", format_tokens_human(cache_write)));
|
||||
}
|
||||
if let Some(reasoning) = usage.reasoning_tokens {
|
||||
s.push_str(&format!(" {d}reasoning:{r} {}\n", format_tokens_human(reasoning)));
|
||||
}
|
||||
s.push_str(&format!(" {d}text:{r} {truncated}\n"));
|
||||
s
|
||||
}
|
||||
AgentEvent::ToolCallStarted { tool_name, tool_call_id, arguments } => {
|
||||
let args_str = serde_json::to_string(arguments).unwrap_or_else(|_| arguments.to_string());
|
||||
let truncated = if args_str.len() > 200 { &args_str[..200] } else { &args_str };
|
||||
format!("{d}── TOOL_CALL_STARTED ────────────────────────{r}\n {d}stage:{r} {stage}\n {d}tool_name:{r} {tool_name}\n {d}tool_call_id:{r} {tool_call_id}\n {d}arguments:{r} {truncated}\n")
|
||||
}
|
||||
AgentEvent::ToolCallCompleted { tool_name, tool_call_id, output, is_error } => {
|
||||
let output_str = serde_json::to_string(output).unwrap_or_else(|_| output.to_string());
|
||||
let truncated = if output_str.len() > 200 { &output_str[..200] } else { &output_str };
|
||||
format!("{d}── TOOL_CALL_COMPLETED ──────────────────────{r}\n {d}stage:{r} {stage}\n {d}tool_name:{r} {tool_name}\n {d}tool_call_id:{r} {tool_call_id}\n {d}is_error:{r} {is_error}\n {d}output:{r} {truncated}\n")
|
||||
}
|
||||
AgentEvent::Error { error } => {
|
||||
format!("{d}── SESSION_ERROR ────────────────────────────{r}\n {d}stage:{r} {stage}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
AgentEvent::ContextWindowWarning { estimated_tokens, context_window_size, usage_percent } => {
|
||||
format!("{d}── CONTEXT_WINDOW_WARNING ───────────────────{r}\n {d}stage:{r} {stage}\n {d}estimated_tokens:{r} {estimated_tokens}\n {d}context_window_size:{r} {context_window_size}\n {d}usage_percent:{r} {usage_percent}%\n")
|
||||
}
|
||||
AgentEvent::LoopDetected => {
|
||||
format!("{d}── LOOP_DETECTED ────────────────────────────{r}\n {d}stage:{r} {stage}\n")
|
||||
}
|
||||
AgentEvent::TurnLimitReached { max_turns } => {
|
||||
format!("{d}── TURN_LIMIT_REACHED ───────────────────────{r}\n {d}stage:{r} {stage}\n {d}max_turns:{r} {max_turns}\n")
|
||||
}
|
||||
AgentEvent::CompactionStarted { estimated_tokens, context_window_size } => {
|
||||
format!("{d}── COMPACTION_STARTED ───────────────────────{r}\n {d}stage:{r} {stage}\n {d}estimated_tokens:{r} {estimated_tokens}\n {d}context_window_size:{r} {context_window_size}\n")
|
||||
}
|
||||
AgentEvent::CompactionCompleted { original_turn_count, preserved_turn_count, summary_token_estimate, tracked_file_count } => {
|
||||
format!("{d}── COMPACTION_COMPLETED ─────────────────────{r}\n {d}stage:{r} {stage}\n {d}original_turn_count:{r} {original_turn_count}\n {d}preserved_turn_count:{r} {preserved_turn_count}\n {d}summary_token_estimate:{r} {summary_token_estimate}\n {d}tracked_file_count:{r} {tracked_file_count}\n")
|
||||
}
|
||||
AgentEvent::LlmRetry { provider, model, attempt, delay_secs, error } => {
|
||||
let delay_ms = (*delay_secs * 1000.0) as u64;
|
||||
format!("{d}── LLM_RETRY ────────────────────────────────{r}\n {d}stage:{r} {stage}\n {d}provider:{r} {provider}\n {d}model:{r} {model}\n {d}attempt:{r} {attempt}\n {d}delay_ms:{r} {delay_ms}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
AgentEvent::SubAgentSpawned { agent_id, depth, task } => {
|
||||
let task_preview = if task.len() > 200 { &task[..200] } else { task.as_str() };
|
||||
format!("{d}── SUBAGENT_SPAWNED ─────────────────────────{r}\n {d}stage:{r} {stage}\n {d}agent_id:{r} {agent_id}\n {d}depth:{r} {depth}\n {d}task:{r} {task_preview}\n")
|
||||
}
|
||||
AgentEvent::SubAgentCompleted { agent_id, depth, success, turns_used } => {
|
||||
format!("{d}── SUBAGENT_COMPLETED ───────────────────────{r}\n {d}stage:{r} {stage}\n {d}agent_id:{r} {agent_id}\n {d}depth:{r} {depth}\n {d}success:{r} {success}\n {d}turns_used:{r} {turns_used}\n")
|
||||
}
|
||||
AgentEvent::SubAgentFailed { agent_id, depth, error } => {
|
||||
format!("{d}── SUBAGENT_FAILED ──────────────────────────{r}\n {d}stage:{r} {stage}\n {d}agent_id:{r} {agent_id}\n {d}depth:{r} {depth}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
AgentEvent::SubAgentClosed { agent_id, depth } => {
|
||||
format!("{d}── SUBAGENT_CLOSED ──────────────────────────{r}\n {d}stage:{r} {stage}\n {d}agent_id:{r} {agent_id}\n {d}depth:{r} {depth}\n")
|
||||
}
|
||||
AgentEvent::SubAgentEvent { agent_id, depth, event } => {
|
||||
format!("{d}── SUBAGENT_EVENT ───────────────────────────{r}\n {d}stage:{r} {stage}\n {d}agent_id:{r} {agent_id}\n {d}depth:{r} {depth}\n {d}event:{r} {event:?}\n")
|
||||
}
|
||||
other => format!("{d}── AGENT ────────────────────────────────────{r}\n {d}stage:{r} {stage}\n {d}event:{r} {other:?}\n"),
|
||||
}
|
||||
WorkflowRunEvent::ParallelEarlyTermination {
|
||||
reason,
|
||||
completed_count,
|
||||
pending_count,
|
||||
} => {
|
||||
format!("{d}── PARALLEL_EARLY_TERMINATION ───────────────{r}\n {d}reason:{r} {reason}\n {d}completed_count:{r} {completed_count}\n {d}pending_count:{r} {pending_count}\n")
|
||||
}
|
||||
WorkflowRunEvent::SubgraphStarted { node_id, start_node } => {
|
||||
format!("{d}── SUBGRAPH_STARTED ─────────────────────────{r}\n {d}node_id:{r} {node_id}\n {d}start_node:{r} {start_node}\n")
|
||||
}
|
||||
WorkflowRunEvent::SubgraphCompleted {
|
||||
node_id,
|
||||
steps_executed,
|
||||
status,
|
||||
duration_ms,
|
||||
} => {
|
||||
format!("{d}── SUBGRAPH_COMPLETED ───────────────────────{r}\n {d}node_id:{r} {node_id}\n {d}steps_executed:{r} {steps_executed}\n {d}status:{r} {status}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::Sandbox { event } => {
|
||||
use arc_agent::SandboxEvent;
|
||||
match event {
|
||||
SandboxEvent::Initializing { provider } => {
|
||||
format!("{d}── SANDBOX_INITIALIZING ────────────────────{r}\n {d}provider:{r} {provider}\n")
|
||||
}
|
||||
SandboxEvent::Ready { provider, duration_ms } => {
|
||||
format!("{d}── SANDBOX_READY ───────────────────────────{r}\n {d}provider:{r} {provider}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::InitializeFailed { provider, error, duration_ms } => {
|
||||
format!("{d}── SANDBOX_INIT_FAILED ─────────────────────{r}\n {d}provider:{r} {provider}\n {d}error:{r} {error}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::CleanupStarted { provider } => {
|
||||
format!("{d}── SANDBOX_CLEANUP_STARTED ─────────────────{r}\n {d}provider:{r} {provider}\n")
|
||||
}
|
||||
SandboxEvent::CleanupCompleted { provider, duration_ms } => {
|
||||
format!("{d}── SANDBOX_CLEANUP_COMPLETED ───────────────{r}\n {d}provider:{r} {provider}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::CleanupFailed { provider, error } => {
|
||||
format!("{d}── SANDBOX_CLEANUP_FAILED ──────────────────{r}\n {d}provider:{r} {provider}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotPulling { name } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_PULLING ───────────────────{r}\n {d}name:{r} {name}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotPulled { name, duration_ms } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_PULLED ────────────────────{r}\n {d}name:{r} {name}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotEnsuring { name } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_ENSURING ───────────────{r}\n {d}name:{r} {name}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotCreating { name } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_CREATING ───────────────{r}\n {d}name:{r} {name}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotReady { name, duration_ms } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_READY ──────────────────{r}\n {d}name:{r} {name}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::SnapshotFailed { name, error } => {
|
||||
format!("{d}── SANDBOX_SNAPSHOT_FAILED ─────────────────{r}\n {d}name:{r} {name}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
SandboxEvent::GitCloneStarted { url, branch } => {
|
||||
let branch_str = branch.as_deref().unwrap_or("(default)");
|
||||
format!("{d}── SANDBOX_GIT_CLONE_STARTED ──────────────{r}\n {d}url:{r} {url}\n {d}branch:{r} {branch_str}\n")
|
||||
}
|
||||
SandboxEvent::GitCloneCompleted { url, duration_ms } => {
|
||||
format!("{d}── SANDBOX_GIT_CLONE_COMPLETED ────────────{r}\n {d}url:{r} {url}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
SandboxEvent::GitCloneFailed { url, error } => {
|
||||
format!("{d}── SANDBOX_GIT_CLONE_FAILED ───────────────{r}\n {d}url:{r} {url}\n {d}error:{r} {error}\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
WorkflowRunEvent::SetupStarted { command_count } => {
|
||||
format!("{d}── SETUP_STARTED ────────────────────────────{r}\n {d}command_count:{r} {command_count}\n")
|
||||
}
|
||||
WorkflowRunEvent::SetupCommandStarted { command, index } => {
|
||||
format!("{d}── SETUP_COMMAND_STARTED ────────────────────{r}\n {d}index:{r} {index}\n {d}command:{r} {command}\n")
|
||||
}
|
||||
WorkflowRunEvent::SetupCommandCompleted { command, index, exit_code, duration_ms } => {
|
||||
format!("{d}── SETUP_COMMAND_COMPLETED ──────────────────{r}\n {d}index:{r} {index}\n {d}command:{r} {command}\n {d}exit_code:{r} {exit_code}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::SetupCompleted { duration_ms } => {
|
||||
format!("{d}── SETUP_COMPLETED ──────────────────────────{r}\n {d}duration_ms:{r} {duration_ms}\n")
|
||||
}
|
||||
WorkflowRunEvent::SetupFailed { command, index, exit_code, stderr } => {
|
||||
format!("{d}── SETUP_FAILED ─────────────────────────────{r}\n {d}index:{r} {index}\n {d}command:{r} {command}\n {d}exit_code:{r} {exit_code}\n {d}stderr:{r} {stderr}\n")
|
||||
}
|
||||
WorkflowRunEvent::StallWatchdogTimeout { node, idle_seconds } => {
|
||||
format!("{d}── STALL_WATCHDOG_TIMEOUT ────────────────────{r}\n {d}node:{r} {node}\n {d}idle_seconds:{r} {idle_seconds}\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute the dollar cost for a stage's token usage, if pricing is available.
|
||||
#[must_use]
|
||||
pub fn compute_stage_cost(usage: &StageUsage) -> Option<f64> {
|
||||
|
|
@ -1007,20 +660,6 @@ mod tests {
|
|||
assert!(s.contains("3"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_detail_sandbox_ready() {
|
||||
let event = WorkflowRunEvent::Sandbox {
|
||||
event: arc_agent::SandboxEvent::Ready {
|
||||
provider: "local".into(),
|
||||
duration_ms: 42,
|
||||
},
|
||||
};
|
||||
let s = format_event_detail(&event, test_styles());
|
||||
assert!(s.contains("SANDBOX_READY"));
|
||||
assert!(s.contains("local"));
|
||||
assert!(s.contains("42"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_summary_subagent_spawned() {
|
||||
let event = WorkflowRunEvent::Agent {
|
||||
|
|
@ -1054,36 +693,6 @@ mod tests {
|
|||
assert!(s.contains("turns=5"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_detail_subagent_failed() {
|
||||
let event = WorkflowRunEvent::Agent {
|
||||
stage: "code".into(),
|
||||
event: AgentEvent::SubAgentFailed {
|
||||
agent_id: "abcdef12-xxxx".into(),
|
||||
depth: 2,
|
||||
error: "timeout".into(),
|
||||
},
|
||||
};
|
||||
let s = format_event_detail(&event, test_styles());
|
||||
assert!(s.contains("SUBAGENT_FAILED"));
|
||||
assert!(s.contains("timeout"));
|
||||
assert!(s.contains("depth"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_detail_subagent_closed() {
|
||||
let event = WorkflowRunEvent::Agent {
|
||||
stage: "code".into(),
|
||||
event: AgentEvent::SubAgentClosed {
|
||||
agent_id: "abcdef12-xxxx".into(),
|
||||
depth: 1,
|
||||
},
|
||||
};
|
||||
let s = format_event_detail(&event, test_styles());
|
||||
assert!(s.contains("SUBAGENT_CLOSED"));
|
||||
assert!(s.contains("abcdef12-xxxx"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_summary_subagent_event() {
|
||||
let event = WorkflowRunEvent::Agent {
|
||||
|
|
@ -1099,17 +708,4 @@ mod tests {
|
|||
assert!(s.contains("abcdef12"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn format_detail_setup_command_completed() {
|
||||
let event = WorkflowRunEvent::SetupCommandCompleted {
|
||||
command: "npm install".into(),
|
||||
index: 0,
|
||||
exit_code: 0,
|
||||
duration_ms: 5000,
|
||||
};
|
||||
let s = format_event_detail(&event, test_styles());
|
||||
assert!(s.contains("SETUP_COMMAND_COMPLETED"));
|
||||
assert!(s.contains("npm install"));
|
||||
assert!(s.contains("5000"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ use super::backend::AgentApiBackend;
|
|||
use super::cli_backend::{BackendRouter, AgentCliBackend};
|
||||
use super::task_config;
|
||||
use super::{
|
||||
compute_stage_cost, format_cost, format_duration_human, format_event_detail,
|
||||
compute_stage_cost, format_cost, format_duration_human,
|
||||
format_event_summary, format_tokens_human, print_diagnostics, read_dot_file, SandboxProvider,
|
||||
RunArgs,
|
||||
};
|
||||
|
|
@ -154,7 +154,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
|
|||
}
|
||||
}
|
||||
|
||||
if args.verbose >= 1 {
|
||||
if args.verbose {
|
||||
eprintln!(
|
||||
"{dim}Logs: {}{reset}",
|
||||
logs_dir.display(),
|
||||
|
|
@ -230,11 +230,7 @@ pub async fn run_command(args: RunArgs, styles: &'static Styles) -> anyhow::Resu
|
|||
});
|
||||
}
|
||||
|
||||
if args.verbose >= 2 {
|
||||
emitter.on_event(move |event| {
|
||||
eprint!("{}", format_event_detail(event, styles));
|
||||
});
|
||||
} else if args.verbose >= 1 {
|
||||
if args.verbose {
|
||||
emitter.on_event(move |event| {
|
||||
eprintln!("{}", format_event_summary(event, styles));
|
||||
});
|
||||
|
|
|
|||
|
|
@ -7208,7 +7208,7 @@ async fn arc_e2e_with_real_llm() {
|
|||
Some(Box::new(AgentApiBackend::new(
|
||||
model.clone(),
|
||||
Provider::Anthropic,
|
||||
0,
|
||||
false,
|
||||
&TEST_STYLES,
|
||||
))
|
||||
as Box<dyn arc_workflows::handler::codergen::CodergenBackend>)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue