additional metrics + Ui implementation (#3871)
This commit is contained in:
+102
-31
@@ -16,7 +16,6 @@ use crate::commands::schedule::{
|
||||
handle_schedule_sessions,
|
||||
};
|
||||
use crate::commands::session::{handle_session_list, handle_session_remove};
|
||||
use crate::logging::setup_logging;
|
||||
use crate::recipes::extract_from_cli::extract_recipe_info_from_cli;
|
||||
use crate::recipes::recipe::{explain_recipe, render_recipe_as_yaml};
|
||||
use crate::session;
|
||||
@@ -718,7 +717,7 @@ pub async fn cli() -> Result<()> {
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
monotonic_counter.goose.cli_commands = 1,
|
||||
counter.goose.cli_commands = 1,
|
||||
command = command_name,
|
||||
"CLI command executed"
|
||||
);
|
||||
@@ -779,6 +778,16 @@ pub async fn cli() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
None => {
|
||||
let session_start = std::time::Instant::now();
|
||||
let session_type = if resume { "resumed" } else { "new" };
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_starts = 1,
|
||||
session_type,
|
||||
interactive = true,
|
||||
"Session started"
|
||||
);
|
||||
|
||||
// Run session command by default
|
||||
let mut session: crate::Session = build_session(SessionBuilderConfig {
|
||||
identifier: identifier.map(extract_identifier),
|
||||
@@ -804,21 +813,46 @@ pub async fn cli() -> Result<()> {
|
||||
retry_config: None,
|
||||
})
|
||||
.await;
|
||||
setup_logging(
|
||||
session
|
||||
.session_file()
|
||||
.as_ref()
|
||||
.and_then(|p| p.file_stem())
|
||||
.and_then(|s| s.to_str()),
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Render previous messages if resuming a session and history flag is set
|
||||
if resume && history {
|
||||
session.render_message_history();
|
||||
}
|
||||
|
||||
let _ = session.interactive(None).await;
|
||||
let result = session.interactive(None).await;
|
||||
|
||||
let session_duration = session_start.elapsed();
|
||||
let exit_type = if result.is_ok() { "normal" } else { "error" };
|
||||
|
||||
let (total_tokens, message_count) = session
|
||||
.get_metadata()
|
||||
.map(|m| (m.total_tokens.unwrap_or(0), m.message_count))
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_completions = 1,
|
||||
session_type,
|
||||
exit_type,
|
||||
duration_ms = session_duration.as_millis() as u64,
|
||||
total_tokens,
|
||||
message_count,
|
||||
"Session completed"
|
||||
);
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_duration_ms = session_duration.as_millis() as u64,
|
||||
session_type,
|
||||
"Session duration"
|
||||
);
|
||||
|
||||
if total_tokens > 0 {
|
||||
tracing::info!(
|
||||
counter.goose.session_tokens = total_tokens,
|
||||
session_type,
|
||||
"Session tokens"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
@@ -897,8 +931,13 @@ pub async fn cli() -> Result<()> {
|
||||
(input_config, None)
|
||||
}
|
||||
(_, _, Some(recipe_name)) => {
|
||||
tracing::info!(monotonic_counter.goose.recipe_runs = 1,
|
||||
recipe_name = %recipe_name,
|
||||
let recipe_display_name = std::path::Path::new(&recipe_name)
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.unwrap_or(&recipe_name);
|
||||
|
||||
tracing::info!(counter.goose.recipe_runs = 1,
|
||||
recipe_name = %recipe_display_name,
|
||||
"Recipe execution started"
|
||||
);
|
||||
|
||||
@@ -952,19 +991,59 @@ pub async fn cli() -> Result<()> {
|
||||
})
|
||||
.await;
|
||||
|
||||
setup_logging(
|
||||
session
|
||||
.session_file()
|
||||
.as_ref()
|
||||
.and_then(|p| p.file_stem())
|
||||
.and_then(|s| s.to_str()),
|
||||
None,
|
||||
)?;
|
||||
|
||||
if interactive {
|
||||
let _ = session.interactive(input_config.contents).await;
|
||||
} else if let Some(contents) = input_config.contents {
|
||||
let _ = session.headless(contents).await;
|
||||
let session_start = std::time::Instant::now();
|
||||
let session_type = if recipe_info.is_some() {
|
||||
"recipe"
|
||||
} else {
|
||||
"run"
|
||||
};
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_starts = 1,
|
||||
session_type,
|
||||
interactive = false,
|
||||
"Headless session started"
|
||||
);
|
||||
|
||||
let result = session.headless(contents).await;
|
||||
|
||||
let session_duration = session_start.elapsed();
|
||||
let exit_type = if result.is_ok() { "normal" } else { "error" };
|
||||
|
||||
let (total_tokens, message_count) = session
|
||||
.get_metadata()
|
||||
.map(|m| (m.total_tokens.unwrap_or(0), m.message_count))
|
||||
.unwrap_or((0, 0));
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_completions = 1,
|
||||
session_type,
|
||||
exit_type,
|
||||
duration_ms = session_duration.as_millis() as u64,
|
||||
total_tokens,
|
||||
message_count,
|
||||
interactive = false,
|
||||
"Headless session completed"
|
||||
);
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_duration_ms = session_duration.as_millis() as u64,
|
||||
session_type,
|
||||
"Headless session duration"
|
||||
);
|
||||
|
||||
if total_tokens > 0 {
|
||||
tracing::info!(
|
||||
counter.goose.session_tokens = total_tokens,
|
||||
session_type,
|
||||
"Headless session tokens"
|
||||
);
|
||||
}
|
||||
|
||||
result?;
|
||||
} else {
|
||||
eprintln!("Error: no text provided for prompt in headless mode");
|
||||
std::process::exit(1);
|
||||
@@ -1083,14 +1162,6 @@ pub async fn cli() -> Result<()> {
|
||||
retry_config: None,
|
||||
})
|
||||
.await;
|
||||
setup_logging(
|
||||
session
|
||||
.session_file()
|
||||
.as_ref()
|
||||
.and_then(|p| p.file_stem())
|
||||
.and_then(|s| s.to_str()),
|
||||
None,
|
||||
)?;
|
||||
if let Err(e) = session.interactive(None).await {
|
||||
eprintln!("Session ended with error: {}", e);
|
||||
}
|
||||
|
||||
@@ -3,5 +3,32 @@ use goose_cli::cli::cli;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
cli().await
|
||||
if let Err(e) = goose_cli::logging::setup_logging(None, None) {
|
||||
eprintln!("Warning: Failed to initialize telemetry: {}", e);
|
||||
}
|
||||
|
||||
let result = cli().await;
|
||||
|
||||
// Only wait for telemetry flush if OTLP is configured
|
||||
if std::env::var("OTEL_EXPORTER_OTLP_ENDPOINT").is_ok() {
|
||||
// Use a shorter, dynamic wait with max timeout
|
||||
let max_wait = tokio::time::Duration::from_millis(500);
|
||||
let start = tokio::time::Instant::now();
|
||||
|
||||
// Give telemetry a chance to flush, but don't wait too long
|
||||
while start.elapsed() < max_wait {
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(50)).await;
|
||||
|
||||
// In future, we could check if there are pending spans/metrics here
|
||||
// For now, we just do a quick wait to allow batch exports to complete
|
||||
if start.elapsed() >= tokio::time::Duration::from_millis(200) {
|
||||
break; // Most exports should complete within 200ms
|
||||
}
|
||||
}
|
||||
|
||||
// Then shutdown the providers
|
||||
goose::tracing::shutdown_otlp();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
@@ -851,7 +851,8 @@ impl Session {
|
||||
pub async fn headless(&mut self, prompt: String) -> Result<()> {
|
||||
let message = Message::user().with_text(&prompt);
|
||||
self.process_message(message, CancellationToken::default())
|
||||
.await
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn process_agent_response(
|
||||
@@ -1023,12 +1024,45 @@ impl Session {
|
||||
for content in &message.content {
|
||||
if let MessageContent::ToolRequest(tool_request) = content {
|
||||
if let Ok(tool_call) = &tool_request.tool_call {
|
||||
tracing::info!(monotonic_counter.goose.tool_calls = 1,
|
||||
tracing::info!(counter.goose.tool_calls = 1,
|
||||
tool_name = %tool_call.name,
|
||||
"Tool call executed"
|
||||
"Tool call started"
|
||||
);
|
||||
}
|
||||
}
|
||||
if let MessageContent::ToolResponse(tool_response) = content {
|
||||
let tool_name = self.messages
|
||||
.iter()
|
||||
.rev()
|
||||
.find_map(|msg| {
|
||||
msg.content.iter().find_map(|c| {
|
||||
if let MessageContent::ToolRequest(req) = c {
|
||||
if req.id == tool_response.id {
|
||||
if let Ok(tool_call) = &req.tool_call {
|
||||
Some(tool_call.name.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| "unknown".to_string());
|
||||
|
||||
let success = tool_response.tool_result.is_ok();
|
||||
let result_status = if success { "success" } else { "error" };
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.tool_completions = 1,
|
||||
tool_name = %tool_name,
|
||||
result = %result_status,
|
||||
"Tool call completed"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
push_message(&mut self.messages, message.clone());
|
||||
|
||||
Reference in New Issue
Block a user