| 98a16830 Andy McCall ↶ |
1 |
|
| 2 |
|
| 3 |
|
| 4 |
|
| 5 |
|
| 6 |
|
| 7 |
mod common; |
| 8 |
|
| 9 |
use common::{add_agent, setup, Serving}; |
| 10 |
use serde_json::json; |
| 11 |
use spectra_mcp::client::{rpc_result, Client}; |
| 12 |
use std::time::{Duration, Instant}; |
| 13 |
|
| 14 |
async fn call(c: &Client, name: &str, args: serde_json::Value) -> serde_json::Value { |
| 15 |
let req = json!({ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": name, "arguments": args } }); |
| 16 |
rpc_result(&c.mcp("2025-11-25", &req).await.unwrap()).unwrap() |
| 17 |
} |
| 18 |
|
| 19 |
fn median(mut v: Vec<Duration>) -> Duration { |
| 20 |
v.sort(); |
| 21 |
v[v.len() / 2] |
| 22 |
} |
| 23 |
|
| 24 |
#[tokio::test(flavor = "multi_thread", worker_threads = 4)] |
| 25 |
#[ignore] |
| 26 |
async fn spec_24_targets() { |
| 27 |
let dir = setup(); |
| 28 |
let d = dir.path(); |
| 29 |
let a = add_agent(d, "bench-a", &[]); |
| 30 |
let b = add_agent(d, "bench-b", &[]); |
| 31 |
let srv = Serving::start(d); |
| 32 |
let (ca, cb) = (Client::new(&srv.socket, Some(a)), Client::new(&srv.socket, Some(b))); |
| 33 |
for i in 0..1_000 { |
| 34 |
call(&ca, "say", json!({ "body": format!("message {i} about the pin bump"), "channel": "general" })).await; |
| 35 |
} |
| 36 |
let mut brief = Vec::new(); |
| 37 |
let mut say = Vec::new(); |
| 38 |
for i in 0..50 { |
| 39 |
let t = Instant::now(); |
| 40 |
call(&ca, "brief", json!({})).await; |
| 41 |
brief.push(t.elapsed()); |
| 42 |
let t = Instant::now(); |
| 43 |
call(&ca, "say", json!({ "body": format!("timed {i}") })).await; |
| 44 |
say.push(t.elapsed()); |
| 45 |
} |
| 46 |
let mut wake = Vec::new(); |
| 47 |
for i in 0..10 { |
| 48 |
let w = tokio::spawn({ |
| 49 |
let cb = Client::new(&srv.socket, Some(spectra_core::keys::KeyPair::load_home(&d.join("agents/bench-b")).unwrap())); |
| 50 |
async move { |
| 51 |
call(&cb, "wait", json!({ "timeout_s": 20 })).await; |
| 52 |
Instant::now() |
| 53 |
} |
| 54 |
}); |
| 55 |
tokio::time::sleep(Duration::from_millis(200)).await; |
| 56 |
let sent = Instant::now(); |
| 57 |
call(&ca, "say", json!({ "body": format!("@bench-b wake {i}"), "channel": "general" })).await; |
| 58 |
wake.push(w.await.unwrap().saturating_duration_since(sent)); |
| 59 |
call(&cb, "ack", json!({ "ids": [] })).await; |
| 60 |
let inbox = call(&cb, "inbox", json!({})).await; |
| 61 |
let ids: Vec<serde_json::Value> = |
| 62 |
inbox["result"]["structuredContent"]["items"].as_array().unwrap().iter().map(|i| i["id"].clone()).collect(); |
| 63 |
call(&cb, "ack", json!({ "ids": ids })).await; |
| 64 |
} |
| 65 |
println!("spec §24 with 1,000 messages, round trip over the socket including signing:"); |
| 66 |
println!(" brief median {:?}", median(brief)); |
| 67 |
println!(" say median {:?}", median(say)); |
| 68 |
println!(" wait wakes {:?} after the mention is sent (median)", median(wake)); |
| 69 |
srv.stop(); |
| 70 |
} |