Skip to main content

helper_remember_recall/
helper_remember_recall.rs

1#[path = "support/utils.rs"]
2mod _utils;
3
4use _utils::{boxed_error, cleanup_run, create_client, new_run_id, print_summary, require};
5use mubit_sdk::{RecallOptions, RememberOptions, TransportMode};
6use serde_json::json;
7use std::error::Error;
8use std::time::Instant;
9
10#[tokio::main(flavor = "current_thread")]
11async fn main() -> Result<(), Box<dyn Error>> {
12    let name = "helper_remember_recall";
13    let started = Instant::now();
14    let client = create_client().await?;
15    let run_id = new_run_id("helper_remember_recall");
16    client.set_run_id(Some(run_id.clone()));
17    client.set_transport(TransportMode::Http);
18
19    let mut passed = true;
20    let mut detail = "validated helper remember -> recall flow".to_string();
21    let mut metrics = json!({});
22
23    let scenario = async {
24        let mut remember = RememberOptions::new(
25            "Before retrying cache rebuilds, verify the token signer has rotated cleanly.",
26        );
27        remember.run_id = Some(run_id.clone());
28        remember.agent_id = Some("helper-example".to_string());
29        remember.intent = Some("lesson".to_string());
30        remember.lesson_type = Some("success".to_string());
31        remember.lesson_scope = Some("session".to_string());
32        remember.metadata = Some(json!({ "source": "rust-helper-example" }));
33        remember.occurrence_time = Some(std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as i64 - 86400);
34
35        let remembered = client.remember(remember).await?;
36        require(
37            remembered
38                .get("done")
39                .and_then(|value| value.as_bool())
40                .unwrap_or(false),
41            format!("remember should wait for ingest completion: {remembered}"),
42        )?;
43
44        let mut recall = RecallOptions::new("What should I verify before retrying cache rebuilds?");
45        recall.run_id = Some(run_id.clone());
46        recall.entry_types = vec!["lesson".to_string(), "fact".to_string()];
47        let answer = client.recall(recall).await?;
48        let evidence = answer
49            .get("evidence")
50            .and_then(|value| value.as_array())
51            .ok_or_else(|| boxed_error(format!("evidence missing: {answer}")))?;
52        require(!evidence.is_empty(), format!("evidence missing: {answer}"))?;
53        require(
54            answer
55                .get("final_answer")
56                .and_then(|value| value.as_str())
57                .is_some(),
58            format!("final answer missing: {answer}"),
59        )?;
60
61        metrics = json!({
62            "run_id": run_id,
63            "evidence_count": evidence.len(),
64            "confidence": answer.get("confidence").cloned().unwrap_or(serde_json::Value::Null),
65        });
66
67        Ok::<(), Box<dyn Error>>(())
68    }
69    .await;
70
71    if let Err(err) = scenario {
72        passed = false;
73        detail = err.to_string();
74    }
75
76    let cleanup_ok = cleanup_run(&client, &run_id).await;
77    if !cleanup_ok {
78        passed = false;
79        detail = format!("{detail} | cleanup failures");
80    }
81
82    print_summary(
83        name,
84        passed,
85        &detail,
86        &metrics,
87        started.elapsed().as_secs_f64(),
88        cleanup_ok,
89    );
90
91    if passed {
92        Ok(())
93    } else {
94        Err(boxed_error(detail))
95    }
96}