pe-core 0.1.0

Core types for Potential Expectations — messages, channels, state, traits
Documentation
//! State traits — the foundation every agent state implements.
//!
//! `State` + `StateUpdate` are generated by #[derive(State)] macro.
//! `CoreState` defines the fields every agent state must have.
//! Based on Decisions 2, 13 of the pre-plan.

use crate::message::Message;
use serde::{Deserialize, Serialize, de::DeserializeOwned};
use std::collections::HashMap;

/// Every agent state must implement this trait.
/// Generated by #[derive(State)] proc macro.
pub trait State: Clone + Send + Sync + Serialize + DeserializeOwned + 'static {
    /// The companion partial-update struct (all fields Optional)
    type Update: StateUpdate;

    /// Apply a partial update — each field uses its channel's merge strategy
    fn apply(&mut self, update: Self::Update);
}

/// Marker trait for state update structs.
/// Generated by `#[derive(State)]` — the StateUpdate has `Option<T>` per field.
///
/// All generated updates have all-`Option` fields, so `Default` is natural
/// (all fields `None` = empty update).
pub trait StateUpdate:
    Clone + Send + Sync + Serialize + DeserializeOwned + std::fmt::Debug + Default + 'static
{
}

/// Extension trait for state updates that carry messages.
///
/// Required by `pe_tools::ToolNode` and any built-in node that needs
/// to construct updates containing message lists. Generated by
/// `#[derive(State)]` on types that have a `messages: Vec<Message>` field.
pub trait CoreStateUpdate: StateUpdate {
    /// Create an update containing only these messages.
    fn from_messages(messages: Vec<Message>) -> Self;
}

/// Core fields every agent state MUST have.
/// Generated by #[derive(CoreState)] or detected via #[core] fields in #[derive(State)].
///
/// Generic nodes that work on ANY agent state bound on this trait:
/// ```ignore
/// #[node]
/// async fn prepare<S: CoreState>(state: &S) -> NodeResult<S::Update> { ... }
/// ```
pub trait CoreState: State {
    fn messages(&self) -> &[Message];
    fn messages_mut(&mut self) -> &mut Vec<Message>;
    fn iterations(&self) -> u32;
    fn set_iterations(&mut self, n: u32);
    fn thread_id(&self) -> &str;
    fn context(&self) -> &ExecutionContext;
    fn context_mut(&mut self) -> &mut ExecutionContext;

    /// Optional structured metadata projection surfaced on runtime results.
    ///
    /// Most states do not need this and can use the default empty projection.
    /// Specialized runtime-owned states can override it to expose structured
    /// execution details at the `ExecutionResult` boundary.
    fn runtime_result_metadata(&self) -> HashMap<String, serde_json::Value> {
        HashMap::new()
    }
}

/// Execution context injected into every agent state by the runtime.
/// Contains everything a node needs to access runtime services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ExecutionContext {
    /// Agent's identity info
    pub agent_id: String,

    /// Matrix state (if active)
    #[serde(default)]
    pub matrix_c_value: Option<f64>,
    #[serde(default)]
    pub matrix_completion: Option<f64>,

    /// Execution awareness — serialized for LLM context injection
    #[serde(default)]
    pub awareness_summary: Option<String>,

    /// Runtime metadata
    #[serde(default)]
    pub metadata: HashMap<String, serde_json::Value>,
}

impl ExecutionContext {
    pub fn new(agent_id: impl Into<String>) -> Self {
        Self {
            agent_id: agent_id.into(),
            matrix_c_value: None,
            matrix_completion: None,
            awareness_summary: None,
            metadata: HashMap::new(),
        }
    }
}