Skip to main content

harn_vm/agent_events/
worker.rs

1use serde::{Deserialize, Serialize};
2
3/// One coalesced filesystem notification from a hostlib `fs_watch`
4/// subscription.
5#[derive(Clone, Debug, Serialize, Deserialize)]
6pub struct FsWatchEvent {
7    pub kind: String,
8    pub paths: Vec<String>,
9    pub relative_paths: Vec<String>,
10    pub raw_kind: String,
11    pub error: Option<String>,
12}
13
14/// Typed worker lifecycle events emitted by delegated/background agent
15/// execution. Bridge-facing worker updates still derive a string status
16/// from these variants, but the runtime no longer passes raw status
17/// strings around internally.
18///
19/// `Spawned`/`Completed`/`Failed`/`Stopped`/`Cancelled` are the terminal-or-start
20/// states. `Progressed` is fired on intermediate milestones (e.g. a
21/// retriggerable worker resuming from `awaiting_input`, or a workflow
22/// stage completing without ending the worker). `WaitingForInput` covers
23/// retriggerable workers that finish a cycle but stay alive pending the
24/// next host-supplied trigger payload. `Suspended`/`Resumed` cover
25/// cooperative mid-loop pause and warm resume (harn#1836); the
26/// `agent_loop` honors the pause signal at the next turn boundary,
27/// distinct from a graceful `Stopped` handoff or hard `Cancelled` interrupt.
28#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
29pub enum WorkerEvent {
30    WorkerSpawned,
31    WorkerProgressed,
32    WorkerWaitingForInput,
33    WorkerSuspended,
34    WorkerResumed,
35    WorkerCompleted,
36    WorkerFailed,
37    WorkerStopped,
38    WorkerCancelled,
39}
40
41impl WorkerEvent {
42    /// The full set of `WorkerEvent` variants in canonical order. Mirrors
43    /// the pattern used by `ToolCallStatus::ALL` so the protocol-artifact
44    /// dumper can enumerate worker status wire values without
45    /// special-casing each lifecycle event.
46    pub const ALL: [Self; 9] = [
47        Self::WorkerSpawned,
48        Self::WorkerProgressed,
49        Self::WorkerWaitingForInput,
50        Self::WorkerSuspended,
51        Self::WorkerResumed,
52        Self::WorkerCompleted,
53        Self::WorkerFailed,
54        Self::WorkerStopped,
55        Self::WorkerCancelled,
56    ];
57
58    /// Wire-level status string used by bridge `worker_update` payloads
59    /// and ACP `worker_update` session updates. The four canonical
60    /// states are mirrored from harn's internal worker `status` field
61    /// (`running`/`completed`/`failed`/`cancelled`), and the four newer
62    /// lifecycle states pick names that don't collide with any existing
63    /// status string.
64    pub fn as_status(self) -> &'static str {
65        match self {
66            Self::WorkerSpawned => "running",
67            Self::WorkerProgressed => "progressed",
68            Self::WorkerWaitingForInput => "awaiting_input",
69            Self::WorkerSuspended => "suspended",
70            Self::WorkerResumed => "running",
71            Self::WorkerCompleted => "completed",
72            Self::WorkerFailed => "failed",
73            Self::WorkerStopped => "stopped",
74            Self::WorkerCancelled => "cancelled",
75        }
76    }
77
78    pub fn as_str(self) -> &'static str {
79        match self {
80            Self::WorkerSpawned => "WorkerSpawned",
81            Self::WorkerProgressed => "WorkerProgressed",
82            Self::WorkerWaitingForInput => "WorkerWaitingForInput",
83            Self::WorkerSuspended => "WorkerSuspended",
84            Self::WorkerResumed => "WorkerResumed",
85            Self::WorkerCompleted => "WorkerCompleted",
86            Self::WorkerFailed => "WorkerFailed",
87            Self::WorkerStopped => "WorkerStopped",
88            Self::WorkerCancelled => "WorkerCancelled",
89        }
90    }
91
92    /// True for lifecycle events that mean the worker has reached a
93    /// final, non-resumable state. Retriggerable awaiting, progressed,
94    /// and cooperative suspend/resume milestones are *not* terminal —
95    /// the worker keeps running, is waiting for a trigger, or is parked
96    /// awaiting an external resume.
97    pub fn is_terminal(self) -> bool {
98        matches!(
99            self,
100            Self::WorkerCompleted
101                | Self::WorkerFailed
102                | Self::WorkerStopped
103                | Self::WorkerCancelled
104        )
105    }
106}