mod builder;
pub mod dependencies;
mod edges;
mod error;
pub mod export;
mod nodes;
mod queries;
pub mod render;
mod validation;
#[cfg(feature = "wasm")]
pub mod wasm;
pub use builder::RefGraphBuilder;
pub use dependencies::{extract_dependencies, Dependency, DependencyReport, DependencyType};
pub use edges::RefEdge;
pub use error::{GraphBuildError, ValidationError};
pub use export::{EdgeRepr, GraphExport, GraphRepr, NodeRepr, ValidationResultRepr};
pub use nodes::RefNode;
pub use queries::QueryResult;
pub use render::{render_actions_view, render_full_view, render_graphml, render_topic_flow};
pub use validation::ValidationResult;
use petgraph::graph::{DiGraph, NodeIndex};
use std::collections::HashMap;
#[derive(Debug)]
pub struct RefGraph {
graph: DiGraph<RefNode, RefEdge>,
topics: HashMap<String, NodeIndex>,
action_defs: HashMap<(String, String), NodeIndex>,
reasoning_actions: HashMap<(String, String), NodeIndex>,
variables: HashMap<String, NodeIndex>,
start_agent: Option<NodeIndex>,
unresolved_references: Vec<ValidationError>,
}
impl RefGraph {
pub fn from_ast(ast: &crate::AgentFile) -> Result<Self, GraphBuildError> {
RefGraphBuilder::new().build(ast)
}
pub fn inner(&self) -> &DiGraph<RefNode, RefEdge> {
&self.graph
}
pub fn get_node(&self, index: NodeIndex) -> Option<&RefNode> {
self.graph.node_weight(index)
}
pub fn get_topic(&self, name: &str) -> Option<NodeIndex> {
self.topics.get(name).copied()
}
pub fn get_action_def(&self, topic: &str, action: &str) -> Option<NodeIndex> {
self.action_defs
.get(&(topic.to_string(), action.to_string()))
.copied()
}
pub fn get_reasoning_action(&self, topic: &str, action: &str) -> Option<NodeIndex> {
self.reasoning_actions
.get(&(topic.to_string(), action.to_string()))
.copied()
}
pub fn get_variable(&self, name: &str) -> Option<NodeIndex> {
self.variables.get(name).copied()
}
pub fn get_start_agent(&self) -> Option<NodeIndex> {
self.start_agent
}
pub fn topic_names(&self) -> impl Iterator<Item = &str> {
self.topics.keys().map(|s| s.as_str())
}
pub fn variable_names(&self) -> impl Iterator<Item = &str> {
self.variables.keys().map(|s| s.as_str())
}
pub fn node_count(&self) -> usize {
self.graph.node_count()
}
pub fn edge_count(&self) -> usize {
self.graph.edge_count()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_empty_graph() {
let source = r#"config:
agent_name: "Test"
start_agent topic_selector:
description: "Route to topics"
reasoning:
instructions: "Select the best topic"
actions:
go_help: @utils.transition to @topic.help
description: "Go to help topic"
topic help:
description: "Help topic"
reasoning:
instructions: "Provide help"
"#;
let ast = crate::parse(source).unwrap();
let graph = RefGraph::from_ast(&ast).unwrap();
assert!(graph.node_count() > 0);
assert!(graph.get_topic("help").is_some());
assert!(graph.get_start_agent().is_some());
}
}