mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-09-07 08:27:12 +00:00
Redesign --verbose mode to use ProgressUI instead of raw event logs
Both verbose and normal modes now use the same indicatif-based ProgressUI renderer with the same visual hierarchy (indentation, glyphs, colors). In verbose mode: tool calls persist after stage completion, no 5-call cap, stage completion shows stats (turns, tool calls, tokens), and additional events are rendered (edge transitions, loop restarts, setup commands, retries, context warnings, compaction, subagents). Remove the old format_event_summary function and its ~70 tests, the verbose stderr printing from AgentApiBackend, and the verbose/styles fields that are no longer needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
45165c1fa3
commit
c959368452
6 changed files with 247 additions and 1548 deletions
|
|
@ -107,8 +107,6 @@ pub async fn serve_command(args: ServeArgs, styles: &'static Styles) -> anyhow::
|
|||
Some(Box::new(AgentApiBackend::new(
|
||||
model.clone(),
|
||||
provider_enum,
|
||||
false,
|
||||
styles,
|
||||
)))
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ use arc_agent::{
|
|||
};
|
||||
use arc_llm::client::Client;
|
||||
use arc_llm::provider::Provider;
|
||||
use arc_util::terminal::Styles;
|
||||
|
||||
use crate::context::Context;
|
||||
use crate::error::ArcError;
|
||||
|
|
@ -25,19 +24,15 @@ use crate::outcome::StageUsage;
|
|||
pub struct AgentApiBackend {
|
||||
model: String,
|
||||
provider: Provider,
|
||||
verbose: bool,
|
||||
styles: &'static Styles,
|
||||
sessions: Mutex<HashMap<String, Session>>,
|
||||
}
|
||||
|
||||
impl AgentApiBackend {
|
||||
#[must_use]
|
||||
pub fn new(model: String, provider: Provider, verbose: bool, styles: &'static Styles) -> Self {
|
||||
pub fn new(model: String, provider: Provider) -> Self {
|
||||
Self {
|
||||
model,
|
||||
provider,
|
||||
verbose,
|
||||
styles,
|
||||
sessions: Mutex::new(HashMap::new()),
|
||||
}
|
||||
}
|
||||
|
|
@ -224,10 +219,8 @@ impl CodergenBackend for AgentApiBackend {
|
|||
let pending_clone = Arc::clone(&pending_tool_calls);
|
||||
let files_clone = Arc::clone(&files_touched);
|
||||
|
||||
// Subscribe to session events: forward to pipeline emitter and optionally print to stderr.
|
||||
let verbose = self.verbose;
|
||||
// Subscribe to session events: forward to pipeline emitter.
|
||||
let node_id = node.id.clone();
|
||||
let styles = self.styles;
|
||||
let pipeline_emitter = Arc::clone(emitter);
|
||||
let mut rx = session.subscribe();
|
||||
tokio::spawn(async move {
|
||||
|
|
@ -282,34 +275,6 @@ impl CodergenBackend for AgentApiBackend {
|
|||
});
|
||||
}
|
||||
|
||||
// Verbose stderr printing (gated on verbosity)
|
||||
if verbose {
|
||||
match &event.event {
|
||||
AgentEvent::ToolCallStarted {
|
||||
tool_name,
|
||||
arguments,
|
||||
..
|
||||
} => {
|
||||
eprintln!(
|
||||
"{} {} {}{}",
|
||||
styles.dim.apply_to(format!("[{node_id}]")),
|
||||
styles.dim.apply_to("\u{25cf}"),
|
||||
styles.bold_cyan.apply_to(tool_name),
|
||||
styles
|
||||
.dim
|
||||
.apply_to(format!("({})", format_tool_args(arguments))),
|
||||
);
|
||||
}
|
||||
AgentEvent::Error { error } => {
|
||||
eprintln!(
|
||||
"{} {}",
|
||||
styles.dim.apply_to(format!("[{node_id}]")),
|
||||
styles.red.apply_to(format!("\u{2717} {error}")),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -339,15 +304,9 @@ impl CodergenBackend for AgentApiBackend {
|
|||
result?;
|
||||
|
||||
// Aggregate token usage only from new turns (prevents double-counting on reuse).
|
||||
let (mut turn_count, mut tool_call_count) = (0usize, 0usize);
|
||||
let mut total_usage = arc_llm::types::Usage::default();
|
||||
for turn in &session.history().turns()[turns_before..] {
|
||||
if let Turn::Assistant {
|
||||
tool_calls, usage, ..
|
||||
} = turn
|
||||
{
|
||||
turn_count += 1;
|
||||
tool_call_count += tool_calls.len();
|
||||
if let Turn::Assistant { usage, .. } = turn {
|
||||
total_usage = total_usage + usage.clone();
|
||||
}
|
||||
}
|
||||
|
|
@ -363,20 +322,6 @@ impl CodergenBackend for AgentApiBackend {
|
|||
};
|
||||
stage_usage.cost = super::compute_stage_cost(&stage_usage);
|
||||
|
||||
// Print session summary to stderr.
|
||||
if self.verbose {
|
||||
let total_tokens = total_usage.input_tokens + total_usage.output_tokens;
|
||||
let token_str = super::format_tokens_human(total_tokens);
|
||||
let reuse_label = if is_reused { " (reused session)" } else { "" };
|
||||
eprintln!(
|
||||
"{}",
|
||||
self.styles.dim.apply_to(format!(
|
||||
"[{}] Done ({turn_count} turns, {tool_call_count} tool calls, {token_str} tokens{reuse_label})",
|
||||
node.id,
|
||||
)),
|
||||
);
|
||||
}
|
||||
|
||||
// Extract last assistant response from the session history.
|
||||
let response = session
|
||||
.history()
|
||||
|
|
@ -423,26 +368,6 @@ impl CodergenBackend for AgentApiBackend {
|
|||
}
|
||||
}
|
||||
|
||||
fn format_tool_args(args: &serde_json::Value) -> String {
|
||||
let Some(obj) = args.as_object() else {
|
||||
return args.to_string();
|
||||
};
|
||||
obj.iter()
|
||||
.map(|(k, v)| match v {
|
||||
serde_json::Value::String(s) => {
|
||||
let display = if s.len() > 80 {
|
||||
format!("{}...", &s[..77])
|
||||
} else {
|
||||
s.clone()
|
||||
};
|
||||
format!("{k}={display:?}")
|
||||
}
|
||||
other => format!("{k}={other}"),
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
|
@ -450,39 +375,20 @@ 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,
|
||||
true,
|
||||
styles,
|
||||
);
|
||||
let backend = AgentApiBackend::new("claude-opus-4-6".to_string(), Provider::OpenAi);
|
||||
assert_eq!(backend.model, "claude-opus-4-6");
|
||||
assert_eq!(backend.provider, Provider::OpenAi);
|
||||
assert!(backend.verbose);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn agent_backend_initializes_empty_sessions() {
|
||||
let styles = Box::leak(Box::new(Styles::new(false)));
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
Provider::Anthropic,
|
||||
false,
|
||||
styles,
|
||||
);
|
||||
let backend = AgentApiBackend::new("claude-opus-4-6".to_string(), Provider::Anthropic);
|
||||
assert!(backend.sessions.lock().unwrap().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_profile_can_register_subagent_tools() {
|
||||
let styles = Box::leak(Box::new(Styles::new(false)));
|
||||
let backend = AgentApiBackend::new(
|
||||
"claude-opus-4-6".to_string(),
|
||||
Provider::Anthropic,
|
||||
false,
|
||||
styles,
|
||||
);
|
||||
let backend = AgentApiBackend::new("claude-opus-4-6".to_string(), Provider::Anthropic);
|
||||
let mut profile = backend.build_profile();
|
||||
let manager = Arc::new(tokio::sync::Mutex::new(SubAgentManager::new(1)));
|
||||
let factory: SessionFactory = Arc::new(|| {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -12,7 +12,7 @@ use crate::interviewer::{Answer, Interviewer, Question};
|
|||
use crate::outcome::StageStatus;
|
||||
use arc_agent::AgentEvent;
|
||||
|
||||
use super::{compute_stage_cost, format_cost};
|
||||
use super::{compute_stage_cost, format_cost, format_tokens_human};
|
||||
|
||||
// ── Cached styles ───────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -159,6 +159,8 @@ struct ActiveStage {
|
|||
has_model: bool,
|
||||
spinner: ProgressBar,
|
||||
tool_calls: VecDeque<ToolCallEntry>,
|
||||
turn_count: u32,
|
||||
tool_call_count: u32,
|
||||
}
|
||||
|
||||
const MAX_TOOL_CALLS: usize = 5;
|
||||
|
|
@ -178,6 +180,7 @@ enum ProgressRenderer {
|
|||
|
||||
pub struct ProgressUI {
|
||||
renderer: ProgressRenderer,
|
||||
verbose: bool,
|
||||
active_stages: HashMap<String, ActiveStage>,
|
||||
setup_command_count: usize,
|
||||
sandbox_bar: Option<ProgressBar>,
|
||||
|
|
@ -187,7 +190,7 @@ pub struct ProgressUI {
|
|||
}
|
||||
|
||||
impl ProgressUI {
|
||||
pub fn new(is_tty: bool) -> Self {
|
||||
pub fn new(is_tty: bool, verbose: bool) -> Self {
|
||||
let renderer = if is_tty {
|
||||
ProgressRenderer::Tty(TtyRenderer {
|
||||
multi: MultiProgress::new(),
|
||||
|
|
@ -197,6 +200,7 @@ impl ProgressUI {
|
|||
};
|
||||
Self {
|
||||
renderer,
|
||||
verbose,
|
||||
active_stages: HashMap::new(),
|
||||
setup_command_count: 0,
|
||||
sandbox_bar: None,
|
||||
|
|
@ -219,7 +223,7 @@ impl ProgressUI {
|
|||
pub fn finish(&mut self) {
|
||||
for (_id, stage) in self.active_stages.drain() {
|
||||
for entry in &stage.tool_calls {
|
||||
if entry.is_branch {
|
||||
if entry.is_branch || self.verbose {
|
||||
entry.bar.abandon();
|
||||
} else {
|
||||
entry.bar.finish_and_clear();
|
||||
|
|
@ -277,7 +281,32 @@ impl ProgressUI {
|
|||
.and_then(compute_stage_cost)
|
||||
.map(|c| format!("{} ", format_cost(c)))
|
||||
.unwrap_or_default();
|
||||
let prefix = format!("{cost_str}{dur}");
|
||||
let stats_str = if self.verbose {
|
||||
let stage = self.active_stages.get(node_id);
|
||||
let turn_count = stage.map_or(0, |s| s.turn_count);
|
||||
let tool_call_count = stage.map_or(0, |s| s.tool_call_count);
|
||||
let total_tokens = usage
|
||||
.as_ref()
|
||||
.map(|u| u.input_tokens + u.output_tokens)
|
||||
.unwrap_or(0);
|
||||
if turn_count > 0 || tool_call_count > 0 || total_tokens > 0 {
|
||||
let dim = Style::new().dim();
|
||||
format!(
|
||||
" {}",
|
||||
dim.apply_to(format!(
|
||||
"({} turns, {} tool calls, {} tokens)",
|
||||
turn_count,
|
||||
tool_call_count,
|
||||
format_tokens_human(total_tokens),
|
||||
))
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
}
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let prefix = format!("{cost_str}{dur}{stats_str}");
|
||||
let glyph = if succeeded {
|
||||
green_check()
|
||||
} else {
|
||||
|
|
@ -318,6 +347,74 @@ impl ProgressUI {
|
|||
WorkflowRunEvent::SshAccessReady { ssh_command } => {
|
||||
self.on_ssh_access_ready(ssh_command);
|
||||
}
|
||||
WorkflowRunEvent::EdgeSelected {
|
||||
from_node,
|
||||
to_node,
|
||||
label,
|
||||
condition,
|
||||
} if self.verbose => {
|
||||
let detail = if let Some(c) = condition {
|
||||
format!(" [{c}]")
|
||||
} else if let Some(l) = label {
|
||||
format!(" \"{l}\"")
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
self.insert_info_line(&format!("\u{2192} {from_node} \u{2192} {to_node}{detail}"));
|
||||
}
|
||||
WorkflowRunEvent::LoopRestart { from_node, to_node } if self.verbose => {
|
||||
self.insert_info_line(&format!(
|
||||
"\u{21ba} {from_node} \u{2192} {to_node} (loop restart)"
|
||||
));
|
||||
}
|
||||
WorkflowRunEvent::SetupCommandCompleted {
|
||||
command,
|
||||
index,
|
||||
exit_code,
|
||||
duration_ms,
|
||||
} if self.verbose => {
|
||||
let total = self.setup_command_count;
|
||||
let dur = format_duration_ms(*duration_ms);
|
||||
let glyph = if *exit_code == 0 {
|
||||
green_check()
|
||||
} else {
|
||||
red_cross()
|
||||
};
|
||||
let msg = format!(
|
||||
"{glyph} [{}/{total}] {}",
|
||||
index + 1,
|
||||
truncate(command, 60),
|
||||
);
|
||||
match &self.renderer {
|
||||
ProgressRenderer::Tty(tty) => {
|
||||
let bar = if let Some(ref setup_bar) = self.setup_bar {
|
||||
tty.multi
|
||||
.insert_before(setup_bar, ProgressBar::new_spinner())
|
||||
} else {
|
||||
tty.multi.add(ProgressBar::new_spinner())
|
||||
};
|
||||
bar.set_style(style_tool_done());
|
||||
bar.set_prefix(dur);
|
||||
bar.finish_with_message(msg);
|
||||
}
|
||||
ProgressRenderer::Plain => {
|
||||
eprintln!(" {msg} {dur}");
|
||||
}
|
||||
}
|
||||
}
|
||||
WorkflowRunEvent::StageRetrying {
|
||||
node_id: _,
|
||||
name,
|
||||
attempt,
|
||||
max_attempts,
|
||||
delay_ms,
|
||||
..
|
||||
} if self.verbose => {
|
||||
let dur = format_duration_ms(*delay_ms);
|
||||
self.insert_info_line(&format!(
|
||||
"\u{21bb} {name}: retrying (attempt {attempt}/{max_attempts}, delay {dur})"
|
||||
));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -474,6 +571,8 @@ impl ProgressUI {
|
|||
has_model: false,
|
||||
spinner: bar,
|
||||
tool_calls: VecDeque::new(),
|
||||
turn_count: 0,
|
||||
tool_call_count: 0,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
@ -484,8 +583,8 @@ impl ProgressUI {
|
|||
ProgressRenderer::Tty(_) => {
|
||||
if let Some(stage) = self.active_stages.remove(node_id) {
|
||||
for entry in &stage.tool_calls {
|
||||
if entry.is_branch {
|
||||
// Already finished by on_parallel_branch_completed; keep visible
|
||||
if entry.is_branch || self.verbose {
|
||||
// Keep visible: branches always, all entries in verbose mode
|
||||
entry.bar.abandon();
|
||||
} else {
|
||||
entry.bar.finish_and_clear();
|
||||
|
|
@ -515,6 +614,7 @@ impl ProgressUI {
|
|||
AgentEvent::AssistantMessage { model, .. } => {
|
||||
if let ProgressRenderer::Tty(_) = &self.renderer {
|
||||
if let Some(stage) = self.active_stages.get_mut(stage_node_id) {
|
||||
stage.turn_count += 1;
|
||||
if !stage.has_model {
|
||||
stage.has_model = true;
|
||||
let dim = Style::new().dim();
|
||||
|
|
@ -537,8 +637,89 @@ impl ProgressUI {
|
|||
is_error,
|
||||
..
|
||||
} => {
|
||||
if let Some(stage) = self.active_stages.get_mut(stage_node_id) {
|
||||
stage.tool_call_count += 1;
|
||||
}
|
||||
self.on_tool_call_completed(stage_node_id, tool_call_id, *is_error);
|
||||
}
|
||||
AgentEvent::ContextWindowWarning { usage_percent, .. } if self.verbose => {
|
||||
let yellow = Style::new().yellow();
|
||||
self.insert_info_line_for_stage(
|
||||
stage_node_id,
|
||||
&format!(
|
||||
"{} context window: {usage_percent}% used",
|
||||
yellow.apply_to("\u{26a0}")
|
||||
),
|
||||
);
|
||||
}
|
||||
AgentEvent::CompactionCompleted {
|
||||
original_turn_count,
|
||||
preserved_turn_count,
|
||||
tracked_file_count,
|
||||
..
|
||||
} if self.verbose => {
|
||||
let dim = Style::new().dim();
|
||||
self.insert_info_line_for_stage(
|
||||
stage_node_id,
|
||||
&format!(
|
||||
"{}",
|
||||
dim.apply_to(format!(
|
||||
"\u{27f3} compaction: {original_turn_count} \u{2192} {preserved_turn_count} turns, {tracked_file_count} files"
|
||||
))
|
||||
),
|
||||
);
|
||||
}
|
||||
AgentEvent::LlmRetry {
|
||||
model,
|
||||
attempt,
|
||||
delay_secs,
|
||||
error,
|
||||
..
|
||||
} if self.verbose => {
|
||||
let yellow = Style::new().yellow();
|
||||
let delay_ms = (*delay_secs * 1000.0) as u64;
|
||||
let dur = format_duration_ms(delay_ms);
|
||||
self.insert_info_line_for_stage(
|
||||
stage_node_id,
|
||||
&format!(
|
||||
"{} retry: {model} attempt {attempt} ({error}, delay {dur})",
|
||||
yellow.apply_to("\u{26a0}")
|
||||
),
|
||||
);
|
||||
}
|
||||
AgentEvent::SubAgentSpawned {
|
||||
agent_id, task, ..
|
||||
} if self.verbose => {
|
||||
let dim = Style::new().dim();
|
||||
let short_id = &agent_id[..agent_id.len().min(8)];
|
||||
self.insert_info_line_for_stage(
|
||||
stage_node_id,
|
||||
&format!(
|
||||
"{}",
|
||||
dim.apply_to(format!(
|
||||
"\u{25b8} subagent[{short_id}] \"{}\"",
|
||||
truncate(task, 50)
|
||||
))
|
||||
),
|
||||
);
|
||||
}
|
||||
AgentEvent::SubAgentCompleted {
|
||||
agent_id,
|
||||
turns_used,
|
||||
success,
|
||||
..
|
||||
} if self.verbose => {
|
||||
let short_id = &agent_id[..agent_id.len().min(8)];
|
||||
let glyph = if *success {
|
||||
green_check()
|
||||
} else {
|
||||
red_cross()
|
||||
};
|
||||
self.insert_info_line_for_stage(
|
||||
stage_node_id,
|
||||
&format!("{glyph} subagent[{short_id}] ({turns_used} turns)"),
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -554,8 +735,8 @@ impl ProgressUI {
|
|||
|
||||
if let ProgressRenderer::Tty(tty) = &self.renderer {
|
||||
if let Some(stage) = self.active_stages.get_mut(stage_node_id) {
|
||||
// Evict oldest if at capacity (prefer completed entries)
|
||||
if stage.tool_calls.len() >= MAX_TOOL_CALLS {
|
||||
// Evict oldest if at capacity (prefer completed entries); skip in verbose mode
|
||||
if !self.verbose && stage.tool_calls.len() >= MAX_TOOL_CALLS {
|
||||
let evict_idx = stage
|
||||
.tool_calls
|
||||
.iter()
|
||||
|
|
@ -649,6 +830,43 @@ impl ProgressUI {
|
|||
}
|
||||
}
|
||||
|
||||
/// Insert a static info line (verbose-only) at the current position.
|
||||
fn insert_info_line(&mut self, message: &str) {
|
||||
match &self.renderer {
|
||||
ProgressRenderer::Tty(tty) => {
|
||||
let bar = tty.multi.add(ProgressBar::new_spinner());
|
||||
bar.set_style(style_static_dim());
|
||||
bar.finish_with_message(message.to_string());
|
||||
}
|
||||
ProgressRenderer::Plain => {
|
||||
eprintln!(" {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a static info line nested under a stage's tool calls.
|
||||
fn insert_info_line_for_stage(&mut self, stage_node_id: &str, message: &str) {
|
||||
match &self.renderer {
|
||||
ProgressRenderer::Tty(tty) => {
|
||||
let after = self
|
||||
.active_stages
|
||||
.get(stage_node_id)
|
||||
.map(|s| s.tool_calls.back().map_or(&s.spinner, |e| &e.bar));
|
||||
let bar = if let Some(after_bar) = after {
|
||||
tty.multi
|
||||
.insert_after(after_bar, ProgressBar::new_spinner())
|
||||
} else {
|
||||
tty.multi.add(ProgressBar::new_spinner())
|
||||
};
|
||||
bar.set_style(style_tool_done());
|
||||
bar.finish_with_message(message.to_string());
|
||||
}
|
||||
ProgressRenderer::Plain => {
|
||||
eprintln!(" {message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn on_tool_call_completed(&mut self, stage_node_id: &str, tool_call_id: &str, is_error: bool) {
|
||||
if let ProgressRenderer::Tty(_) = &self.renderer {
|
||||
if let Some(stage) = self.active_stages.get_mut(stage_node_id) {
|
||||
|
|
@ -749,7 +967,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parallel_branches_tracked_as_tool_calls() {
|
||||
let mut ui = ProgressUI::new(true);
|
||||
let mut ui = ProgressUI::new(true, false);
|
||||
|
||||
ui.handle_event(&stage_started("fork1", "Fork Analysis"));
|
||||
assert!(ui.active_stages.contains_key("fork1"));
|
||||
|
|
@ -810,7 +1028,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn parallel_branch_failure_tracked() {
|
||||
let mut ui = ProgressUI::new(true);
|
||||
let mut ui = ProgressUI::new(true, false);
|
||||
|
||||
ui.handle_event(&stage_started("fork1", "Fork"));
|
||||
ui.handle_event(&WorkflowRunEvent::ParallelStarted {
|
||||
|
|
@ -838,7 +1056,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn plain_mode_sets_parallel_parent() {
|
||||
let mut ui = ProgressUI::new(false);
|
||||
let mut ui = ProgressUI::new(false, false);
|
||||
|
||||
ui.handle_event(&stage_started("fork1", "Fork"));
|
||||
ui.handle_event(&WorkflowRunEvent::ParallelStarted {
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ use indicatif::HumanDuration;
|
|||
use std::time::Duration;
|
||||
|
||||
use super::{
|
||||
compute_stage_cost, format_cost, format_event_summary, format_tokens_human, print_diagnostics,
|
||||
read_dot_file, RunArgs, SandboxProvider,
|
||||
compute_stage_cost, format_cost, format_tokens_human, print_diagnostics, read_dot_file,
|
||||
RunArgs, SandboxProvider,
|
||||
};
|
||||
|
||||
/// Return the default model string for a given provider.
|
||||
|
|
@ -287,22 +287,14 @@ pub async fn run_command(
|
|||
}
|
||||
}
|
||||
|
||||
// Create progress UI (used for non-verbose mode)
|
||||
// Create progress UI (used for both normal and verbose modes)
|
||||
let is_tty = std::io::stderr().is_terminal();
|
||||
let progress_ui = Arc::new(Mutex::new(progress::ProgressUI::new(is_tty)));
|
||||
let progress_ui = Arc::new(Mutex::new(progress::ProgressUI::new(is_tty, args.verbose)));
|
||||
|
||||
if args.verbose {
|
||||
eprintln!(
|
||||
"{} {}",
|
||||
styles.dim.apply_to("Logs:"),
|
||||
styles.underline.apply_to(super::tilde_path(&logs_dir)),
|
||||
);
|
||||
} else {
|
||||
progress_ui
|
||||
.lock()
|
||||
.expect("progress lock poisoned")
|
||||
.show_logs_dir(&logs_dir);
|
||||
}
|
||||
progress_ui
|
||||
.lock()
|
||||
.expect("progress lock poisoned")
|
||||
.show_logs_dir(&logs_dir);
|
||||
|
||||
// 3. Build event emitter
|
||||
let mut emitter = EventEmitter::new();
|
||||
|
|
@ -385,19 +377,11 @@ pub async fn run_command(
|
|||
});
|
||||
}
|
||||
|
||||
if args.verbose {
|
||||
emitter.on_event(move |event| {
|
||||
eprintln!("{}", format_event_summary(event, styles));
|
||||
});
|
||||
} else {
|
||||
progress::ProgressUI::register(&progress_ui, &mut emitter);
|
||||
}
|
||||
progress::ProgressUI::register(&progress_ui, &mut emitter);
|
||||
|
||||
// 4. Build interviewer
|
||||
let interviewer: Arc<dyn Interviewer> = if args.auto_approve {
|
||||
Arc::new(AutoApproveInterviewer)
|
||||
} else if args.verbose {
|
||||
Arc::new(ConsoleInterviewer::new(styles))
|
||||
} else {
|
||||
Arc::new(progress::ProgressAwareInterviewer::new(
|
||||
ConsoleInterviewer::new(styles),
|
||||
|
|
@ -617,7 +601,7 @@ pub async fn run_command(
|
|||
if dry_run_mode {
|
||||
None
|
||||
} else {
|
||||
let api = AgentApiBackend::new(model.clone(), provider_enum, args.verbose, styles);
|
||||
let api = AgentApiBackend::new(model.clone(), provider_enum);
|
||||
let cli = AgentCliBackend::new(model.clone(), provider_enum);
|
||||
Some(Box::new(BackendRouter::new(Box::new(api), cli)))
|
||||
}
|
||||
|
|
@ -700,9 +684,7 @@ pub async fn run_command(
|
|||
}
|
||||
|
||||
// Finish progress bars before printing summary
|
||||
if !args.verbose {
|
||||
progress_ui.lock().expect("progress lock poisoned").finish();
|
||||
}
|
||||
progress_ui.lock().expect("progress lock poisoned").finish();
|
||||
|
||||
// Auto-derive retro (always, cheap) and optionally run retro agent
|
||||
if !args.no_retro {
|
||||
|
|
@ -1005,7 +987,7 @@ async fn run_from_branch(
|
|||
if dry_run_mode {
|
||||
None
|
||||
} else {
|
||||
let api = AgentApiBackend::new(model.clone(), provider_enum, args.verbose, styles);
|
||||
let api = AgentApiBackend::new(model.clone(), provider_enum);
|
||||
let cli = AgentCliBackend::new(model.clone(), provider_enum);
|
||||
Some(Box::new(BackendRouter::new(Box::new(api), cli)))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7204,8 +7204,6 @@ async fn arc_e2e_with_real_llm() {
|
|||
Some(Box::new(AgentApiBackend::new(
|
||||
model.clone(),
|
||||
Provider::Anthropic,
|
||||
false,
|
||||
&TEST_STYLES,
|
||||
))
|
||||
as Box<dyn arc_workflows::handler::codergen::CodergenBackend>)
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue