Skip to main content

ferrum_interfaces/vnext/execution/
provider.rs

1use super::sequence_checkpoint::{SequenceCheckpointLayout, SequenceCheckpointLayoutData};
2use super::{
3    AttributeId, BTreeMap, BTreeSet, CapabilityId, ContractVersion, Deserialize, Deserializer,
4    ExecutionWeightPlan, MemoryPlan, ModelFamilyId, NodeId, NodeWorkContract, OperationId,
5    OperationRegistryAuthority, PlanExactAlias, PlanHash, PlanId, PlanNode,
6    PlanProviderRejectReason, PlanSchemaVersion, PlanStateEffect, ProviderId, ProviderResourcePlan,
7    ProviderSelection, ProviderWorkspaceRequirement, QuantizationFormatId, ResolvedValueBinding,
8    ResourceId, RetainedCompletionValue, SemanticValue, Serialize, WeightFormatId,
9};
10use crate::vnext::ProviderExecutionSemantics;
11
12/// Per-node trusted physical resolution. It supplies physical bindings and a
13/// provider estimator result, but cannot provide memory totals, compatibility
14/// reports, plan identities, or hashes.
15#[derive(Debug, Clone, PartialEq, Eq)]
16pub struct PlanNodeResolution {
17    pub(super) operation_registry_authority: OperationRegistryAuthority,
18    pub(super) node_id: NodeId,
19    pub(super) values: Vec<ResolvedValueBinding>,
20    pub(super) required_capabilities: BTreeSet<CapabilityId>,
21    pub(super) preferred_provider: Option<ProviderId>,
22    pub(super) provider_resource_candidates: Vec<ProviderResourcePlan>,
23    pub(super) provider_resolution_rejections: BTreeMap<ProviderId, PlanProviderRejectReason>,
24}
25
26#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
27#[serde(deny_unknown_fields)]
28pub struct ExecutionPlanPayload {
29    pub(super) schema: PlanSchemaVersion,
30    pub(super) plan_id: PlanId,
31    pub(super) family_id: ModelFamilyId,
32    pub(super) device_id: super::DeviceId,
33    pub(super) device_runtime_implementation_fingerprint: String,
34    pub(super) prepared_family_fingerprint: String,
35    pub(super) program_fingerprint: String,
36    pub(super) capability_catalog_fingerprint: String,
37    pub(super) policy_version: ContractVersion,
38    pub(super) policy_fingerprint: String,
39    pub(super) maximum_scheduled_tokens: u64,
40    pub(super) execution_weights: ExecutionWeightPlan,
41    pub(super) weight_format: WeightFormatId,
42    pub(super) quantization_formats: BTreeSet<QuantizationFormatId>,
43    pub(super) retained_completion_values: Vec<RetainedCompletionValue>,
44    pub(super) terminal_output_resources: Vec<ResourceId>,
45    pub(super) nodes: Vec<PlanNode>,
46    pub(super) memory: MemoryPlan,
47    #[serde(skip_serializing_if = "Option::is_none")]
48    pub(super) sequence_checkpoint_layout: Option<SequenceCheckpointLayout>,
49}
50
51impl ExecutionPlanPayload {
52    pub const fn schema(&self) -> PlanSchemaVersion {
53        self.schema
54    }
55
56    pub fn plan_id(&self) -> &PlanId {
57        &self.plan_id
58    }
59
60    pub fn family_id(&self) -> &ModelFamilyId {
61        &self.family_id
62    }
63
64    pub fn device_id(&self) -> &super::DeviceId {
65        &self.device_id
66    }
67
68    pub fn device_runtime_implementation_fingerprint(&self) -> &str {
69        &self.device_runtime_implementation_fingerprint
70    }
71
72    pub fn prepared_family_fingerprint(&self) -> &str {
73        &self.prepared_family_fingerprint
74    }
75
76    pub fn program_fingerprint(&self) -> &str {
77        &self.program_fingerprint
78    }
79
80    pub fn capability_catalog_fingerprint(&self) -> &str {
81        &self.capability_catalog_fingerprint
82    }
83
84    pub const fn policy_version(&self) -> ContractVersion {
85        self.policy_version
86    }
87
88    pub fn policy_fingerprint(&self) -> &str {
89        &self.policy_fingerprint
90    }
91
92    pub const fn maximum_scheduled_tokens(&self) -> u64 {
93        self.maximum_scheduled_tokens
94    }
95
96    pub fn execution_weights(&self) -> &ExecutionWeightPlan {
97        &self.execution_weights
98    }
99
100    pub fn weight_format(&self) -> &WeightFormatId {
101        &self.weight_format
102    }
103
104    pub fn quantization_formats(&self) -> &BTreeSet<QuantizationFormatId> {
105        &self.quantization_formats
106    }
107
108    pub fn retained_completion_values(&self) -> &[RetainedCompletionValue] {
109        &self.retained_completion_values
110    }
111
112    pub fn terminal_output_resources(&self) -> &[ResourceId] {
113        &self.terminal_output_resources
114    }
115
116    pub fn nodes(&self) -> &[PlanNode] {
117        &self.nodes
118    }
119
120    pub fn memory(&self) -> &MemoryPlan {
121        &self.memory
122    }
123}
124
125#[derive(Serialize)]
126pub(super) struct PlanHashMaterial<'a> {
127    pub(super) schema: PlanSchemaVersion,
128    pub(super) family_id: &'a ModelFamilyId,
129    pub(super) device_id: &'a super::DeviceId,
130    pub(super) device_runtime_implementation_fingerprint: &'a str,
131    pub(super) prepared_family_fingerprint: &'a str,
132    pub(super) program_fingerprint: &'a str,
133    pub(super) capability_catalog_fingerprint: &'a str,
134    pub(super) policy_version: ContractVersion,
135    pub(super) policy_fingerprint: &'a str,
136    pub(super) maximum_scheduled_tokens: u64,
137    pub(super) execution_weights: &'a ExecutionWeightPlan,
138    pub(super) weight_format: &'a WeightFormatId,
139    pub(super) quantization_formats: &'a BTreeSet<QuantizationFormatId>,
140    pub(super) retained_completion_values: &'a [RetainedCompletionValue],
141    pub(super) terminal_output_resources: &'a [ResourceId],
142    pub(super) nodes: &'a [PlanNode],
143    pub(super) memory: &'a MemoryPlan,
144    #[serde(skip_serializing_if = "Option::is_none")]
145    pub(super) sequence_checkpoint_layout: Option<&'a SequenceCheckpointLayout>,
146}
147
148impl<'a> From<&'a ExecutionPlanPayload> for PlanHashMaterial<'a> {
149    fn from(payload: &'a ExecutionPlanPayload) -> Self {
150        Self {
151            schema: payload.schema,
152            family_id: &payload.family_id,
153            device_id: &payload.device_id,
154            device_runtime_implementation_fingerprint: &payload
155                .device_runtime_implementation_fingerprint,
156            prepared_family_fingerprint: &payload.prepared_family_fingerprint,
157            program_fingerprint: &payload.program_fingerprint,
158            capability_catalog_fingerprint: &payload.capability_catalog_fingerprint,
159            policy_version: payload.policy_version,
160            policy_fingerprint: &payload.policy_fingerprint,
161            maximum_scheduled_tokens: payload.maximum_scheduled_tokens,
162            execution_weights: &payload.execution_weights,
163            weight_format: &payload.weight_format,
164            quantization_formats: &payload.quantization_formats,
165            retained_completion_values: &payload.retained_completion_values,
166            terminal_output_resources: &payload.terminal_output_resources,
167            nodes: &payload.nodes,
168            memory: &payload.memory,
169            sequence_checkpoint_layout: payload.sequence_checkpoint_layout.as_ref(),
170        }
171    }
172}
173
174/// A wire payload is deliberately not an executable plan. It must be rebuilt
175/// against a typed model family, catalog, and runtime policy before use.
176#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
177#[serde(deny_unknown_fields)]
178pub struct UnvalidatedProviderResourcePlan {
179    pub(super) provider_id: ProviderId,
180    pub(super) estimator_id: String,
181    pub(super) estimator_version: ContractVersion,
182    pub(super) estimator_implementation_fingerprint: String,
183    pub(super) estimator_input_fingerprint: String,
184    pub(super) estimate_fingerprint: String,
185    pub(super) value_alignment_bytes: u64,
186    pub(super) scratch: Option<ProviderWorkspaceRequirement>,
187    pub(super) binding: Option<ProviderWorkspaceRequirement>,
188    pub(super) persistent: Option<ProviderWorkspaceRequirement>,
189}
190
191#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
192#[serde(deny_unknown_fields)]
193pub struct UnvalidatedPlanNode {
194    pub(super) id: NodeId,
195    pub(super) dependencies: Vec<NodeId>,
196    pub(super) operation_id: OperationId,
197    pub(super) operation_version: ContractVersion,
198    pub(super) operation_fingerprint: String,
199    pub(super) provider_implementation_fingerprint: String,
200    pub(super) provider_execution_semantics: ProviderExecutionSemantics,
201    pub(super) required_capabilities: BTreeSet<CapabilityId>,
202    pub(super) attributes: BTreeMap<AttributeId, SemanticValue>,
203    pub(super) work: NodeWorkContract,
204    pub(super) selection: ProviderSelection,
205    pub(super) provider_resources: UnvalidatedProviderResourcePlan,
206    pub(super) values: Vec<ResolvedValueBinding>,
207    pub(super) exact_aliases: Vec<PlanExactAlias>,
208    pub(super) state_effects: Vec<PlanStateEffect>,
209    pub(super) scratch_resource: Option<ResourceId>,
210    pub(super) binding_resource: Option<ResourceId>,
211    pub(super) persistent_resource: Option<ResourceId>,
212    pub(super) resources: Vec<ResourceId>,
213}
214
215#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
216#[serde(deny_unknown_fields)]
217pub(super) struct UnvalidatedExecutionPlanPayload {
218    pub(super) schema: PlanSchemaVersion,
219    pub(super) plan_id: PlanId,
220    pub(super) family_id: ModelFamilyId,
221    pub(super) device_id: super::DeviceId,
222    pub(super) device_runtime_implementation_fingerprint: String,
223    pub(super) prepared_family_fingerprint: String,
224    pub(super) program_fingerprint: String,
225    pub(super) capability_catalog_fingerprint: String,
226    pub(super) policy_version: ContractVersion,
227    pub(super) policy_fingerprint: String,
228    pub(super) maximum_scheduled_tokens: u64,
229    pub(super) execution_weights: ExecutionWeightPlan,
230    pub(super) weight_format: WeightFormatId,
231    pub(super) quantization_formats: BTreeSet<QuantizationFormatId>,
232    pub(super) retained_completion_values: Vec<RetainedCompletionValue>,
233    pub(super) terminal_output_resources: Vec<ResourceId>,
234    pub(super) nodes: Vec<UnvalidatedPlanNode>,
235    pub(super) memory: MemoryPlan,
236    #[serde(default, skip_serializing_if = "Option::is_none")]
237    pub(super) sequence_checkpoint_layout: Option<SequenceCheckpointLayoutData>,
238}
239
240#[derive(Debug, Clone, PartialEq, Eq)]
241pub struct UnvalidatedExecutionPlan {
242    pub(super) payload: UnvalidatedExecutionPlanPayload,
243    pub(super) plan_hash: PlanHash,
244}
245
246#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
247pub(crate) struct UnvalidatedExecutionPlanWire {
248    pub(super) payload: UnvalidatedExecutionPlanPayload,
249    pub(super) plan_hash: PlanHash,
250}
251
252#[derive(Deserialize, Serialize)]
253#[serde(deny_unknown_fields)]
254pub(super) struct UnvalidatedExecutionPlanWireFields {
255    pub(super) payload: UnvalidatedExecutionPlanPayload,
256    pub(super) plan_hash: PlanHash,
257}
258
259impl<'de> Deserialize<'de> for UnvalidatedExecutionPlanWire {
260    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
261    where
262        D: Deserializer<'de>,
263    {
264        let raw = serde_json::Value::deserialize(deserializer)?;
265        let fields = UnvalidatedExecutionPlanWireFields::deserialize(&raw)
266            .map_err(serde::de::Error::custom)?;
267        if let Some(layout) = &fields.payload.sequence_checkpoint_layout {
268            layout
269                .validate_version()
270                .map_err(serde::de::Error::custom)?;
271        }
272        let canonical = serde_json::to_value(&fields).map_err(serde::de::Error::custom)?;
273        if canonical != raw {
274            return Err(serde::de::Error::custom(
275                "execution plan wire contains unknown or non-canonical nested fields",
276            ));
277        }
278        Ok(Self {
279            payload: fields.payload,
280            plan_hash: fields.plan_hash,
281        })
282    }
283}
284
285impl From<UnvalidatedExecutionPlanWire> for UnvalidatedExecutionPlan {
286    fn from(wire: UnvalidatedExecutionPlanWire) -> Self {
287        Self {
288            payload: wire.payload,
289            plan_hash: wire.plan_hash,
290        }
291    }
292}