atman-runtime 1.8.0

atman flow execution runtime: evaluator, tool dispatch, provider dispatch, executor, memory stores
Documentation
use std::sync::Arc;

use atman_dsl::parse::parse_file;
use atman_runtime::memory::confession::ConfessionStore;
use atman_runtime::memory::spec::SpecStore;
use atman_runtime::memory::todo::TodoStore;
use atman_runtime::{Executor, tools, validate};
use tempfile::TempDir;

fn build_executor_with_memory(dir: &TempDir) -> Executor {
    let ex = Executor::new();
    tools::register_tier_zero(&ex.tools);
    let todo = Arc::new(TodoStore::at(dir.path()));
    let confession = Arc::new(ConfessionStore::at(dir.path()));
    let goal = Arc::new(atman_runtime::memory::GoalStore::at(dir.path()));
    let spec = Arc::new(SpecStore::new(dir.path().to_path_buf()));
    let plan = Arc::new(atman_runtime::memory::PlanStore::at(dir.path()));
    tools::register_memory(&ex.tools, todo, confession, goal, plan);
    tools::register_spec_memory(&ex.tools, spec);
    ex
}

#[test]
fn validate_accepts_registered_memory_tools() {
    let dir = TempDir::new().unwrap();
    let ex = build_executor_with_memory(&dir);
    let src = r#"flow t() -> string {
    memory.confess(trigger: "typo", rule_violated: "no", what_i_did: "x", why: "y", mitigation: "z")
    return "ok"
}
"#;
    let file = parse_file(src).unwrap();
    validate::validate(&file.flows[0], &ex.tools).expect("valid memory flow");
}

#[test]
fn validate_rejects_typo_in_memory_tool_name() {
    let dir = TempDir::new().unwrap();
    let ex = build_executor_with_memory(&dir);
    let src = r#"flow t() -> string {
    memory.confes(body: "typo")
    return "ok"
}
"#;
    let file = parse_file(src).unwrap();
    let errs = validate::validate(&file.flows[0], &ex.tools).unwrap_err();
    assert!(
        errs.iter().any(|e| matches!(
            e,
            validate::ValidationError::UndefinedTool(name) if name == "memory.confes"
        )),
        "expected UndefinedTool(memory.confes) in {errs:?}"
    );
}

#[test]
fn validate_rejects_unknown_memory_family() {
    let dir = TempDir::new().unwrap();
    let ex = build_executor_with_memory(&dir);
    let src = r#"flow t() -> string {
    memory.dream(body: "not a thing")
    return "ok"
}
"#;
    let file = parse_file(src).unwrap();
    let errs = validate::validate(&file.flows[0], &ex.tools).unwrap_err();
    assert!(
        errs.iter().any(|e| matches!(
            e,
            validate::ValidationError::UndefinedTool(name) if name == "memory.dream"
        )),
        "expected UndefinedTool(memory.dream) in {errs:?}"
    );
}

#[test]
fn validate_accepts_all_registered_memory_spec_tools() {
    let dir = TempDir::new().unwrap();
    let ex = build_executor_with_memory(&dir);
    for tool in &[
        "memory.spec.status",
        "memory.spec.update",
        "memory.spec.deviate",
        "memory.todo.set",
        "memory.todo.done",
        "memory.fetch_confessions",
    ] {
        assert!(
            ex.tools.has(tool),
            "expected tool `{tool}` to be registered"
        );
    }
}