diff --git a/crates/goose-cli/src/cli.rs b/crates/goose-cli/src/cli.rs index 76edd308dd8d..f3ed00c657b7 100644 --- a/crates/goose-cli/src/cli.rs +++ b/crates/goose-cli/src/cli.rs @@ -941,8 +941,25 @@ pub async fn cli() -> Result<()> { .and_then(|name| name.to_str()) .unwrap_or(&recipe_name); - tracing::info!(counter.goose.recipe_runs = 1, + let recipe_version = + crate::recipes::search_recipe::retrieve_recipe_file(&recipe_name) + .ok() + .and_then(|rf| { + goose::recipe::template_recipe::parse_recipe_content( + &rf.content, + rf.parent_dir.to_string_lossy().to_string(), + ) + .ok() + .map(|(r, _)| r.version) + }) + .unwrap_or_else(|| "unknown".to_string()); + + tracing::info!( + counter.goose.recipe_runs = 1, recipe_name = %recipe_display_name, + recipe_version = %recipe_version, + session_type = "recipe", + interface = "cli", "Recipe execution started" ); diff --git a/crates/goose-server/src/routes/reply.rs b/crates/goose-server/src/routes/reply.rs index dd45ff598903..0b75a913777e 100644 --- a/crates/goose-server/src/routes/reply.rs +++ b/crates/goose-server/src/routes/reply.rs @@ -91,6 +91,8 @@ struct ChatRequest { session_id: Option, session_working_dir: String, scheduled_job_id: Option, + recipe_name: Option, + recipe_version: Option, } pub struct SseResponse { @@ -183,6 +185,19 @@ async fn reply_handler( "Session started" ); + if let Some(recipe_name) = &request.recipe_name { + let recipe_version = request.recipe_version.as_deref().unwrap_or("unknown"); + + tracing::info!( + counter.goose.recipe_runs = 1, + recipe_name = %recipe_name, + recipe_version = %recipe_version, + session_type = "app", + interface = "ui", + "Recipe execution started" + ); + } + let (tx, rx) = mpsc::channel(100); let stream = ReceiverStream::new(rx); let cancel_token = CancellationToken::new(); @@ -585,6 +600,8 @@ mod tests { session_id: Some("test-session".to_string()), session_working_dir: "test-working-dir".to_string(), scheduled_job_id: None, + recipe_name: None, + recipe_version: None, }) .unwrap(), )) diff --git a/crates/goose-server/src/routes/schedule.rs b/crates/goose-server/src/routes/schedule.rs index 64df30aa5625..cda501a5c4f4 100644 --- a/crates/goose-server/src/routes/schedule.rs +++ b/crates/goose-server/src/routes/schedule.rs @@ -231,6 +231,53 @@ async fn run_now_handler( .await .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let recipe_display_name = match scheduler.list_scheduled_jobs().await { + Ok(jobs) => jobs + .into_iter() + .find(|job| job.id == id) + .and_then(|job| { + std::path::Path::new(&job.source) + .file_name() + .and_then(|name| name.to_str()) + .map(|s| s.to_string()) + }) + .unwrap_or_else(|| id.clone()), + Err(_) => id.clone(), + }; + + let recipe_version = match scheduler.list_scheduled_jobs().await { + Ok(jobs) => jobs + .into_iter() + .find(|job| job.id == id) + .and_then(|job| { + std::fs::read_to_string(&job.source) + .ok() + .and_then(|content| { + goose::recipe::template_recipe::parse_recipe_content( + &content, + std::path::Path::new(&job.source) + .parent() + .unwrap_or_else(|| std::path::Path::new("")) + .to_string_lossy() + .to_string(), + ) + .ok() + .map(|(r, _)| r.version) + }) + }) + .unwrap_or_else(|| "unknown".to_string()), + Err(_) => "unknown".to_string(), + }; + + tracing::info!( + counter.goose.recipe_runs = 1, + recipe_name = %recipe_display_name, + recipe_version = %recipe_version, + session_type = "schedule", + interface = "server", + "Recipe execution started" + ); + tracing::info!("Server: Calling scheduler.run_now() for job '{}'", id); match scheduler.run_now(&id).await { diff --git a/ui/desktop/src/hooks/useChatEngine.ts b/ui/desktop/src/hooks/useChatEngine.ts index d76db361eb6e..8c53f0a40d36 100644 --- a/ui/desktop/src/hooks/useChatEngine.ts +++ b/ui/desktop/src/hooks/useChatEngine.ts @@ -101,7 +101,16 @@ export const useChatEngine = ({ api: getApiUrl('/reply'), id: chat.id, initialMessages: chat.messages, - body: { session_id: chat.id, session_working_dir: window.appConfig.get('GOOSE_WORKING_DIR') }, + body: { + session_id: chat.id, + session_working_dir: window.appConfig.get('GOOSE_WORKING_DIR'), + ...(chat.recipeConfig?.title + ? { + recipe_name: chat.recipeConfig.title, + recipe_version: chat.recipeConfig?.version ?? 'unknown', + } + : {}), + }, onFinish: async (_message, _reason) => { stopPowerSaveBlocker();