helper_handoff_feedback/
helper_handoff_feedback.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::{
6 FeedbackOptions, GetContextOptions, HandoffOptions, RegisterAgentOptions, TransportMode,
7};
8use serde_json::json;
9use std::error::Error;
10use std::time::Instant;
11
12#[tokio::main(flavor = "current_thread")]
13async fn main() -> Result<(), Box<dyn Error>> {
14 let name = "helper_handoff_feedback";
15 let started = Instant::now();
16 let client = create_client().await?;
17 let run_id = new_run_id("helper_handoff_feedback");
18 client.set_run_id(Some(run_id.clone()));
19 client.set_transport(TransportMode::Http);
20
21 let mut passed = true;
22 let mut detail = "validated helper handoff + feedback flow".to_string();
23 let mut metrics = json!({});
24
25 let scenario = async {
26 let mut planner = RegisterAgentOptions::new("planner");
27 planner.run_id = Some(run_id.clone());
28 planner.role = "planner".to_string();
29 client.register_agent(planner).await?;
30
31 let mut reviewer = RegisterAgentOptions::new("reviewer");
32 reviewer.run_id = Some(run_id.clone());
33 reviewer.role = "reviewer".to_string();
34 client.register_agent(reviewer).await?;
35
36 let mut handoff = HandoffOptions::new(
37 "task-1",
38 "planner",
39 "reviewer",
40 "Review the retry policy patch before rollout.",
41 );
42 handoff.run_id = Some(run_id.clone());
43 handoff.requested_action = "review".to_string();
44 handoff.metadata = Some(json!({ "source": "rust-helper-example" }));
45 let handoff_response = client.handoff(handoff).await?;
46 let handoff_id = handoff_response
47 .get("handoff_id")
48 .and_then(|value| value.as_str())
49 .ok_or_else(|| boxed_error(format!("handoff id missing: {handoff_response}")))?
50 .to_string();
51
52 let mut feedback = FeedbackOptions::new(handoff_id.clone(), "approve");
53 feedback.run_id = Some(run_id.clone());
54 feedback.comments = "Patch looks safe for rollout.".to_string();
55 feedback.from_agent_id = Some("reviewer".to_string());
56 feedback.metadata = Some(json!({ "source": "rust-helper-example" }));
57 let feedback_response = client.feedback(feedback).await?;
58
59 let mut context = GetContextOptions::default();
60 context.run_id = Some(run_id.clone());
61 context.query = Some("What coordination artifacts were recorded for this review handoff?".to_string());
62 context.mode = Some("sections".to_string());
63 context.sections = vec!["handoffs".to_string(), "feedback".to_string()];
64 let context_response = client.get_context(context).await?;
65
66 require(
67 handoff_response
68 .get("success")
69 .and_then(|value| value.as_bool())
70 .unwrap_or(false),
71 format!("handoff failed: {handoff_response}"),
72 )?;
73 require(
74 feedback_response
75 .get("success")
76 .and_then(|value| value.as_bool())
77 .unwrap_or(false),
78 format!("feedback failed: {feedback_response}"),
79 )?;
80 let section_count = context_response
81 .get("section_summaries")
82 .and_then(|value| value.as_array())
83 .map(|items| items.len())
84 .unwrap_or(0);
85
86 metrics = json!({
87 "run_id": run_id,
88 "handoff_id": handoff_id,
89 "feedback_id": feedback_response.get("feedback_id").cloned().unwrap_or(serde_json::Value::Null),
90 "section_count": section_count,
91 });
92
93 Ok::<(), Box<dyn Error>>(())
94 }
95 .await;
96
97 if let Err(err) = scenario {
98 passed = false;
99 detail = err.to_string();
100 }
101
102 let cleanup_ok = cleanup_run(&client, &run_id).await;
103 if !cleanup_ok {
104 passed = false;
105 detail = format!("{detail} | cleanup failures");
106 }
107
108 print_summary(
109 name,
110 passed,
111 &detail,
112 &metrics,
113 started.elapsed().as_secs_f64(),
114 cleanup_ok,
115 );
116
117 if passed {
118 Ok(())
119 } else {
120 Err(boxed_error(detail))
121 }
122}