Watch
0
0
Fork
You've already forked hyperhive
0

a hive-side pause holds against the swarm's declared state until an operator resumes

the harness writes the reason into the pause marker when it pauses itself and reports it as paused_by_hive in its turn-state header. swarm-controller declares such an agent paused (only if declared up) and shows the reason on the agents status row and the swarm ui card.
This commit is contained in:
atlas 2026-11-09 23:09:14 +01:00 • committed by mara
commit e5c55257f8
2 changed files with 517 additions and 26 deletions

View file

@ -0,0 +1,43 @@
//! Whether the agent's own harness paused its turn loop, as the agent itself
//! reports it.
//!
//! Part of the turn-state header the agent publishes on
//! `swarm_queue_client::agent_state_subject`, beside [`crate::agent_login::Login`];
//! swarm-controller decodes it out of that header with this same type.
/// The hive-pause fields of an agent's turn-state header.
#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct HivePause {
/// Why the harness paused its own turn loop; present only while that
/// pause is in force. An operator's pause (`hivectl pause`, the
/// dashboard) is not reported here, and neither is any pause by a harness
/// that predates the field, so absence says nothing about `agent_state`.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub paused_by_hive: Option<String>,
}
#[cfg(test)]
mod tests {
use super::HivePause;
#[test]
fn a_header_without_the_field_decodes_as_not_paused_by_the_hive() {
let header = serde_json::json!({ "agent_state": "paused", "needs_login": false });
let decoded: HivePause = serde_json::from_value(header).expect("an old header decodes");
assert_eq!(decoded.paused_by_hive, None);
}
#[test]
fn the_reason_round_trips_and_an_absent_one_is_not_sent() {
let sent = HivePause {
paused_by_hive: Some("skipped get_loose_ends".to_owned()),
};
let value = serde_json::to_value(&sent).expect("serialises");
assert_eq!(value["paused_by_hive"], "skipped get_loose_ends");
let decoded: HivePause = serde_json::from_value(value).expect("decodes");
assert_eq!(decoded, sent);
let none = serde_json::to_value(HivePause::default()).expect("serialises");
assert!(none.as_object().expect("an object").is_empty());
}
}

View file

@ -11,6 +11,7 @@ pub mod agent_icon;
pub mod agent_inference;
pub mod agent_limits;
pub mod agent_login;
pub mod agent_pause;
pub mod agent_permissions;
pub mod agent_schedules;
pub mod agent_status;