public_01_remember_recall/
01_remember_recall.rs1#[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 = "public_01_remember_recall";
13 let started = Instant::now();
14 let client = create_client().await?;
15 let run_id = new_run_id("public_01_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 with upsert_key idempotency".to_string();
21 let mut metrics = json!({});
22
23 let scenario = async {
24 let upsert_key = format!("remember-recall-{run_id}");
25 let mut remember = RememberOptions::new(
26 "Before retrying cache rebuilds, verify the token signer has rotated cleanly.",
27 );
28 remember.run_id = Some(run_id.clone());
29 remember.agent_id = Some("helper-example".to_string());
30 remember.intent = Some("lesson".to_string());
31 remember.lesson_type = Some("success".to_string());
32 remember.lesson_scope = Some("session".to_string());
33 remember.upsert_key = Some(upsert_key.clone());
34 remember.metadata = Some(json!({ "source": "rust-helper-example" }));
35
36 let remembered = client.remember(remember).await?;
37 require(
38 remembered
39 .get("done")
40 .and_then(|value| value.as_bool())
41 .unwrap_or(false),
42 format!("remember should wait for ingest completion: {remembered}"),
43 )?;
44
45 let mut updated = RememberOptions::new(
46 "Before retrying cache rebuilds, verify the signer rotation completed and invalidate stale cache tokens.",
47 );
48 updated.run_id = Some(run_id.clone());
49 updated.agent_id = Some("helper-example".to_string());
50 updated.intent = Some("lesson".to_string());
51 updated.lesson_type = Some("success".to_string());
52 updated.lesson_scope = Some("session".to_string());
53 updated.upsert_key = Some(upsert_key.clone());
54 updated.metadata = Some(json!({ "source": "rust-helper-example", "revision": 2 }));
55
56 let updated_response = client.remember(updated).await?;
57 require(
58 updated_response
59 .get("done")
60 .and_then(|value| value.as_bool())
61 .unwrap_or(false),
62 format!("upsert remember should wait for ingest completion: {updated_response}"),
63 )?;
64
65 let mut recall = RecallOptions::new("What should I verify before retrying cache rebuilds?");
66 recall.run_id = Some(run_id.clone());
67 recall.entry_types = vec!["lesson".to_string(), "fact".to_string()];
68 let answer = client.recall(recall).await?;
69 let evidence = answer
70 .get("evidence")
71 .and_then(|value| value.as_array())
72 .ok_or_else(|| boxed_error(format!("evidence missing: {answer}")))?;
73 require(!evidence.is_empty(), format!("evidence missing: {answer}"))?;
74 let rendered = evidence
75 .iter()
76 .filter_map(|item| item.get("content").and_then(|value| value.as_str()))
77 .collect::<Vec<_>>()
78 .join(" ");
79 require(
80 rendered.contains("invalidate stale cache tokens"),
81 format!("upserted lesson should be recalled: {answer}"),
82 )?;
83 require(
84 answer
85 .get("final_answer")
86 .and_then(|value| value.as_str())
87 .is_some(),
88 format!("final answer missing: {answer}"),
89 )?;
90
91 metrics = json!({
92 "run_id": run_id,
93 "evidence_count": evidence.len(),
94 "confidence": answer.get("confidence").cloned().unwrap_or(serde_json::Value::Null),
95 "upsert_key": upsert_key,
96 });
97
98 Ok::<(), Box<dyn Error>>(())
99 }
100 .await;
101
102 if let Err(err) = scenario {
103 passed = false;
104 detail = err.to_string();
105 }
106
107 let cleanup_ok = cleanup_run(&client, &run_id).await;
108 if !cleanup_ok {
109 passed = false;
110 detail = format!("{detail} | cleanup failures");
111 }
112
113 print_summary(
114 name,
115 passed,
116 &detail,
117 &metrics,
118 started.elapsed().as_secs_f64(),
119 cleanup_ok,
120 );
121
122 if passed {
123 Ok(())
124 } else {
125 Err(boxed_error(detail))
126 }
127}