Add operator Mentra memory browser
This commit is contained in:
186
vendor/mentra/benches/long_session.rs
vendored
Normal file
186
vendor/mentra/benches/long_session.rs
vendored
Normal file
@@ -0,0 +1,186 @@
|
||||
use criterion::{Criterion, criterion_group, criterion_main};
|
||||
use mentra::{
|
||||
ContentBlock,
|
||||
memory::{MemoryRecord, MemoryRecordKind, MemorySearchMode, MemorySearchRequest, MemoryStore},
|
||||
runtime::SqliteRuntimeStore,
|
||||
test::{MockRuntimeBuilder, MockTurn},
|
||||
};
|
||||
use std::time::SystemTime;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Helpers
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn now_secs() -> i64 {
|
||||
SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_secs() as i64
|
||||
}
|
||||
|
||||
fn temp_sqlite_path(label: &str) -> std::path::PathBuf {
|
||||
std::env::temp_dir().join(format!(
|
||||
"mentra-bench-{}-{}.sqlite",
|
||||
label,
|
||||
SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.unwrap_or_default()
|
||||
.as_nanos()
|
||||
))
|
||||
}
|
||||
|
||||
fn build_mock_runtime(
|
||||
n_turns: usize,
|
||||
store_path: std::path::PathBuf,
|
||||
) -> (mentra::test::MockRuntime, mentra::ModelInfo) {
|
||||
let store = SqliteRuntimeStore::new(store_path);
|
||||
let mut builder = MockRuntimeBuilder::default().with_store(store);
|
||||
for i in 0..n_turns {
|
||||
builder = builder.push_turn(MockTurn::Text(format!("turn {i} response")));
|
||||
}
|
||||
let mock = builder.build().expect("build mock runtime");
|
||||
let model = mock.model();
|
||||
(mock, model)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// bench_500_turn_session
|
||||
// Measures total wall time for driving 500 send/response cycles.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn bench_500_turn_session(c: &mut Criterion) {
|
||||
let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
|
||||
|
||||
c.bench_function("500_turn_session", |b| {
|
||||
b.to_async(&rt).iter(|| async {
|
||||
let store_path = temp_sqlite_path("500turns");
|
||||
let (mock, model) = build_mock_runtime(500, store_path);
|
||||
let mut agent = mock
|
||||
.runtime()
|
||||
.spawn("bench-agent", model)
|
||||
.expect("spawn agent");
|
||||
|
||||
for i in 0u32..500 {
|
||||
agent
|
||||
.send(vec![ContentBlock::text(format!("message {i}"))])
|
||||
.await
|
||||
.expect("send turn");
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// bench_resume_after_heavy_session
|
||||
// 200 turns followed by a resume from the persisted agent record.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn bench_resume_after_heavy_session(c: &mut Criterion) {
|
||||
let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
|
||||
|
||||
c.bench_function("resume_after_200_turn_session", |b| {
|
||||
b.to_async(&rt).iter(|| async {
|
||||
let store_path = temp_sqlite_path("resume");
|
||||
// Prepare: 200 turns for the heavy session + 1 turn for the resumed send
|
||||
let store = SqliteRuntimeStore::new(store_path.clone());
|
||||
let mut builder = MockRuntimeBuilder::default().with_store(store);
|
||||
for i in 0..201usize {
|
||||
builder = builder.push_turn(MockTurn::Text(format!("turn {i} response")));
|
||||
}
|
||||
let mock = builder.build().expect("build mock runtime");
|
||||
let model = mock.model();
|
||||
|
||||
// Drive the heavy session
|
||||
let agent_id = {
|
||||
let mut agent = mock
|
||||
.runtime()
|
||||
.spawn("bench-agent", model.clone())
|
||||
.expect("spawn agent");
|
||||
for i in 0u32..200 {
|
||||
agent
|
||||
.send(vec![ContentBlock::text(format!("message {i}"))])
|
||||
.await
|
||||
.expect("send turn");
|
||||
}
|
||||
agent.id().to_string()
|
||||
};
|
||||
|
||||
// Measure: resume and send one more turn
|
||||
let mut resumed = mock
|
||||
.runtime()
|
||||
.resume_agent(&agent_id)
|
||||
.expect("resume agent");
|
||||
resumed
|
||||
.send(vec![ContentBlock::text("resumed message")])
|
||||
.await
|
||||
.expect("send after resume");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// bench_memory_scaling_1000_records
|
||||
// Seeds 1000 memory records into a SQLite store and measures search latency.
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
fn bench_memory_scaling_1000_records(c: &mut Criterion) {
|
||||
use mentra::memory::SqliteHybridMemoryStore;
|
||||
|
||||
let rt = tokio::runtime::Runtime::new().expect("tokio runtime");
|
||||
|
||||
c.bench_function("memory_search_1000_records", |b| {
|
||||
b.to_async(&rt).iter(|| async {
|
||||
let store_path = temp_sqlite_path("memory");
|
||||
let store = SqliteHybridMemoryStore::new(&store_path);
|
||||
|
||||
// Seed 1000 records
|
||||
let records: Vec<MemoryRecord> = (0..1000usize)
|
||||
.map(|i| MemoryRecord {
|
||||
record_id: format!("rec-{i:04}"),
|
||||
agent_id: "bench-agent".to_string(),
|
||||
kind: if i % 3 == 0 {
|
||||
MemoryRecordKind::Episode
|
||||
} else if i % 3 == 1 {
|
||||
MemoryRecordKind::Fact
|
||||
} else {
|
||||
MemoryRecordKind::Summary
|
||||
},
|
||||
content: format!(
|
||||
"memory record {i}: the agent discussed topic {i} in session {i}"
|
||||
),
|
||||
source_revision: i as u64,
|
||||
created_at: now_secs() - i as i64,
|
||||
metadata_json: "{}".to_string(),
|
||||
source: None,
|
||||
pinned: false,
|
||||
score: None,
|
||||
})
|
||||
.collect();
|
||||
|
||||
store.upsert_records(&records).expect("seed records");
|
||||
|
||||
// Measure search latency
|
||||
let request = MemorySearchRequest {
|
||||
agent_id: "bench-agent".to_string(),
|
||||
query: "agent discussed topic session".to_string(),
|
||||
limit: 20,
|
||||
char_budget: None,
|
||||
mode: MemorySearchMode::Automatic,
|
||||
};
|
||||
let _hits = store
|
||||
.search_records_with_options(&request)
|
||||
.expect("search records");
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Criterion group
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
criterion_group! {
|
||||
name = benches;
|
||||
config = Criterion::default().sample_size(10);
|
||||
targets = bench_500_turn_session, bench_resume_after_heavy_session, bench_memory_scaling_1000_records
|
||||
}
|
||||
criterion_main!(benches);
|
||||
Reference in New Issue
Block a user