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`/`Cancelled` are the four 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 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 WorkerCancelled,
38}
39
40impl WorkerEvent {
41 /// The full set of `WorkerEvent` variants in canonical order. Mirrors
42 /// the pattern used by `ToolCallStatus::ALL` so the protocol-artifact
43 /// dumper can enumerate worker status wire values without
44 /// special-casing each lifecycle event.
45 pub const ALL: [Self; 8] = [
46 Self::WorkerSpawned,
47 Self::WorkerProgressed,
48 Self::WorkerWaitingForInput,
49 Self::WorkerSuspended,
50 Self::WorkerResumed,
51 Self::WorkerCompleted,
52 Self::WorkerFailed,
53 Self::WorkerCancelled,
54 ];
55
56 /// Wire-level status string used by bridge `worker_update` payloads
57 /// and ACP `worker_update` session updates. The four canonical
58 /// states are mirrored from harn's internal worker `status` field
59 /// (`running`/`completed`/`failed`/`cancelled`), and the four newer
60 /// lifecycle states pick names that don't collide with any existing
61 /// status string.
62 pub fn as_status(self) -> &'static str {
63 match self {
64 Self::WorkerSpawned => "running",
65 Self::WorkerProgressed => "progressed",
66 Self::WorkerWaitingForInput => "awaiting_input",
67 Self::WorkerSuspended => "suspended",
68 Self::WorkerResumed => "running",
69 Self::WorkerCompleted => "completed",
70 Self::WorkerFailed => "failed",
71 Self::WorkerCancelled => "cancelled",
72 }
73 }
74
75 pub fn as_str(self) -> &'static str {
76 match self {
77 Self::WorkerSpawned => "WorkerSpawned",
78 Self::WorkerProgressed => "WorkerProgressed",
79 Self::WorkerWaitingForInput => "WorkerWaitingForInput",
80 Self::WorkerSuspended => "WorkerSuspended",
81 Self::WorkerResumed => "WorkerResumed",
82 Self::WorkerCompleted => "WorkerCompleted",
83 Self::WorkerFailed => "WorkerFailed",
84 Self::WorkerCancelled => "WorkerCancelled",
85 }
86 }
87
88 /// True for lifecycle events that mean the worker has reached a
89 /// final, non-resumable state. Retriggerable awaiting, progressed,
90 /// and cooperative suspend/resume milestones are *not* terminal —
91 /// the worker keeps running, is waiting for a trigger, or is parked
92 /// awaiting an external resume.
93 pub fn is_terminal(self) -> bool {
94 matches!(
95 self,
96 Self::WorkerCompleted | Self::WorkerFailed | Self::WorkerCancelled
97 )
98 }
99}