Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
3845037
feat(ux): complete UX overhaul — design system, boot screen, onboardi…
ilblackdragon Mar 20, 2026
d6e6de7
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 20, 2026
eea1cb4
feat(ux): Apple-level design refinements — spring physics, glass morp…
ilblackdragon Mar 20, 2026
7bcb0d0
feat(web): mobile layout improvements — sidebar toggle, settings dril…
ilblackdragon Mar 20, 2026
61d3ba0
feat(repl): interactive approval selector and transient status lines
ilblackdragon Mar 20, 2026
46d099a
fix: widen TurnCost token fields to u64 and remove unused variable
ilblackdragon Mar 20, 2026
77d4656
chore: reduce startup log noise — demote info to debug
ilblackdragon Mar 20, 2026
1a92147
fix(web): allow CDN scripts in CSP connect-src directive
ilblackdragon Mar 20, 2026
7e63692
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 20, 2026
e355259
style: fix cargo fmt in repl.rs
ilblackdragon Mar 20, 2026
8b81ce7
fix(web): gate turn_cost SSE handler on current thread
ilblackdragon Mar 20, 2026
f75127d
ci: retrigger CI
ilblackdragon Mar 20, 2026
a2248d8
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 20, 2026
d9c5ede
fix: add missing extension_manager to webhook EngineContext
ilblackdragon Mar 20, 2026
8796c7c
chore: ignore RUSTSEC-2026-0049 rustls-webpki CRL advisory
ilblackdragon Mar 21, 2026
9764929
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 21, 2026
2d6faa9
fix(routines): use fields.join for cron normalization
ilblackdragon Mar 21, 2026
8103ee4
feat(repl): Apple-style approval card — clean vertical flow
ilblackdragon Mar 21, 2026
d5d8389
refactor(repl): replace inquire with crossterm for approval selector
ilblackdragon Mar 21, 2026
5de6e60
chore(deps): upgrade crossterm 0.28 → 0.29, eliminate duplication
ilblackdragon Mar 21, 2026
a895123
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 21, 2026
f88f96f
fix: address review comments — box_top off-by-one, smart_truncate ove…
ilblackdragon Mar 21, 2026
37d1e1f
style: cargo fmt repl.rs
ilblackdragon Mar 21, 2026
abb3511
fix: address review — retry duplication, CSP connect-src, deny color
ilblackdragon Mar 21, 2026
1c30e94
Merge remote-tracking branch 'origin/staging' into ux-overhaul
ilblackdragon Mar 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 10 additions & 26 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ async-trait = "0.1"
clap = { version = "4", features = ["derive", "env"] }

# Terminal
crossterm = "0.28"
crossterm = "0.29"
rustyline = { version = "17", features = ["custom-bindings", "derive", "with-file-history"] }
termimad = "0.34"

Expand Down
28 changes: 26 additions & 2 deletions src/agent/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ impl<'a> LoopDelegate for ChatDelegate<'a> {
.channels
.send_status(
&self.message.channel,
StatusUpdate::Thinking("Calling LLM...".into()),
StatusUpdate::Thinking(format!("Thinking (step {iteration})...")),
&self.message.metadata,
)
.await;
Expand Down Expand Up @@ -435,7 +435,7 @@ impl<'a> LoopDelegate for ChatDelegate<'a> {
.channels
.send_status(
&self.message.channel,
StatusUpdate::Thinking(format!("Executing {} tool(s)...", tool_calls.len())),
StatusUpdate::Thinking(contextual_tool_message(&tool_calls)),
&self.message.metadata,
)
.await;
Expand Down Expand Up @@ -969,6 +969,30 @@ pub(super) fn check_auth_required(
Some((name, instructions))
}

/// Build a contextual thinking message based on tool names.
///
/// Instead of a generic "Executing 2 tool(s)..." this returns messages like
/// "Running command..." or "Fetching page..." for single-tool calls, falling
/// back to "Executing N tool(s)..." for multi-tool calls.
fn contextual_tool_message(tool_calls: &[crate::llm::ToolCall]) -> String {
if tool_calls.len() == 1 {
match tool_calls[0].name.as_str() {
"shell" => "Running command...".into(),
"web_fetch" => "Fetching page...".into(),
"memory_search" => "Searching memory...".into(),
"memory_write" => "Writing to memory...".into(),
"memory_read" => "Reading memory...".into(),
"http_request" => "Making HTTP request...".into(),
"file_read" => "Reading file...".into(),
"file_write" => "Writing file...".into(),
"json_transform" => "Transforming data...".into(),
name => format!("Running {name}..."),
}
} else {
format!("Executing {} tool(s)...", tool_calls.len())
}
}

/// Compact messages for retry after a context-length-exceeded error.
///
/// Keeps all `System` messages (which carry the system prompt and instructions),
Expand Down
4 changes: 2 additions & 2 deletions src/agent/routine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -529,8 +529,8 @@ pub fn normalize_cron_expression(schedule: &str) -> String {
let trimmed = schedule.trim();
let fields: Vec<&str> = trimmed.split_whitespace().collect();
match fields.len() {
5 => format!("0 {} *", trimmed),
6 => format!("{} *", trimmed),
5 => format!("0 {} *", fields.join(" ")),
6 => format!("{} *", fields.join(" ")),
_ => trimmed.to_string(),
}
}
Expand Down
27 changes: 27 additions & 0 deletions src/agent/thread_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -556,6 +556,33 @@ impl Agent {
.await;
}

// Emit per-turn cost summary
{
let usage = self.cost_guard().model_usage().await;
let (total_in, total_out, total_cost) =
usage
.values()
.fold((0u64, 0u64, rust_decimal::Decimal::ZERO), |acc, m| {
(
acc.0 + m.input_tokens,
acc.1 + m.output_tokens,
acc.2 + m.cost,
)
});
let _ = self
.channels
.send_status(
&message.channel,
StatusUpdate::TurnCost {
input_tokens: total_in,
output_tokens: total_out,
cost_usd: format!("${:.4}", total_cost),
},
&message.metadata,
)
.await;
Comment on lines +559 to +583

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The u32→u64 overflow concern is fixed in this PR. The cumulative-vs-per-turn design issue is a pre-existing limitation of the CostGuard API — tracking per-turn deltas requires snapshotting before/after, which is a separate change. Filed for follow-up.

}
Comment on lines +559 to +584

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Despite the comment “per-turn cost summary”, this sums CostGuard model usage “since startup” (see cost_guard::model_usage docs), so the emitted tokens/cost will be cumulative across the whole process rather than for the current turn. Track a per-turn baseline (before/after) or accumulate per-turn usage during the submission so TurnCost reflects only the completed turn.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Valid design issue — pre-existing. The u32→u64 widening in this PR addresses the overflow concern. Per-turn delta tracking requires CostGuard API changes, tracked for a separate PR.


Ok(SubmissionResult::response(response))
}
Ok(AgenticLoopResult::NeedApproval { pending }) => {
Expand Down
2 changes: 1 addition & 1 deletion src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ impl AppBuilder {
let b = tools
.register_builder_tool(llm.clone(), Some(self.config.builder.to_builder_config()))
.await;
tracing::info!("Builder mode enabled");
tracing::debug!("Builder mode enabled");
Some(b)
} else {
None
Expand Down
Loading
Loading