agentos_native_sidecar_core/
diagnostics.rs1use agentos_kernel::process_table::{ProcessInfo, ProcessStatus};
2use agentos_sidecar_protocol::protocol::{ProcessSnapshotEntry, ProcessSnapshotStatus};
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum SharedProcessSnapshotStatus {
6 Running,
7 Stopped,
8 Exited,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct SharedProcessSnapshotEntry {
13 pub process_id: String,
14 pub pid: u32,
15 pub ppid: u32,
16 pub pgid: u32,
17 pub sid: u32,
18 pub driver: String,
19 pub command: String,
20 pub args: Vec<String>,
21 pub cwd: String,
22 pub status: SharedProcessSnapshotStatus,
23 pub exit_code: Option<i32>,
24}
25
26pub fn process_status_from_kernel(status: ProcessStatus) -> SharedProcessSnapshotStatus {
27 match status {
28 ProcessStatus::Running => SharedProcessSnapshotStatus::Running,
29 ProcessStatus::Stopped => SharedProcessSnapshotStatus::Stopped,
30 ProcessStatus::Exited => SharedProcessSnapshotStatus::Exited,
31 }
32}
33
34pub fn process_snapshot_entry_from_kernel(
35 process_id: &str,
36 info: &ProcessInfo,
37 cwd: impl Into<String>,
38 exit_code: Option<i32>,
39) -> SharedProcessSnapshotEntry {
40 SharedProcessSnapshotEntry {
41 process_id: process_id.to_owned(),
42 pid: info.pid,
43 ppid: info.ppid,
44 pgid: info.pgid,
45 sid: info.sid,
46 driver: info.driver.clone(),
47 command: info.command.clone(),
48 args: Vec::new(),
49 cwd: cwd.into(),
50 status: if exit_code.is_some() {
51 SharedProcessSnapshotStatus::Exited
52 } else {
53 process_status_from_kernel(info.status)
54 },
55 exit_code: exit_code.or(info.exit_code),
56 }
57}
58
59pub fn protocol_process_snapshot_entry(entry: SharedProcessSnapshotEntry) -> ProcessSnapshotEntry {
60 ProcessSnapshotEntry {
61 process_id: entry.process_id,
62 pid: entry.pid,
63 ppid: entry.ppid,
64 pgid: entry.pgid,
65 sid: entry.sid,
66 driver: entry.driver,
67 command: entry.command,
68 args: entry.args,
69 cwd: entry.cwd,
70 status: match entry.status {
71 SharedProcessSnapshotStatus::Running => ProcessSnapshotStatus::Running,
72 SharedProcessSnapshotStatus::Stopped => ProcessSnapshotStatus::Stopped,
73 SharedProcessSnapshotStatus::Exited => ProcessSnapshotStatus::Exited,
74 },
75 exit_code: entry.exit_code,
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use agentos_kernel::user::ProcessIdentity;
83
84 fn process_info(status: ProcessStatus, exit_code: Option<i32>) -> ProcessInfo {
85 ProcessInfo {
86 pid: 42,
87 ppid: 1,
88 pgid: 42,
89 sid: 42,
90 driver: "javascript".to_owned(),
91 command: "node".to_owned(),
92 status,
93 exit_code,
94 identity: ProcessIdentity::default(),
95 }
96 }
97
98 #[test]
99 fn maps_kernel_process_statuses() {
100 assert_eq!(
101 process_status_from_kernel(ProcessStatus::Running),
102 SharedProcessSnapshotStatus::Running
103 );
104 assert_eq!(
105 process_status_from_kernel(ProcessStatus::Stopped),
106 SharedProcessSnapshotStatus::Stopped
107 );
108 assert_eq!(
109 process_status_from_kernel(ProcessStatus::Exited),
110 SharedProcessSnapshotStatus::Exited
111 );
112 }
113
114 #[test]
115 fn builds_process_snapshot_from_kernel_info() {
116 let entry = process_snapshot_entry_from_kernel(
117 "exec-1",
118 &process_info(ProcessStatus::Running, None),
119 "/workspace",
120 None,
121 );
122
123 assert_eq!(entry.process_id, "exec-1");
124 assert_eq!(entry.pid, 42);
125 assert_eq!(entry.ppid, 1);
126 assert_eq!(entry.pgid, 42);
127 assert_eq!(entry.sid, 42);
128 assert_eq!(entry.driver, "javascript");
129 assert_eq!(entry.command, "node");
130 assert_eq!(entry.args, Vec::<String>::new());
131 assert_eq!(entry.cwd, "/workspace");
132 assert_eq!(entry.status, SharedProcessSnapshotStatus::Running);
133 assert_eq!(entry.exit_code, None);
134 }
135
136 #[test]
137 fn explicit_exit_code_marks_snapshot_exited() {
138 let entry = process_snapshot_entry_from_kernel(
139 "exec-1",
140 &process_info(ProcessStatus::Running, Some(9)),
141 "/workspace",
142 Some(7),
143 );
144
145 assert_eq!(entry.status, SharedProcessSnapshotStatus::Exited);
146 assert_eq!(entry.exit_code, Some(7));
147 }
148
149 #[test]
150 fn maps_shared_process_snapshot_to_protocol_entry() {
151 let entry = protocol_process_snapshot_entry(SharedProcessSnapshotEntry {
152 process_id: String::from("proc-1"),
153 pid: 42,
154 ppid: 1,
155 pgid: 42,
156 sid: 42,
157 driver: String::from("javascript"),
158 command: String::from("node"),
159 args: vec![String::from("app.js")],
160 cwd: String::from("/workspace"),
161 status: SharedProcessSnapshotStatus::Stopped,
162 exit_code: None,
163 });
164
165 assert_eq!(entry.process_id, "proc-1");
166 assert_eq!(entry.pid, 42);
167 assert_eq!(entry.args, vec![String::from("app.js")]);
168 assert_eq!(entry.cwd, "/workspace");
169 assert_eq!(entry.status, ProcessSnapshotStatus::Stopped);
170 assert_eq!(entry.exit_code, None);
171 }
172}