diff --git a/server/src/chat/transport/matrix/bot/format.rs b/server/src/chat/transport/matrix/bot/format.rs index 93413721..649083e4 100644 --- a/server/src/chat/transport/matrix/bot/format.rs +++ b/server/src/chat/transport/matrix/bot/format.rs @@ -11,10 +11,18 @@ pub fn format_startup_announcement(bot_name: &str) -> String { /// Format the ready announcement sent after a successful gateway trampoline restart. /// -/// Returns "gateway X.Y.Z ready" using the compiled-in crate version so the -/// operator can confirm which binary is running after a rebuild. -pub fn format_gateway_ready_announcement() -> String { - format!("gateway {} ready", env!("CARGO_PKG_VERSION")) +/// Returns "gateway X.Y.Z (git_hash) ready — model: " using the compiled-in +/// crate version (same source as `/api/version`), the given git hash, and the +/// configured chat model, so the operator can confirm which binary and model are +/// running after a rebuild. `git_hash` should already have been resolved to +/// `"unknown"` by the caller if unavailable. `model` is `None` when `bot.toml` +/// has no `model` override configured, in which case the CLI's own default applies. +pub fn format_gateway_ready_announcement(git_hash: &str, model: Option<&str>) -> String { + format!( + "gateway {} ({git_hash}) ready — model: {}", + env!("CARGO_PKG_VERSION"), + model.unwrap_or("default") + ) } /// Format the failure announcement sent when the trampoline rolls back to the @@ -170,6 +178,38 @@ mod tests { ); } + #[test] + fn gateway_ready_announcement_includes_version_hash_and_model() { + let msg = format_gateway_ready_announcement("abc1234", Some("claude-sonnet-5")); + assert!( + msg.contains(env!("CARGO_PKG_VERSION")), + "expected crate version in announcement: {msg}" + ); + assert!(msg.contains("abc1234"), "expected git hash: {msg}"); + assert!( + msg.contains("claude-sonnet-5"), + "expected configured model: {msg}" + ); + } + + #[test] + fn gateway_ready_announcement_renders_unknown_git_hash_cleanly() { + let msg = format_gateway_ready_announcement("unknown", Some("claude-sonnet-5")); + assert!( + msg.contains("unknown"), + "expected 'unknown' fallback for missing git hash: {msg}" + ); + } + + #[test] + fn gateway_ready_announcement_falls_back_to_default_when_model_absent() { + let msg = format_gateway_ready_announcement("abc1234", None); + assert!( + msg.contains("default"), + "expected 'default' fallback when no model configured: {msg}" + ); + } + #[test] fn bot_name_defaults_to_assistant_when_display_name_absent() { // When display_name is not set in bot.toml, bot_name should be "Assistant". diff --git a/server/src/chat/transport/matrix/bot/run.rs b/server/src/chat/transport/matrix/bot/run.rs index 03bf9081..5c507eae 100644 --- a/server/src/chat/transport/matrix/bot/run.rs +++ b/server/src/chat/transport/matrix/bot/run.rs @@ -414,12 +414,15 @@ pub async fn run_bot( // blip or sync resumption. // // When started by the trampoline the message is specialised: - // - HUSKIES_TRAMPOLINE_STARTED=1 → "gateway X.Y.Z ready" + // - HUSKIES_TRAMPOLINE_STARTED=1 → "gateway X.Y.Z (git_hash) ready — model: ..." // - HUSKIES_TRAMPOLINE_FAILURE= → rollback failure notice let announce_msg = if let Ok(reason) = std::env::var("HUSKIES_TRAMPOLINE_FAILURE") { super::format::format_gateway_rollback_announcement(&reason) } else if std::env::var("HUSKIES_TRAMPOLINE_STARTED").is_ok() { - super::format::format_gateway_ready_announcement() + super::format::format_gateway_ready_announcement( + option_env!("BUILD_GIT_HASH").unwrap_or("unknown"), + config.model.as_deref(), + ) } else { format_startup_announcement(&announce_bot_name) };