1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
5#[serde(rename_all = "snake_case")]
6pub enum AgentState {
7 Working,
9 Blocked,
11 WaitingReview,
13 Idle,
15}
16
17impl AgentState {
18 pub fn as_str(&self) -> &'static str {
19 match self {
20 Self::Working => "working",
21 Self::Blocked => "blocked",
22 Self::WaitingReview => "waiting_review",
23 Self::Idle => "idle",
24 }
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
30pub struct AgentStatusSnapshot {
31 pub state: AgentState,
32 pub task_id: Option<String>,
33 pub blocked_reason: Option<String>,
34 pub waiting_on_agent: Option<String>,
36 pub checkpoint: Option<String>,
38 pub working_on: String,
40}
41
42impl Default for AgentStatusSnapshot {
43 fn default() -> Self {
44 Self {
45 state: AgentState::Working,
46 task_id: None,
47 blocked_reason: None,
48 waiting_on_agent: None,
49 checkpoint: None,
50 working_on: "heartbeat via WS".into(),
51 }
52 }
53}
54
55#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct HeartbeatRequest {
57 pub agent_id: String,
58 pub status: AgentStatusSnapshot,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
62pub struct HeartbeatResponse {
63 pub accepted: bool,
64 pub nudges: Vec<NudgeMessage>,
65}
66
67#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct NudgeMessage {
69 pub reason: String,
70 pub severity: NudgeSeverity,
71}
72
73#[derive(Debug, Clone, Serialize, Deserialize)]
74#[serde(rename_all = "snake_case")]
75pub enum NudgeSeverity {
76 Info,
77 Warning,
78 Blocking,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
83pub struct NudgeConfig {
84 pub stale_threshold_minutes: i64,
86 pub check_interval_seconds: u64,
88}
89
90impl Default for NudgeConfig {
91 fn default() -> Self {
92 Self {
93 stale_threshold_minutes: 5,
94 check_interval_seconds: 30,
95 }
96 }
97}