Skip to main content

busbar_sf_agentscript/graph/
nodes.rs

1//! Node types for the reference graph.
2
3use serde::{Deserialize, Serialize};
4
5/// A span in the source code (start, end byte offsets).
6pub type Span = (usize, usize);
7
8/// A node in the reference graph representing a definition.
9#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
10pub enum RefNode {
11    /// The start_agent entry point
12    StartAgent {
13        /// Source location
14        span: Span,
15    },
16
17    /// A topic definition
18    Topic {
19        /// Topic name
20        name: String,
21        /// Source location
22        span: Span,
23    },
24
25    /// An action definition within a topic
26    ActionDef {
27        /// Action name
28        name: String,
29        /// Parent topic name
30        topic: String,
31        /// Source location
32        span: Span,
33    },
34
35    /// A reasoning action within a topic
36    ReasoningAction {
37        /// Reasoning action name
38        name: String,
39        /// Parent topic name
40        topic: String,
41        /// The target action or topic this reasoning action invokes
42        target: Option<String>,
43        /// Source location
44        span: Span,
45    },
46
47    /// A variable definition
48    Variable {
49        /// Variable name
50        name: String,
51        /// Whether this is a mutable variable
52        mutable: bool,
53        /// Source location
54        span: Span,
55    },
56
57    /// A connection/escalation definition
58    Connection {
59        /// Connection name
60        name: String,
61        /// Source location
62        span: Span,
63    },
64}
65
66impl RefNode {
67    /// Get a human-readable label for this node.
68    pub fn label(&self) -> String {
69        match self {
70            RefNode::StartAgent { .. } => "start_agent".to_string(),
71            RefNode::Topic { name, .. } => format!("topic:{}", name),
72            RefNode::ActionDef { name, topic, .. } => format!("action:{}:{}", topic, name),
73            RefNode::ReasoningAction { name, topic, .. } => {
74                format!("reasoning:{}:{}", topic, name)
75            }
76            RefNode::Variable { name, .. } => format!("variable:{}", name),
77            RefNode::Connection { name, .. } => format!("connection:{}", name),
78        }
79    }
80
81    /// Get the source span for this node.
82    pub fn span(&self) -> Span {
83        match self {
84            RefNode::StartAgent { span }
85            | RefNode::Topic { span, .. }
86            | RefNode::ActionDef { span, .. }
87            | RefNode::ReasoningAction { span, .. }
88            | RefNode::Variable { span, .. }
89            | RefNode::Connection { span, .. } => *span,
90        }
91    }
92
93    /// Get the name of this node (if applicable).
94    pub fn name(&self) -> Option<&str> {
95        match self {
96            RefNode::StartAgent { .. } => None,
97            RefNode::Topic { name, .. }
98            | RefNode::ActionDef { name, .. }
99            | RefNode::ReasoningAction { name, .. }
100            | RefNode::Variable { name, .. }
101            | RefNode::Connection { name, .. } => Some(name),
102        }
103    }
104
105    /// Check if this node is a topic.
106    pub fn is_topic(&self) -> bool {
107        matches!(self, RefNode::Topic { .. })
108    }
109
110    /// Check if this node is an action definition.
111    pub fn is_action_def(&self) -> bool {
112        matches!(self, RefNode::ActionDef { .. })
113    }
114
115    /// Check if this node is a reasoning action.
116    pub fn is_reasoning_action(&self) -> bool {
117        matches!(self, RefNode::ReasoningAction { .. })
118    }
119
120    /// Check if this node is a variable.
121    pub fn is_variable(&self) -> bool {
122        matches!(self, RefNode::Variable { .. })
123    }
124}