use anyhow::Result;
use rigg_core::resources::ResourceKind;
pub fn order_by_dependencies(
resources: &[(ResourceKind, String, serde_json::Value, bool)],
) -> Vec<(ResourceKind, String, serde_json::Value, bool)> {
let order = [
ResourceKind::SynonymMap, ResourceKind::DataSource, ResourceKind::Index, ResourceKind::Alias, ResourceKind::Skillset, ResourceKind::KnowledgeBase, ResourceKind::Indexer, ResourceKind::KnowledgeSource, ResourceKind::Agent, ];
let mut ordered = resources.to_vec();
ordered
.sort_by_key(|(kind, _, _, _)| order.iter().position(|k| k == kind).unwrap_or(usize::MAX));
ordered
}
pub fn read_agent_yaml(path: &std::path::Path) -> Result<serde_json::Value> {
let content = std::fs::read_to_string(path)?;
rigg_core::resources::agent::yaml_to_agent(&content)
.map_err(|e| anyhow::anyhow!("Invalid YAML in {}: {}", path.display(), e))
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn test_order_datasource_before_indexer() {
let resources = vec![
(ResourceKind::Indexer, "ixer".to_string(), json!({}), false),
(ResourceKind::DataSource, "ds".to_string(), json!({}), false),
];
let ordered = order_by_dependencies(&resources);
assert_eq!(ordered[0].0, ResourceKind::DataSource);
assert_eq!(ordered[1].0, ResourceKind::Indexer);
}
#[test]
fn test_order_index_before_indexer() {
let resources = vec![
(ResourceKind::Indexer, "ixer".to_string(), json!({}), false),
(ResourceKind::Index, "idx".to_string(), json!({}), false),
];
let ordered = order_by_dependencies(&resources);
assert_eq!(ordered[0].0, ResourceKind::Index);
assert_eq!(ordered[1].0, ResourceKind::Indexer);
}
#[test]
fn test_order_knowledge_base_before_knowledge_source() {
let resources = vec![
(
ResourceKind::KnowledgeSource,
"ks".to_string(),
json!({}),
false,
),
(
ResourceKind::KnowledgeBase,
"kb".to_string(),
json!({}),
false,
),
];
let ordered = order_by_dependencies(&resources);
assert_eq!(ordered[0].0, ResourceKind::KnowledgeBase);
assert_eq!(ordered[1].0, ResourceKind::KnowledgeSource);
}
#[test]
fn test_order_full_dependency_chain() {
let resources = vec![
(
ResourceKind::KnowledgeSource,
"ks".to_string(),
json!({}),
false,
),
(ResourceKind::Indexer, "ixer".to_string(), json!({}), false),
(ResourceKind::Index, "idx".to_string(), json!({}), false),
(ResourceKind::Alias, "al".to_string(), json!({}), false),
(ResourceKind::DataSource, "ds".to_string(), json!({}), false),
(
ResourceKind::KnowledgeBase,
"kb".to_string(),
json!({}),
false,
),
(ResourceKind::Skillset, "sk".to_string(), json!({}), false),
(ResourceKind::SynonymMap, "sm".to_string(), json!({}), false),
];
let ordered = order_by_dependencies(&resources);
let kinds: Vec<_> = ordered.iter().map(|(k, _, _, _)| *k).collect();
assert_eq!(
kinds,
vec![
ResourceKind::SynonymMap,
ResourceKind::DataSource,
ResourceKind::Index,
ResourceKind::Alias,
ResourceKind::Skillset,
ResourceKind::KnowledgeBase,
ResourceKind::Indexer,
ResourceKind::KnowledgeSource,
]
);
}
#[test]
fn test_order_empty() {
let resources: Vec<(ResourceKind, String, serde_json::Value, bool)> = vec![];
let ordered = order_by_dependencies(&resources);
assert!(ordered.is_empty());
}
#[test]
fn test_order_preserves_within_same_kind() {
let resources = vec![
(ResourceKind::Index, "b-index".to_string(), json!({}), false),
(ResourceKind::Index, "a-index".to_string(), json!({}), false),
];
let ordered = order_by_dependencies(&resources);
assert_eq!(ordered[0].1, "b-index");
assert_eq!(ordered[1].1, "a-index");
}
#[test]
fn test_read_agent_yaml_full() {
let dir = tempfile::tempdir().unwrap();
let yaml_path = dir.path().join("my-agent.yaml");
std::fs::write(
&yaml_path,
"kind: prompt\nmodel: gpt-4o\ninstructions: You are helpful.\ntools:\n - type: code_interpreter\ntool_resources:\n file_search:\n vector_store_ids:\n - vs_1\n",
)
.unwrap();
let value = read_agent_yaml(&yaml_path).unwrap();
assert_eq!(value["model"], "gpt-4o");
assert_eq!(value["kind"], "prompt");
assert!(value["instructions"].as_str().unwrap().contains("helpful"));
assert_eq!(value["tools"].as_array().unwrap().len(), 1);
assert!(
value["tool_resources"]["file_search"]["vector_store_ids"]
.as_array()
.unwrap()
.len()
== 1
);
}
#[test]
fn test_read_agent_yaml_missing_file() {
let dir = tempfile::tempdir().unwrap();
let yaml_path = dir.path().join("missing.yaml");
let result = read_agent_yaml(&yaml_path);
assert!(result.is_err());
}
#[test]
fn test_read_agent_yaml_invalid_yaml() {
let dir = tempfile::tempdir().unwrap();
let yaml_path = dir.path().join("bad.yaml");
std::fs::write(&yaml_path, "{{invalid yaml").unwrap();
let result = read_agent_yaml(&yaml_path);
assert!(result.is_err());
}
#[test]
fn test_read_agent_yaml_roundtrip() {
use rigg_core::resources::agent::agent_to_yaml;
let dir = tempfile::tempdir().unwrap();
let yaml_path = dir.path().join("roundtrip.yaml");
let original = json!({
"name": "roundtrip",
"kind": "prompt",
"model": "gpt-4o",
"instructions": "Be concise.",
"tools": [{"type": "file_search"}]
});
let yaml = agent_to_yaml(&original);
std::fs::write(&yaml_path, &yaml).unwrap();
let parsed = read_agent_yaml(&yaml_path).unwrap();
assert_eq!(parsed["kind"], "prompt");
assert_eq!(parsed["model"], "gpt-4o");
assert_eq!(parsed["instructions"], "Be concise.");
assert_eq!(parsed["tools"].as_array().unwrap().len(), 1);
}
}