Skip to main content

meerkat_mobkit/
types.rs

1//! Core type definitions shared across the MobKit runtime.
2
3use std::collections::BTreeMap;
4
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8/// A structural mob event projected from `meerkat_mob::AttributedEvent` and
9/// `MobEventKind` into a flat, identity-aware envelope suitable for SSE
10/// replay and JSON-RPC query.
11///
12/// Mirrors the shape of [`crate::console_contracts::ConsoleIdentityEventEnvelope`]
13/// but preserves structural fields (`mob_id`, `run_id`, `step_id`,
14/// `agent_identity`) that the lossy `UnifiedEvent::Agent` projection
15/// discards. `cursor` is a monotonically increasing sequence assigned at
16/// ingestion time and serves as the pagination token (clients pass the
17/// last-seen cursor as `EventQuery::after_seq`).
18#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
19pub struct MobStructuralEventEnvelope {
20    /// Unique event id (mirrors the originating mob event cursor when
21    /// available, prefixed with `mob-evt-`).
22    pub event_id: String,
23    /// Monotonic ingestion sequence (used as `after_seq` cursor).
24    pub cursor: u64,
25    /// Mob this event belongs to.
26    pub mob_id: String,
27    /// Millisecond-precision wall-clock timestamp at ingestion.
28    pub timestamp_ms: u64,
29    /// Snake-case event kind (e.g. `flow_started`, `step_dispatched`).
30    pub kind: String,
31    /// Run id when the event is associated with a flow run, otherwise `None`.
32    #[serde(default, skip_serializing_if = "Option::is_none")]
33    pub run_id: Option<String>,
34    /// Step id when the event is associated with a flow step, otherwise `None`.
35    #[serde(default, skip_serializing_if = "Option::is_none")]
36    pub step_id: Option<String>,
37    /// Stable agent identity when the event is attributable to a member,
38    /// otherwise `None`.
39    #[serde(default, skip_serializing_if = "Option::is_none")]
40    pub agent_identity: Option<String>,
41    /// Mob-scoped labels at projection time (snapshot of the
42    /// `RuntimeMetadataTable` entry for `MetadataScope::Mob(mob_id)`).
43    /// Empty if no labels are set.
44    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
45    pub mob_labels: BTreeMap<String, String>,
46    /// Run-scoped labels at projection time (snapshot of the
47    /// `RuntimeMetadataTable` entry for `MetadataScope::Run(mob_id, run_id)`).
48    /// Empty when the event has no `run_id` or no labels are set for the run.
49    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
50    pub run_labels: BTreeMap<String, String>,
51    /// Full structured payload (the variant-specific fields of `MobEventKind`).
52    pub data: Value,
53}
54
55/// Timestamped wrapper around an event payload.
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
57pub struct EventEnvelope<T> {
58    pub event_id: String,
59    pub source: String,
60    pub timestamp_ms: u64,
61    pub event: T,
62}
63
64/// A runtime event from either an agent or a module.
65#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(tag = "kind", rename_all = "snake_case")]
67pub enum UnifiedEvent {
68    Agent {
69        agent_id: String,
70        event_type: String,
71        #[serde(default, skip_serializing_if = "Option::is_none")]
72        payload: Option<Value>,
73    },
74    Module(ModuleEvent),
75}
76
77/// An event originating from a loaded MCP module.
78#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
79pub struct ModuleEvent {
80    pub module: String,
81    pub event_type: String,
82    pub payload: Value,
83}
84
85/// Configuration for a single MCP module to be loaded.
86#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
87pub struct ModuleConfig {
88    pub id: String,
89    pub command: String,
90    pub args: Vec<String>,
91    pub restart_policy: RestartPolicy,
92}
93
94/// Policy controlling automatic module restart behavior.
95#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
96#[serde(rename_all = "snake_case")]
97pub enum RestartPolicy {
98    Never,
99    OnFailure,
100    Always,
101}
102
103/// Specification for module discovery at startup.
104#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
105pub struct DiscoverySpec {
106    pub namespace: String,
107    pub modules: Vec<String>,
108}
109
110/// Agent-level discovery specification for spawning agents into a mob.
111///
112/// Unlike [`DiscoverySpec`] (which describes module discovery for `MobKitConfig`),
113/// this type captures the fields needed to discover and spawn individual agents.
114#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
115pub struct AgentDiscoverySpec {
116    /// Agent profile name (maps to a profile in the mob definition).
117    pub profile: String,
118    /// Unique agent ID within the mob.
119    pub meerkat_id: String,
120    /// Application-defined labels for this agent.
121    #[serde(default, skip_serializing_if = "Option::is_none")]
122    pub labels: Option<BTreeMap<String, String>>,
123    /// Opaque application context passed through to the agent build pipeline.
124    #[serde(default, skip_serializing_if = "Option::is_none")]
125    pub context: Option<Value>,
126    /// Extra instructions appended to the agent prompt.
127    #[serde(default, skip_serializing_if = "Vec::is_empty")]
128    pub additional_instructions: Vec<String>,
129    /// Resume an existing session instead of creating a new one.
130    #[serde(default, skip_serializing_if = "Option::is_none")]
131    pub resume_session_id: Option<String>,
132}
133
134/// Pre-spawn context passed to modules during discovery.
135#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
136pub struct PreSpawnData {
137    pub module_id: String,
138    pub env: Vec<(String, String)>,
139}
140
141/// Top-level configuration for a MobKit runtime instance.
142#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
143pub struct MobKitConfig {
144    pub modules: Vec<ModuleConfig>,
145    pub discovery: DiscoverySpec,
146    pub pre_spawn: Vec<PreSpawnData>,
147}