jellyflow_runtime/profile/mod.rs
1//! Domain specializations for node graphs.
2//!
3//! A profile selects:
4//! - how port types are resolved (schema vs inferred vs domain-owned),
5//! - which compatibility rules apply,
6//! - how concretization (dynamic ports) is scheduled,
7//! - how validation diagnostics are produced.
8//!
9//! This module is intentionally headless (no `fret-ui` dependency).
10
11mod pipeline;
12
13use crate::io::NodeGraphInteractionState;
14use crate::rules::{ConnectPlan, Diagnostic};
15use jellyflow_core::core::{EdgeKind, Graph, PortId};
16use jellyflow_core::interaction::NodeGraphConnectionMode;
17use jellyflow_core::types::{DefaultTypeCompatibility, TypeDesc};
18pub(crate) use pipeline::apply_transaction_with_profile_in_place;
19pub use pipeline::{
20 ApplyPipelineError, apply_connect_plan_with_profile, apply_transaction_with_profile,
21};
22
23/// Profile hooks for typed graphs and domain specialization.
24pub trait GraphProfile {
25 /// Returns the current type of a port.
26 ///
27 /// Default implementations may read `Port::ty` and/or derive from node payloads.
28 fn type_of_port(&mut self, graph: &Graph, port: PortId) -> Option<TypeDesc>;
29
30 /// Plans connecting two ports under this profile.
31 ///
32 /// Implementations should call into `crate::rules` and then enforce extra constraints
33 /// (type compatibility, cycle policy, exec/data policy, etc.).
34 fn plan_connect(
35 &mut self,
36 graph: &Graph,
37 a: PortId,
38 b: PortId,
39 mode: NodeGraphConnectionMode,
40 ) -> ConnectPlan {
41 let mut compat = DefaultTypeCompatibility::default();
42 crate::rules::plan_connect_typed_with_mode_and_policy(
43 graph,
44 a,
45 b,
46 mode,
47 &NodeGraphInteractionState::default(),
48 |graph, port| self.type_of_port(graph, port),
49 &mut compat,
50 )
51 }
52
53 /// Validates a graph and returns diagnostics.
54 fn validate_graph(&mut self, graph: &Graph) -> Vec<Diagnostic>;
55
56 /// Whether the profile allows cycles for the given edge kind.
57 fn allow_cycles(&self, _edge_kind: EdgeKind) -> bool {
58 true
59 }
60
61 /// Maximum number of concretization iterations per edit.
62 ///
63 /// This bounds fixed-point scheduling to prevent oscillation.
64 fn concretize_bound(&self) -> usize {
65 8
66 }
67
68 /// Runs concretization for dynamic ports and returns additional ops to apply.
69 ///
70 /// The returned ops must be deterministic and undoable.
71 fn concretize(&mut self, _graph: &Graph) -> Vec<jellyflow_core::ops::GraphOp> {
72 Vec::new()
73 }
74}