1#![allow(dead_code)]
2use std::collections::HashMap;
6use std::path::{Path, PathBuf};
7
8use anyhow::{Context, Result};
9use serde::Deserialize;
10
11#[derive(Debug, Deserialize)]
14pub struct BrickManifest {
15 pub brick_id: String,
16 pub version: String,
17 pub ncp_protocol_range: String,
18 #[serde(default)]
19 pub required_runtime_features: Vec<String>,
20 pub status: String,
21 #[serde(default)]
22 pub successor: Option<String>,
23 #[serde(default)]
24 pub confidence_threshold: Option<f64>,
25 pub artifact: Artifact,
26 pub schemas: Schemas,
27 pub limits: Limits,
28 #[serde(default)]
29 pub capabilities: Vec<String>,
30 pub determinism: Determinism,
31 pub time_model: String,
32 pub carry_state_class: String,
33 pub carry_state_transport: String,
34 pub carry_state_max_bytes: u64,
35 #[serde(default)]
36 pub carry_state_side_effects_schema: Option<String>,
37 #[serde(default)]
38 pub graph_ref_slots: Vec<GraphRefSlot>,
39}
40
41#[derive(Debug, Deserialize)]
42pub struct Artifact {
43 pub format: String,
44 pub entrypoint: String,
45 pub digest: String,
46 pub size_bytes: u64,
47 #[serde(default)]
48 pub path: Option<PathBuf>,
49}
50
51#[derive(Debug, Deserialize)]
52pub struct Schemas {
53 pub input: String,
54 pub output: String,
55 pub carry_state: Option<String>,
56 #[serde(default)]
57 pub metadata: Option<String>,
58}
59
60#[derive(Debug, Deserialize)]
61pub struct Limits {
62 pub max_ms: u64,
63 pub max_mem_mb: u64,
64 pub max_output_bytes: u64,
65 #[serde(default)]
66 pub max_input_bytes: Option<u64>,
67 #[serde(default)]
68 pub estimated_cost_per_invoke_usd: Option<f64>,
69}
70
71#[derive(Debug, Deserialize)]
72pub struct Determinism {
73 pub mode: String,
74 #[serde(default)]
75 pub epsilon: Option<f64>,
76 #[serde(default)]
77 pub seed_source: Option<String>,
78 #[serde(default)]
79 pub model_pin: Option<String>,
80 #[serde(default)]
81 pub reproducibility_level: Option<String>,
82}
83
84#[derive(Debug, Deserialize)]
85pub struct GraphRefSlot {
86 pub slot: String,
87 #[serde(rename = "type")]
88 pub slot_type: String,
89 pub access: String,
90 pub ref_consistency: String,
91}
92
93#[derive(Debug, Deserialize)]
96pub struct GraphManifest {
97 pub graph_id: String,
98 pub graph_version: String,
99 pub synaptic_state_version: String,
100 pub nodes: Vec<Node>,
101 pub edges: Vec<Edge>,
102}
103
104#[derive(Debug, Deserialize)]
105pub struct Node {
106 pub node_id: String,
107 pub brick: NodeBrick,
108 #[serde(default)]
109 pub activation: Option<Activation>,
110 #[serde(default)]
111 pub bindings: Bindings,
112 #[serde(default)]
113 pub carry_state_lifecycle: Option<CarryStateLifecycle>,
114}
115
116#[derive(Debug, Deserialize)]
117pub struct NodeBrick {
118 pub brick_id: String,
119 pub version_or_range: String,
120}
121
122#[derive(Debug, Deserialize)]
123pub struct Activation {
124 pub mode: String,
125 #[serde(default)]
126 pub timeout_ms: Option<u64>,
127 #[serde(default)]
128 pub allow_partial: Option<bool>,
129 #[serde(default)]
130 pub required_fields: Option<Vec<String>>,
131 #[serde(default)]
132 pub defaults: Option<HashMap<String, serde_yaml::Value>>,
133 #[serde(default)]
134 pub conflict_resolution: Option<String>,
135 #[serde(default)]
136 pub quorum_n: Option<u64>,
137 #[serde(default)]
138 pub quorum_m: Option<u64>,
139}
140
141#[derive(Debug, Default, Deserialize)]
142pub struct Bindings {
143 #[serde(default)]
144 pub graph_ref_slot_values: HashMap<String, serde_yaml::Value>,
145}
146
147#[derive(Debug, Deserialize)]
148pub struct CarryStateLifecycle {
149 #[serde(default)]
150 pub init: Option<String>,
151 #[serde(default)]
152 pub ttl_seconds: Option<u64>,
153 #[serde(default)]
154 pub on_graph_version_change: Option<String>,
155}
156
157#[derive(Debug, Clone, Deserialize)]
158pub struct Edge {
159 pub edge_id: String,
160 pub source_node: String,
161 pub target_node: String,
162 #[serde(default)]
163 pub mapping: Vec<FieldMapping>,
164 #[serde(default)]
165 pub on_success: Option<OnSuccess>,
166 #[serde(default)]
167 pub on_error: Option<HashMap<String, Vec<String>>>,
168 #[serde(default)]
169 pub priority: Option<i64>,
170}
171
172#[derive(Debug, Clone, Deserialize)]
173pub struct FieldMapping {
174 pub from: String,
175 pub to: String,
176}
177
178#[derive(Debug, Clone, Deserialize)]
179pub struct OnSuccess {
180 #[serde(default)]
181 pub weight: Option<f64>,
182 #[serde(default)]
183 pub threshold: Option<f64>,
184}
185
186pub fn load_graph(path: &Path) -> Result<GraphManifest> {
189 let contents = std::fs::read_to_string(path)
190 .with_context(|| format!("reading graph manifest '{}'", path.display()))?;
191 let graph: GraphManifest = serde_yaml::from_str(&contents)
192 .with_context(|| format!("parsing graph manifest '{}'", path.display()))?;
193 Ok(graph)
194}
195
196pub fn load_brick(path: &Path) -> Result<BrickManifest> {
197 let contents = std::fs::read_to_string(path)
198 .with_context(|| format!("reading brick manifest '{}'", path.display()))?;
199 let brick: BrickManifest = serde_yaml::from_str(&contents)
200 .with_context(|| format!("parsing brick manifest '{}'", path.display()))?;
201 Ok(brick)
202}