include agent label in turn failure notification body

This commit is contained in:
damocles 2026-05-16 20:28:45 +02:00
parent 1023acf69f
commit 824acee134
2 changed files with 16 additions and 10 deletions

View file

@ -76,7 +76,7 @@ async fn main() -> Result<()> {
let turn_lock: TurnLock = Arc::new(tokio::sync::Mutex::new(())); let turn_lock: TurnLock = Arc::new(tokio::sync::Mutex::new(()));
plugins::install_configured(&cli.socket, Some("manager")).await; plugins::install_configured(&cli.socket, Some("manager")).await;
tokio::spawn(web_ui::serve( tokio::spawn(web_ui::serve(
label, label.clone(),
port, port,
login_state.clone(), login_state.clone(),
bus.clone(), bus.clone(),
@ -93,6 +93,7 @@ async fn main() -> Result<()> {
bus, bus,
&files, &files,
turn_lock, turn_lock,
&label,
) )
.await .await
} }
@ -108,6 +109,7 @@ async fn main() -> Result<()> {
bus, bus,
&files, &files,
turn_lock, turn_lock,
&label,
) )
.await .await
} }
@ -143,6 +145,7 @@ async fn serve(
bus: Bus, bus: Bus,
files: &turn::TurnFiles, files: &turn::TurnFiles,
turn_lock: TurnLock, turn_lock: TurnLock,
label: &str,
) -> Result<()> { ) -> Result<()> {
tracing::info!(socket = %socket.display(), "hive-ag3nt serve"); tracing::info!(socket = %socket.display(), "hive-ag3nt serve");
let _ = state; // reserved for future state transitions (turn-loop -> needs-login) let _ = state; // reserved for future state transitions (turn-loop -> needs-login)
@ -182,7 +185,7 @@ async fn serve(
// manager so it can investigate / restart / page the // manager so it can investigate / restart / page the
// operator; best-effort, swallow the send error. // operator; best-effort, swallow the send error.
if let turn::TurnOutcome::Failed(e) = &outcome { if let turn::TurnOutcome::Failed(e) = &outcome {
notify_manager_of_failure(socket, e).await; notify_manager_of_failure(socket, label, e).await;
} }
// After turn completes, check if there are pending messages waiting. // After turn completes, check if there are pending messages waiting.
@ -235,13 +238,15 @@ fn format_wake_prompt(from: &str, body: &str, unread: u64) -> String {
/// Best-effort: tell the manager that this agent's last turn crashed /// Best-effort: tell the manager that this agent's last turn crashed
/// (claude exited non-zero, compaction didn't help, etc.). Routed /// (claude exited non-zero, compaction didn't help, etc.). Routed
/// through the normal send path so the manager's inbox surfaces it /// through the normal send path so the manager's inbox surfaces it
/// like any other message; the agent's label is what the broker /// as a system-style event; `label` is included explicitly in the
/// stamps as `from`, so the message body doesn't need to repeat it. /// body so the manager can identify the failing agent without having
/// Swallows transport errors — we just logged the failure, the worst /// to look at the `from` field (which is broker-stamped and may
/// case is the manager learns about the crash from the dashboard /// differ from what the operator sees in the dashboard). Swallows
/// instead of inbox. /// transport errors — we just logged the failure, the worst case is
async fn notify_manager_of_failure(socket: &Path, err: &anyhow::Error) { /// the manager learns about the crash from the dashboard instead of
let body = format!("claude turn failed:\n{err:#}"); /// inbox.
async fn notify_manager_of_failure(socket: &Path, label: &str, err: &anyhow::Error) {
let body = format!("[system] agent `{label}` claude turn failed:\n{err:#}");
let res = client::request::<_, AgentResponse>( let res = client::request::<_, AgentResponse>(
socket, socket,
&AgentRequest::Send { &AgentRequest::Send {

View file

@ -158,7 +158,8 @@ async fn serve(
ManagerResponse::Ok ManagerResponse::Ok
| ManagerResponse::Status { .. } | ManagerResponse::Status { .. }
| ManagerResponse::QuestionQueued { .. } | ManagerResponse::QuestionQueued { .. }
| ManagerResponse::Recent { .. }, | ManagerResponse::Recent { .. }
| ManagerResponse::Logs { .. },
) => { ) => {
tracing::warn!("recv produced unexpected response kind"); tracing::warn!("recv produced unexpected response kind");
} }