additional metrics + Ui implementation (#3871)
This commit is contained in:
@@ -13,7 +13,7 @@ use tracing::info;
|
||||
use goose::providers::pricing::initialize_pricing_cache;
|
||||
|
||||
pub async fn run() -> Result<()> {
|
||||
// Initialize logging
|
||||
// Initialize logging and telemetry
|
||||
crate::logging::setup_logging(Some("goosed"))?;
|
||||
|
||||
let settings = configuration::Settings::new()?;
|
||||
|
||||
@@ -11,7 +11,7 @@ use bytes::Bytes;
|
||||
use futures::{stream::StreamExt, Stream};
|
||||
use goose::{
|
||||
agents::{AgentEvent, SessionConfig},
|
||||
message::{push_message, Message},
|
||||
message::{push_message, Message, MessageContent},
|
||||
permission::permission_confirmation::PrincipalType,
|
||||
};
|
||||
use goose::{
|
||||
@@ -37,6 +37,53 @@ use tokio_stream::wrappers::ReceiverStream;
|
||||
use tokio_util::sync::CancellationToken;
|
||||
use utoipa::ToSchema;
|
||||
|
||||
fn track_tool_telemetry(content: &MessageContent, all_messages: &[Message]) {
|
||||
match content {
|
||||
MessageContent::ToolRequest(tool_request) => {
|
||||
if let Ok(tool_call) = &tool_request.tool_call {
|
||||
tracing::info!(monotonic_counter.goose.tool_calls = 1,
|
||||
tool_name = %tool_call.name,
|
||||
"Tool call started"
|
||||
);
|
||||
}
|
||||
}
|
||||
MessageContent::ToolResponse(tool_response) => {
|
||||
let tool_name = all_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"
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, Serialize)]
|
||||
struct ChatRequest {
|
||||
messages: Vec<Message>,
|
||||
@@ -126,6 +173,15 @@ async fn reply_handler(
|
||||
) -> Result<SseResponse, StatusCode> {
|
||||
verify_secret_key(&headers, &state)?;
|
||||
|
||||
let session_start = std::time::Instant::now();
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_starts = 1,
|
||||
session_type = "app",
|
||||
interface = "ui",
|
||||
"Session started"
|
||||
);
|
||||
|
||||
let (tx, rx) = mpsc::channel(100);
|
||||
let stream = ReceiverStream::new(rx);
|
||||
let cancel_token = CancellationToken::new();
|
||||
@@ -222,8 +278,12 @@ async fn reply_handler(
|
||||
response = timeout(Duration::from_millis(500), stream.next()) => {
|
||||
match response {
|
||||
Ok(Some(Ok(AgentEvent::Message(message)))) => {
|
||||
push_message(&mut all_messages, message.clone());
|
||||
stream_event(MessageEvent::Message { message }, &tx, &cancel_token).await;
|
||||
for content in &message.content {
|
||||
track_tool_telemetry(content, &all_messages);
|
||||
}
|
||||
|
||||
push_message(&mut all_messages, message.clone());
|
||||
stream_event(MessageEvent::Message { message }, &tx, &cancel_token).await;
|
||||
}
|
||||
Ok(Some(Ok(AgentEvent::HistoryReplaced(new_messages)))) => {
|
||||
// Replace the message history with the compacted messages
|
||||
@@ -269,10 +329,12 @@ async fn reply_handler(
|
||||
if all_messages.len() > saved_message_count {
|
||||
if let Ok(provider) = agent.provider().await {
|
||||
let provider = Arc::clone(&provider);
|
||||
let session_path_clone = session_path.to_path_buf();
|
||||
let all_messages_clone = all_messages.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = session::persist_messages(
|
||||
&session_path,
|
||||
&all_messages,
|
||||
&session_path_clone,
|
||||
&all_messages_clone,
|
||||
Some(provider),
|
||||
Some(PathBuf::from(&session_working_dir)),
|
||||
)
|
||||
@@ -284,6 +346,58 @@ async fn reply_handler(
|
||||
}
|
||||
}
|
||||
|
||||
let session_duration = session_start.elapsed();
|
||||
|
||||
if let Ok(metadata) = session::read_metadata(&session_path) {
|
||||
let total_tokens = metadata.total_tokens.unwrap_or(0);
|
||||
let message_count = metadata.message_count;
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_completions = 1,
|
||||
session_type = "app",
|
||||
interface = "ui",
|
||||
exit_type = "normal",
|
||||
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 = "app",
|
||||
interface = "ui",
|
||||
"Session duration"
|
||||
);
|
||||
|
||||
if total_tokens > 0 {
|
||||
tracing::info!(
|
||||
counter.goose.session_tokens = total_tokens,
|
||||
session_type = "app",
|
||||
interface = "ui",
|
||||
"Session tokens"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
tracing::info!(
|
||||
counter.goose.session_completions = 1,
|
||||
session_type = "app",
|
||||
interface = "ui",
|
||||
exit_type = "normal",
|
||||
duration_ms = session_duration.as_millis() as u64,
|
||||
total_tokens = 0u64,
|
||||
message_count = all_messages.len(),
|
||||
"Session completed"
|
||||
);
|
||||
|
||||
tracing::info!(
|
||||
counter.goose.session_duration_ms = session_duration.as_millis() as u64,
|
||||
session_type = "app",
|
||||
interface = "ui",
|
||||
"Session duration"
|
||||
);
|
||||
}
|
||||
|
||||
let _ = stream_event(
|
||||
MessageEvent::Finish {
|
||||
reason: "stop".to_string(),
|
||||
|
||||
Reference in New Issue
Block a user