Fix timing footer being saved to context window
The timing footer (e.g., ⏱️ 19.4s | 💭 4.7s) was being saved to the conversation history as a separate assistant message. This happened because stream_completion_with_tools returns the timing footer in TaskResult.response for display, but the caller was also saving it to context. Fix: Strip the timing footer (identified by \n\n⏱️) before saving to context window. The timing footer remains display-only. Also includes: - Research tool blank line fix: only add visual separator for research tool output, not all tools - Research tool webdriver propagation: pass parent's webdriver browser choice (Safari vs Chrome headless) to scout subprocess
This commit is contained in:
@@ -231,8 +231,6 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print_tool_timing(&self, duration_str: &str, tokens_delta: u32, context_percentage: f32) {
|
fn print_tool_timing(&self, duration_str: &str, tokens_delta: u32, context_percentage: f32) {
|
||||||
// Add blank line before footer for visual separation
|
|
||||||
println!();
|
|
||||||
// Parse the duration string to determine color
|
// Parse the duration string to determine color
|
||||||
// Format is like "1.5s", "500ms", "2m 30.0s"
|
// Format is like "1.5s", "500ms", "2m 30.0s"
|
||||||
let color_code = if duration_str.ends_with("ms") {
|
let color_code = if duration_str.ends_with("ms") {
|
||||||
@@ -274,6 +272,12 @@ impl UiWriter for ConsoleUiWriter {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add blank line before footer for research tool (its output is a full report)
|
||||||
|
if let Some(tool_name) = self.current_tool_name.lock().unwrap().as_ref() {
|
||||||
|
if tool_name == "research" {
|
||||||
|
println!();
|
||||||
|
}
|
||||||
|
}
|
||||||
println!("└─ ⚡️ {}{}\x1b[0m \x1b[2m{} ◉ | {:.0}%\x1b[0m", color_code, duration_str, tokens_delta, context_percentage);
|
println!("└─ ⚡️ {}{}\x1b[0m \x1b[2m{} ◉ | {:.0}%\x1b[0m", color_code, duration_str, tokens_delta, context_percentage);
|
||||||
println!();
|
println!();
|
||||||
// Clear the stored tool info
|
// Clear the stored tool info
|
||||||
|
|||||||
@@ -851,8 +851,14 @@ impl<W: UiWriter> Agent<W> {
|
|||||||
|
|
||||||
// Add assistant response to context window only if not empty
|
// Add assistant response to context window only if not empty
|
||||||
// This prevents the "Skipping empty message" warning when only tools were executed
|
// This prevents the "Skipping empty message" warning when only tools were executed
|
||||||
if !response_content.trim().is_empty() {
|
// Also strip timing footer - it's display-only and shouldn't be in context
|
||||||
let assistant_message = Message::new(MessageRole::Assistant, response_content.clone());
|
let content_for_context = if let Some(timing_pos) = response_content.rfind("\n\n⏱️") {
|
||||||
|
response_content[..timing_pos].to_string()
|
||||||
|
} else {
|
||||||
|
response_content.clone()
|
||||||
|
};
|
||||||
|
if !content_for_context.trim().is_empty() {
|
||||||
|
let assistant_message = Message::new(MessageRole::Assistant, content_for_context);
|
||||||
self.context_window.add_message(assistant_message);
|
self.context_window.add_message(assistant_message);
|
||||||
} else {
|
} else {
|
||||||
debug!("Assistant response was empty (likely only tool execution), skipping message addition");
|
debug!("Assistant response was empty (likely only tool execution), skipping message addition");
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use tokio::process::Command;
|
|||||||
|
|
||||||
use crate::ui_writer::UiWriter;
|
use crate::ui_writer::UiWriter;
|
||||||
use crate::ToolCall;
|
use crate::ToolCall;
|
||||||
|
use g3_config::WebDriverBrowser;
|
||||||
|
|
||||||
use super::executor::ToolContext;
|
use super::executor::ToolContext;
|
||||||
|
|
||||||
@@ -156,14 +157,21 @@ pub async fn execute_research<W: UiWriter>(
|
|||||||
let g3_path = std::env::current_exe()
|
let g3_path = std::env::current_exe()
|
||||||
.unwrap_or_else(|_| std::path::PathBuf::from("g3"));
|
.unwrap_or_else(|_| std::path::PathBuf::from("g3"));
|
||||||
|
|
||||||
// Spawn the scout agent
|
// Build the command with appropriate webdriver flags
|
||||||
let mut child = Command::new(&g3_path)
|
let mut cmd = Command::new(&g3_path);
|
||||||
|
cmd
|
||||||
.arg("--agent")
|
.arg("--agent")
|
||||||
.arg("scout")
|
.arg("scout")
|
||||||
.arg("--webdriver") // Scout needs webdriver for web research
|
|
||||||
.arg("--new-session") // Always start fresh for research
|
.arg("--new-session") // Always start fresh for research
|
||||||
.arg("--quiet") // Suppress log file creation
|
.arg("--quiet"); // Suppress log file creation
|
||||||
.arg(query)
|
|
||||||
|
// Propagate the webdriver browser choice from the parent g3 instance
|
||||||
|
match ctx.config.webdriver.browser {
|
||||||
|
WebDriverBrowser::ChromeHeadless => { cmd.arg("--chrome-headless"); }
|
||||||
|
WebDriverBrowser::Safari => { cmd.arg("--webdriver"); }
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut child = cmd.arg(query)
|
||||||
.stdout(Stdio::piped())
|
.stdout(Stdio::piped())
|
||||||
.stderr(Stdio::piped())
|
.stderr(Stdio::piped())
|
||||||
.spawn()
|
.spawn()
|
||||||
|
|||||||
Reference in New Issue
Block a user