Skip to main content

pe_core/
state.rs

1//! State traits — the foundation every agent state implements.
2//!
3//! `State` + `StateUpdate` are generated by #[derive(State)] macro.
4//! `CoreState` defines the fields every agent state must have.
5//! Based on Decisions 2, 13 of the pre-plan.
6
7use crate::message::Message;
8use serde::{Deserialize, Serialize, de::DeserializeOwned};
9use std::collections::HashMap;
10
11/// Every agent state must implement this trait.
12/// Generated by #[derive(State)] proc macro.
13pub trait State: Clone + Send + Sync + Serialize + DeserializeOwned + 'static {
14    /// The companion partial-update struct (all fields Optional)
15    type Update: StateUpdate;
16
17    /// Apply a partial update — each field uses its channel's merge strategy
18    fn apply(&mut self, update: Self::Update);
19}
20
21/// Marker trait for state update structs.
22/// Generated by `#[derive(State)]` — the StateUpdate has `Option<T>` per field.
23///
24/// All generated updates have all-`Option` fields, so `Default` is natural
25/// (all fields `None` = empty update).
26pub trait StateUpdate:
27    Clone + Send + Sync + Serialize + DeserializeOwned + std::fmt::Debug + Default + 'static
28{
29}
30
31/// Extension trait for state updates that carry messages.
32///
33/// Required by `pe_tools::ToolNode` and any built-in node that needs
34/// to construct updates containing message lists. Generated by
35/// `#[derive(State)]` on types that have a `messages: Vec<Message>` field.
36pub trait CoreStateUpdate: StateUpdate {
37    /// Create an update containing only these messages.
38    fn from_messages(messages: Vec<Message>) -> Self;
39}
40
41/// Core fields every agent state MUST have.
42/// Generated by #[derive(CoreState)] or detected via #[core] fields in #[derive(State)].
43///
44/// Generic nodes that work on ANY agent state bound on this trait:
45/// ```ignore
46/// #[node]
47/// async fn prepare<S: CoreState>(state: &S) -> NodeResult<S::Update> { ... }
48/// ```
49pub trait CoreState: State {
50    fn messages(&self) -> &[Message];
51    fn messages_mut(&mut self) -> &mut Vec<Message>;
52    fn iterations(&self) -> u32;
53    fn set_iterations(&mut self, n: u32);
54    fn thread_id(&self) -> &str;
55    fn context(&self) -> &ExecutionContext;
56    fn context_mut(&mut self) -> &mut ExecutionContext;
57
58    /// Optional structured metadata projection surfaced on runtime results.
59    ///
60    /// Most states do not need this and can use the default empty projection.
61    /// Specialized runtime-owned states can override it to expose structured
62    /// execution details at the `ExecutionResult` boundary.
63    fn runtime_result_metadata(&self) -> HashMap<String, serde_json::Value> {
64        HashMap::new()
65    }
66}
67
68/// Execution context injected into every agent state by the runtime.
69/// Contains everything a node needs to access runtime services.
70#[derive(Debug, Clone, Serialize, Deserialize)]
71pub struct ExecutionContext {
72    /// Agent's identity info
73    pub agent_id: String,
74
75    /// Matrix state (if active)
76    #[serde(default)]
77    pub matrix_c_value: Option<f64>,
78    #[serde(default)]
79    pub matrix_completion: Option<f64>,
80
81    /// Execution awareness — serialized for LLM context injection
82    #[serde(default)]
83    pub awareness_summary: Option<String>,
84
85    /// Runtime metadata
86    #[serde(default)]
87    pub metadata: HashMap<String, serde_json::Value>,
88}
89
90impl ExecutionContext {
91    pub fn new(agent_id: impl Into<String>) -> Self {
92        Self {
93            agent_id: agent_id.into(),
94            matrix_c_value: None,
95            matrix_completion: None,
96            awareness_summary: None,
97            metadata: HashMap::new(),
98        }
99    }
100}