deepstrike_core/proc/
mod.rs1use compact_str::CompactString;
2use serde::{Deserialize, Serialize};
3
4use crate::types::agent::{AgentIsolation, AgentRole, ContextInheritance};
5use crate::types::result::{SubAgentResult, TerminationReason};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(rename_all = "snake_case")]
10pub enum ProcessState {
11 Running,
12 Joined,
13 Failed,
14}
15
16impl ProcessState {
17 pub fn label(self) -> &'static str {
18 match self {
19 Self::Running => "running",
20 Self::Joined => "joined",
21 Self::Failed => "failed",
22 }
23 }
24}
25
26fn process_state_of(state: crate::scheduler::tcb::TaskState) -> ProcessState {
30 use crate::scheduler::tcb::TaskState;
31 match state {
32 TaskState::Done(TerminationReason::Completed) => ProcessState::Joined,
33 TaskState::Done(_) => ProcessState::Failed,
34 _ => ProcessState::Running,
35 }
36}
37
38#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct AgentProcess {
44 pub agent_id: CompactString,
45 pub parent_session_id: CompactString,
46 pub role: AgentRole,
47 pub isolation: AgentIsolation,
48 pub context_inheritance: ContextInheritance,
49 pub state: ProcessState,
50 #[serde(default, skip_serializing_if = "Vec::is_empty")]
51 pub permitted_capability_ids: Vec<CompactString>,
52 #[serde(default, skip_serializing_if = "Option::is_none")]
53 pub result: Option<SubAgentResult>,
54}
55
56impl AgentProcess {
57 pub fn from_tcb(tcb: &crate::scheduler::tcb::Tcb) -> Option<Self> {
64 let info = tcb.proc.as_ref()?;
65 Some(Self {
66 agent_id: tcb.id.clone(),
67 parent_session_id: info.parent_session_id.clone(),
68 role: info.role,
69 isolation: info.isolation,
70 context_inheritance: info.context_inheritance,
71 state: process_state_of(tcb.state),
72 permitted_capability_ids: tcb.caps.clone(),
73 result: info.result.clone(),
74 })
75 }
76
77 pub fn result_termination_label(&self) -> Option<&'static str> {
78 let result = self.result.as_ref()?;
79 Some(match result.result.termination {
80 TerminationReason::Completed => "completed",
81 TerminationReason::MaxTurns => "max_turns",
82 TerminationReason::TokenBudget => "token_budget",
83 TerminationReason::Timeout => "timeout",
84 TerminationReason::UserAbort => "user_abort",
85 TerminationReason::Error => "error",
86 TerminationReason::MilestoneExceeded => "milestone_exceeded",
87 })
88 }
89}
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use crate::scheduler::policy::SchedulerBudget;
95 use crate::scheduler::tcb::{Tcb, TaskState};
96 use crate::types::agent::{AgentIdentity, AgentRole, AgentRunSpec, IsolationManifest};
97 use crate::types::capability::CapabilityManifest;
98
99 fn child_tcb(id: &str) -> Tcb {
100 let spec = AgentRunSpec::new(
101 AgentIdentity::sub_agent(id, &format!("{id}-session")),
102 AgentRole::Implement,
103 "do work",
104 );
105 let manifest = IsolationManifest::from_spec(&spec, "parent-sess", &CapabilityManifest::new());
106 Tcb::spawned(&manifest, SchedulerBudget::default())
107 }
108
109 #[test]
110 fn from_tcb_is_none_for_root_task() {
111 let root = Tcb::root("root", SchedulerBudget::default());
112 assert!(AgentProcess::from_tcb(&root).is_none());
113 }
114
115 #[test]
116 fn from_tcb_reconstructs_running_process() {
117 let tcb = child_tcb("worker");
118 let p = AgentProcess::from_tcb(&tcb).expect("child reconstructs a process");
119 assert_eq!(p.agent_id.as_str(), "worker");
120 assert_eq!(p.parent_session_id.as_str(), "parent-sess");
121 assert_eq!(p.role, AgentRole::Implement);
122 assert_eq!(p.state, ProcessState::Running);
123 assert!(p.result.is_none());
124 }
125
126 #[test]
127 fn process_state_of_maps_terminal_task_states() {
128 assert_eq!(process_state_of(TaskState::Running), ProcessState::Running);
129 assert_eq!(
130 process_state_of(TaskState::Done(TerminationReason::Completed)),
131 ProcessState::Joined
132 );
133 assert_eq!(
134 process_state_of(TaskState::Done(TerminationReason::Error)),
135 ProcessState::Failed
136 );
137 assert_eq!(
138 process_state_of(TaskState::Done(TerminationReason::Timeout)),
139 ProcessState::Failed
140 );
141 }
142}