feat(cli): add --debug flag to goose session / run (#1564)
This commit is contained in:
@@ -83,8 +83,14 @@ async fn run_eval(
|
|||||||
let requirements = evaluation.required_extensions();
|
let requirements = evaluation.required_extensions();
|
||||||
|
|
||||||
// Create session with error capture
|
// Create session with error capture
|
||||||
let base_session =
|
let base_session = build_session(
|
||||||
build_session(None, false, requirements.external, requirements.builtin).await;
|
None,
|
||||||
|
false,
|
||||||
|
requirements.external,
|
||||||
|
requirements.builtin,
|
||||||
|
false,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let bench_session = Arc::new(Mutex::new(BenchSession::new(base_session)));
|
let bench_session = Arc::new(Mutex::new(BenchSession::new(base_session)));
|
||||||
let bench_session_clone = bench_session.clone();
|
let bench_session_clone = bench_session.clone();
|
||||||
|
|||||||
@@ -90,6 +90,14 @@ enum Command {
|
|||||||
)]
|
)]
|
||||||
resume: bool,
|
resume: bool,
|
||||||
|
|
||||||
|
/// Enable debug output mode
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "Enable debug output mode with full content and no truncation",
|
||||||
|
long_help = "When enabled, shows complete tool responses without truncation and full paths."
|
||||||
|
)]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
/// Add stdio extensions with environment variables and commands
|
/// Add stdio extensions with environment variables and commands
|
||||||
#[arg(
|
#[arg(
|
||||||
long = "with-extension",
|
long = "with-extension",
|
||||||
@@ -157,6 +165,14 @@ enum Command {
|
|||||||
)]
|
)]
|
||||||
resume: bool,
|
resume: bool,
|
||||||
|
|
||||||
|
/// Enable debug output mode
|
||||||
|
#[arg(
|
||||||
|
long,
|
||||||
|
help = "Enable debug output mode with full content and no truncation",
|
||||||
|
long_help = "When enabled, shows complete tool responses without truncation and full paths."
|
||||||
|
)]
|
||||||
|
debug: bool,
|
||||||
|
|
||||||
/// Add stdio extensions with environment variables and commands
|
/// Add stdio extensions with environment variables and commands
|
||||||
#[arg(
|
#[arg(
|
||||||
long = "with-extension",
|
long = "with-extension",
|
||||||
@@ -285,6 +301,7 @@ async fn main() -> Result<()> {
|
|||||||
Some(Command::Session {
|
Some(Command::Session {
|
||||||
identifier,
|
identifier,
|
||||||
resume,
|
resume,
|
||||||
|
debug,
|
||||||
extension,
|
extension,
|
||||||
builtin,
|
builtin,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -293,6 +310,7 @@ async fn main() -> Result<()> {
|
|||||||
resume,
|
resume,
|
||||||
extension,
|
extension,
|
||||||
builtin,
|
builtin,
|
||||||
|
debug,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
@@ -306,6 +324,7 @@ async fn main() -> Result<()> {
|
|||||||
interactive,
|
interactive,
|
||||||
identifier,
|
identifier,
|
||||||
resume,
|
resume,
|
||||||
|
debug,
|
||||||
extension,
|
extension,
|
||||||
builtin,
|
builtin,
|
||||||
}) => {
|
}) => {
|
||||||
@@ -332,6 +351,7 @@ async fn main() -> Result<()> {
|
|||||||
resume,
|
resume,
|
||||||
extension,
|
extension,
|
||||||
builtin,
|
builtin,
|
||||||
|
debug,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
setup_logging(session.session_file().file_stem().and_then(|s| s.to_str()))?;
|
setup_logging(session.session_file().file_stem().and_then(|s| s.to_str()))?;
|
||||||
@@ -410,7 +430,7 @@ async fn main() -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
} else {
|
} else {
|
||||||
// Run session command by default
|
// Run session command by default
|
||||||
let mut session = build_session(None, false, vec![], vec![]).await;
|
let mut session = build_session(None, false, vec![], vec![], false).await;
|
||||||
setup_logging(session.session_file().file_stem().and_then(|s| s.to_str()))?;
|
setup_logging(session.session_file().file_stem().and_then(|s| s.to_str()))?;
|
||||||
let _ = session.interactive(None).await;
|
let _ = session.interactive(None).await;
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ pub async fn build_session(
|
|||||||
resume: bool,
|
resume: bool,
|
||||||
extensions: Vec<String>,
|
extensions: Vec<String>,
|
||||||
builtins: Vec<String>,
|
builtins: Vec<String>,
|
||||||
|
debug: bool,
|
||||||
) -> Session {
|
) -> Session {
|
||||||
// Load config and get provider/model
|
// Load config and get provider/model
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
@@ -92,7 +93,7 @@ pub async fn build_session(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Create new session
|
// Create new session
|
||||||
let mut session = Session::new(agent, session_file.clone());
|
let mut session = Session::new(agent, session_file.clone(), debug);
|
||||||
|
|
||||||
// Add extensions if provided
|
// Add extensions if provided
|
||||||
for extension_str in extensions {
|
for extension_str in extensions {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ pub struct Session {
|
|||||||
session_file: PathBuf,
|
session_file: PathBuf,
|
||||||
// Cache for completion data - using std::sync for thread safety without async
|
// Cache for completion data - using std::sync for thread safety without async
|
||||||
completion_cache: Arc<std::sync::RwLock<CompletionCache>>,
|
completion_cache: Arc<std::sync::RwLock<CompletionCache>>,
|
||||||
|
debug: bool, // New field for debug mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache structure for completion data
|
// Cache structure for completion data
|
||||||
@@ -56,7 +57,7 @@ impl CompletionCache {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn new(agent: Box<dyn Agent>, session_file: PathBuf) -> Self {
|
pub fn new(agent: Box<dyn Agent>, session_file: PathBuf, debug: bool) -> Self {
|
||||||
let messages = match session::read_messages(&session_file) {
|
let messages = match session::read_messages(&session_file) {
|
||||||
Ok(msgs) => msgs,
|
Ok(msgs) => msgs,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@@ -70,6 +71,7 @@ impl Session {
|
|||||||
messages,
|
messages,
|
||||||
session_file,
|
session_file,
|
||||||
completion_cache: Arc::new(std::sync::RwLock::new(CompletionCache::new())),
|
completion_cache: Arc::new(std::sync::RwLock::new(CompletionCache::new())),
|
||||||
|
debug,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,7 +395,7 @@ impl Session {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if msg.role == mcp_core::Role::User {
|
if msg.role == mcp_core::Role::User {
|
||||||
output::render_message(&msg);
|
output::render_message(&msg, self.debug);
|
||||||
}
|
}
|
||||||
self.messages.push(msg);
|
self.messages.push(msg);
|
||||||
}
|
}
|
||||||
@@ -461,7 +463,7 @@ impl Session {
|
|||||||
session::persist_messages(&self.session_file, &self.messages, None).await?;
|
session::persist_messages(&self.session_file, &self.messages, None).await?;
|
||||||
|
|
||||||
if interactive {output::hide_thinking()};
|
if interactive {output::hide_thinking()};
|
||||||
output::render_message(&message);
|
output::render_message(&message, self.debug);
|
||||||
if interactive {output::show_thinking()};
|
if interactive {output::show_thinking()};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,7 +549,7 @@ impl Session {
|
|||||||
// No need for description update here
|
// No need for description update here
|
||||||
session::persist_messages(&self.session_file, &self.messages, None).await?;
|
session::persist_messages(&self.session_file, &self.messages, None).await?;
|
||||||
|
|
||||||
output::render_message(&Message::assistant().with_text(&prompt));
|
output::render_message(&Message::assistant().with_text(&prompt), self.debug);
|
||||||
} else {
|
} else {
|
||||||
// An interruption occurred outside of a tool request-response.
|
// An interruption occurred outside of a tool request-response.
|
||||||
if let Some(last_msg) = self.messages.last() {
|
if let Some(last_msg) = self.messages.last() {
|
||||||
@@ -562,13 +564,19 @@ impl Session {
|
|||||||
session::persist_messages(&self.session_file, &self.messages, None)
|
session::persist_messages(&self.session_file, &self.messages, None)
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
output::render_message(&Message::assistant().with_text(prompt));
|
output::render_message(
|
||||||
|
&Message::assistant().with_text(prompt),
|
||||||
|
self.debug,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Some(_) => {
|
Some(_) => {
|
||||||
// A real users message
|
// A real users message
|
||||||
self.messages.pop();
|
self.messages.pop();
|
||||||
let prompt = "Interrupted before the model replied and removed the last message.";
|
let prompt = "Interrupted before the model replied and removed the last message.";
|
||||||
output::render_message(&Message::assistant().with_text(prompt));
|
output::render_message(
|
||||||
|
&Message::assistant().with_text(prompt),
|
||||||
|
self.debug,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
None => panic!("No content in last message"),
|
None => panic!("No content in last message"),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,14 +96,14 @@ pub fn hide_thinking() {
|
|||||||
THINKING.with(|t| t.borrow_mut().hide());
|
THINKING.with(|t| t.borrow_mut().hide());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn render_message(message: &Message) {
|
pub fn render_message(message: &Message, debug: bool) {
|
||||||
let theme = get_theme();
|
let theme = get_theme();
|
||||||
|
|
||||||
for content in &message.content {
|
for content in &message.content {
|
||||||
match content {
|
match content {
|
||||||
MessageContent::Text(text) => print_markdown(&text.text, theme),
|
MessageContent::Text(text) => print_markdown(&text.text, theme),
|
||||||
MessageContent::ToolRequest(req) => render_tool_request(req, theme),
|
MessageContent::ToolRequest(req) => render_tool_request(req, theme, debug),
|
||||||
MessageContent::ToolResponse(resp) => render_tool_response(resp, theme),
|
MessageContent::ToolResponse(resp) => render_tool_response(resp, theme, debug),
|
||||||
MessageContent::Image(image) => {
|
MessageContent::Image(image) => {
|
||||||
println!("Image: [data: {}, type: {}]", image.data, image.mime_type);
|
println!("Image: [data: {}, type: {}]", image.data, image.mime_type);
|
||||||
}
|
}
|
||||||
@@ -126,18 +126,18 @@ pub fn render_message(message: &Message) {
|
|||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_tool_request(req: &ToolRequest, theme: Theme) {
|
fn render_tool_request(req: &ToolRequest, theme: Theme, debug: bool) {
|
||||||
match &req.tool_call {
|
match &req.tool_call {
|
||||||
Ok(call) => match call.name.as_str() {
|
Ok(call) => match call.name.as_str() {
|
||||||
"developer__text_editor" => render_text_editor_request(call),
|
"developer__text_editor" => render_text_editor_request(call, debug),
|
||||||
"developer__shell" => render_shell_request(call),
|
"developer__shell" => render_shell_request(call, debug),
|
||||||
_ => render_default_request(call),
|
_ => render_default_request(call, debug),
|
||||||
},
|
},
|
||||||
Err(e) => print_markdown(&e.to_string(), theme),
|
Err(e) => print_markdown(&e.to_string(), theme),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_tool_response(resp: &ToolResponse, theme: Theme) {
|
fn render_tool_response(resp: &ToolResponse, theme: Theme, debug: bool) {
|
||||||
let config = Config::global();
|
let config = Config::global();
|
||||||
|
|
||||||
match &resp.tool_result {
|
match &resp.tool_result {
|
||||||
@@ -157,12 +157,14 @@ fn render_tool_response(resp: &ToolResponse, theme: Theme) {
|
|||||||
if content
|
if content
|
||||||
.priority()
|
.priority()
|
||||||
.is_some_and(|priority| priority < min_priority)
|
.is_some_and(|priority| priority < min_priority)
|
||||||
|| content.priority().is_none()
|
|| (content.priority().is_none() && !debug)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let mcp_core::content::Content::Text(text) = content {
|
if debug {
|
||||||
|
println!("{:#?}", content);
|
||||||
|
} else if let mcp_core::content::Content::Text(text) = content {
|
||||||
print_markdown(&text.text, theme);
|
print_markdown(&text.text, theme);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -266,7 +268,7 @@ pub fn render_builtin_error(names: &str, error: &str) {
|
|||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_text_editor_request(call: &ToolCall) {
|
fn render_text_editor_request(call: &ToolCall, debug: bool) {
|
||||||
print_tool_header(call);
|
print_tool_header(call);
|
||||||
|
|
||||||
// Print path first with special formatting
|
// Print path first with special formatting
|
||||||
@@ -274,7 +276,7 @@ fn render_text_editor_request(call: &ToolCall) {
|
|||||||
println!(
|
println!(
|
||||||
"{}: {}",
|
"{}: {}",
|
||||||
style("path").dim(),
|
style("path").dim(),
|
||||||
style(shorten_path(path)).green()
|
style(shorten_path(path, debug)).green()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,26 +288,26 @@ fn render_text_editor_request(call: &ToolCall) {
|
|||||||
other_args.insert(k.clone(), v.clone());
|
other_args.insert(k.clone(), v.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_params(&Value::Object(other_args), 0);
|
print_params(&Value::Object(other_args), 0, debug);
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_shell_request(call: &ToolCall) {
|
fn render_shell_request(call: &ToolCall, debug: bool) {
|
||||||
print_tool_header(call);
|
print_tool_header(call);
|
||||||
|
|
||||||
match call.arguments.get("command") {
|
match call.arguments.get("command") {
|
||||||
Some(Value::String(s)) => {
|
Some(Value::String(s)) => {
|
||||||
println!("{}: {}", style("command").dim(), style(s).green());
|
println!("{}: {}", style("command").dim(), style(s).green());
|
||||||
}
|
}
|
||||||
_ => print_params(&call.arguments, 0),
|
_ => print_params(&call.arguments, 0, debug),
|
||||||
}
|
}
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_default_request(call: &ToolCall) {
|
fn render_default_request(call: &ToolCall, debug: bool) {
|
||||||
print_tool_header(call);
|
print_tool_header(call);
|
||||||
print_params(&call.arguments, 0);
|
print_params(&call.arguments, 0, debug);
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,7 +344,7 @@ fn print_markdown(content: &str, theme: Theme) {
|
|||||||
const MAX_STRING_LENGTH: usize = 40;
|
const MAX_STRING_LENGTH: usize = 40;
|
||||||
const INDENT: &str = " ";
|
const INDENT: &str = " ";
|
||||||
|
|
||||||
fn print_params(value: &Value, depth: usize) {
|
fn print_params(value: &Value, depth: usize, debug: bool) {
|
||||||
let indent = INDENT.repeat(depth);
|
let indent = INDENT.repeat(depth);
|
||||||
|
|
||||||
match value {
|
match value {
|
||||||
@@ -351,17 +353,17 @@ fn print_params(value: &Value, depth: usize) {
|
|||||||
match val {
|
match val {
|
||||||
Value::Object(_) => {
|
Value::Object(_) => {
|
||||||
println!("{}{}:", indent, style(key).dim());
|
println!("{}{}:", indent, style(key).dim());
|
||||||
print_params(val, depth + 1);
|
print_params(val, depth + 1, debug);
|
||||||
}
|
}
|
||||||
Value::Array(arr) => {
|
Value::Array(arr) => {
|
||||||
println!("{}{}:", indent, style(key).dim());
|
println!("{}{}:", indent, style(key).dim());
|
||||||
for item in arr.iter() {
|
for item in arr.iter() {
|
||||||
println!("{}{}- ", indent, INDENT);
|
println!("{}{}- ", indent, INDENT);
|
||||||
print_params(item, depth + 2);
|
print_params(item, depth + 2, debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
if s.len() > MAX_STRING_LENGTH {
|
if !debug && s.len() > MAX_STRING_LENGTH {
|
||||||
println!("{}{}: {}", indent, style(key).dim(), style("...").dim());
|
println!("{}{}: {}", indent, style(key).dim(), style("...").dim());
|
||||||
} else {
|
} else {
|
||||||
println!("{}{}: {}", indent, style(key).dim(), style(s).green());
|
println!("{}{}: {}", indent, style(key).dim(), style(s).green());
|
||||||
@@ -382,11 +384,11 @@ fn print_params(value: &Value, depth: usize) {
|
|||||||
Value::Array(arr) => {
|
Value::Array(arr) => {
|
||||||
for (i, item) in arr.iter().enumerate() {
|
for (i, item) in arr.iter().enumerate() {
|
||||||
println!("{}{}.", indent, i + 1);
|
println!("{}{}.", indent, i + 1);
|
||||||
print_params(item, depth + 1);
|
print_params(item, depth + 1, debug);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Value::String(s) => {
|
Value::String(s) => {
|
||||||
if s.len() > MAX_STRING_LENGTH {
|
if !debug && s.len() > MAX_STRING_LENGTH {
|
||||||
println!(
|
println!(
|
||||||
"{}{}",
|
"{}{}",
|
||||||
indent,
|
indent,
|
||||||
@@ -408,7 +410,12 @@ fn print_params(value: &Value, depth: usize) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shorten_path(path: &str) -> String {
|
fn shorten_path(path: &str, debug: bool) -> String {
|
||||||
|
// In debug mode, return the full path
|
||||||
|
if debug {
|
||||||
|
return path.to_string();
|
||||||
|
}
|
||||||
|
|
||||||
let path = Path::new(path);
|
let path = Path::new(path);
|
||||||
|
|
||||||
// First try to convert to ~ if it's in home directory
|
// First try to convert to ~ if it's in home directory
|
||||||
@@ -485,9 +492,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_short_paths_unchanged() {
|
fn test_short_paths_unchanged() {
|
||||||
assert_eq!(shorten_path("/usr/bin"), "/usr/bin");
|
assert_eq!(shorten_path("/usr/bin", false), "/usr/bin");
|
||||||
assert_eq!(shorten_path("/a/b/c"), "/a/b/c");
|
assert_eq!(shorten_path("/a/b/c", false), "/a/b/c");
|
||||||
assert_eq!(shorten_path("file.txt"), "file.txt");
|
assert_eq!(shorten_path("file.txt", false), "file.txt");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_debug_mode_returns_full_path() {
|
||||||
|
assert_eq!(
|
||||||
|
shorten_path("/very/long/path/that/would/normally/be/shortened", true),
|
||||||
|
"/very/long/path/that/would/normally/be/shortened"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@@ -499,13 +514,13 @@ mod tests {
|
|||||||
env::set_var("HOME", "/Users/testuser");
|
env::set_var("HOME", "/Users/testuser");
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
shorten_path("/Users/testuser/documents/file.txt"),
|
shorten_path("/Users/testuser/documents/file.txt", false),
|
||||||
"~/documents/file.txt"
|
"~/documents/file.txt"
|
||||||
);
|
);
|
||||||
|
|
||||||
// A path that starts similarly to home but isn't in home
|
// A path that starts similarly to home but isn't in home
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
shorten_path("/Users/testuser2/documents/file.txt"),
|
shorten_path("/Users/testuser2/documents/file.txt", false),
|
||||||
"/Users/testuser2/documents/file.txt"
|
"/Users/testuser2/documents/file.txt"
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -521,7 +536,8 @@ mod tests {
|
|||||||
fn test_long_path_shortening() {
|
fn test_long_path_shortening() {
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
shorten_path(
|
shorten_path(
|
||||||
"/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv/long/path/with/many/components/file.txt"
|
"/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv/long/path/with/many/components/file.txt",
|
||||||
|
false
|
||||||
),
|
),
|
||||||
"/v/l/p/w/m/components/file.txt"
|
"/v/l/p/w/m/components/file.txt"
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user