#![recursion_limit = "256"]
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use std::time::Duration;
use harn_vm::bridge::HostBridge;
use harn_vm::value::{VmError, VmValue};
const WORKER_COUNT: usize = 4;
const STALL_MS: u64 = 200;
fn run_with_bridge(
source: &str,
register: impl FnOnce(&mut harn_vm::Vm) + 'static,
peak: Arc<AtomicUsize>,
) -> Result<String, String> {
harn_vm::reset_thread_local_state();
let chunk = harn_vm::compile_source(source)?;
let rt = tokio::runtime::Builder::new_current_thread()
.enable_all()
.start_paused(true)
.build()
.map_err(|e| e.to_string())?;
rt.block_on(async {
let local = tokio::task::LocalSet::new();
local
.run_until(async {
let vm_task = tokio::task::spawn_local(async move {
let bridge = Arc::new(HostBridge::from_parts(
Arc::new(tokio::sync::Mutex::new(std::collections::HashMap::new())),
Arc::new(AtomicBool::new(false)),
Arc::new(Mutex::new(())),
1,
));
harn_vm::llm::install_current_host_bridge(bridge.clone());
let mut vm = harn_vm::Vm::new();
harn_vm::register_vm_stdlib(&mut vm);
register(&mut vm);
let result = vm
.execute(&chunk)
.await
.map_err(|e: VmError| format!("{e:?}"));
let output = vm.output().to_string();
harn_vm::llm::clear_current_host_bridge();
result.map(|_| output)
});
for _ in 0..1_000 {
if peak.load(Ordering::SeqCst) >= WORKER_COUNT || vm_task.is_finished() {
break;
}
tokio::task::yield_now().await;
}
if peak.load(Ordering::SeqCst) < WORKER_COUNT {
vm_task.abort();
return Err(format!(
"background workers never all parked before virtual-time advance; peak={}",
peak.load(Ordering::SeqCst)
));
}
tokio::time::advance(Duration::from_millis(STALL_MS)).await;
vm_task.await.map_err(|e| e.to_string())?
})
.await
})
}
fn out_lines(raw: &str) -> Vec<String> {
raw.lines()
.filter_map(|l| l.strip_prefix("[harn] "))
.map(|s| s.to_string())
.collect()
}
fn parse_kv<'a>(lines: &'a [String], key: &str) -> Option<&'a str> {
lines
.iter()
.find_map(|line| line.strip_prefix(&format!("{key}=")))
}
fn require_usize(lines: &[String], key: &str) -> usize {
parse_kv(lines, key)
.and_then(|v| v.parse().ok())
.unwrap_or_else(|| panic!("missing/unparseable {key}; lines: {lines:?}"))
}
#[test]
fn background_workers_overlap_by_peak_in_flight_count() {
let source = format!(
r#"
fn make_caller() {{
return {{ call ->
__overlap_enter()
sleep({STALL_MS})
__overlap_exit()
return {{
ok: true,
value: {{
text: "<user_response>done</user_response>\n<done>##DONE##</done>",
provider: "mock",
model: "overlap-model",
input_tokens: 0,
output_tokens: 0,
}},
}}
}}
}}
fn base_opts() {{
return {{
provider: "mock",
model: "overlap-model",
llm_caller: make_caller(),
loop_until_done: true,
done_judge: false,
max_iterations: 1,
final_wrapup: false,
tool_format: "text",
}}
}}
pipeline main(task) {{
var handles = []
for i in 0 to {WORKER_COUNT} exclusive {{
handles = handles.push(sub_agent_run("bg worker " + to_string(i), base_opts() + {{background: true}}))
}}
let results = wait_agent(handles)
var conc_done = 0
for r in results {{
let env = r?.result
if (env?.ok ?? false) == true && contains(to_string(env?.summary ?? ""), "done") {{
conc_done = conc_done + 1
}}
}}
log("CONC_RESULTS=" + to_string(len(results)))
log("CONC_DONE=" + to_string(conc_done))
}}
"#,
);
let in_flight = Arc::new(AtomicUsize::new(0));
let peak = Arc::new(AtomicUsize::new(0));
let register = {
let enter_in_flight = in_flight.clone();
let enter_peak = peak.clone();
let exit_in_flight = in_flight.clone();
move |vm: &mut harn_vm::Vm| {
vm.register_builtin("__overlap_enter", move |_args, _out| {
let now = enter_in_flight.fetch_add(1, Ordering::SeqCst) + 1;
enter_peak.fetch_max(now, Ordering::SeqCst);
Ok(VmValue::Int(now as i64))
});
vm.register_builtin("__overlap_exit", move |_args, _out| {
exit_in_flight.fetch_sub(1, Ordering::SeqCst);
Ok(VmValue::Nil)
});
}
};
let raw = run_with_bridge(&source, register, peak.clone()).expect("overlap pipeline must run");
let lines = out_lines(&raw);
eprintln!("--- harn output ---");
for line in &lines {
eprintln!("{line}");
}
let conc_results = require_usize(&lines, "CONC_RESULTS");
let conc_done = require_usize(&lines, "CONC_DONE");
let peak_in_flight = peak.load(Ordering::SeqCst);
let residual_in_flight = in_flight.load(Ordering::SeqCst);
assert_eq!(
conc_results, WORKER_COUNT,
"concurrent phase: wait_agent must return one result per worker; lines: {lines:?}"
);
assert_eq!(
conc_done, WORKER_COUNT,
"concurrent phase: every background worker must complete; lines: {lines:?}"
);
assert_eq!(
residual_in_flight, 0,
"every __overlap_enter must be matched by an __overlap_exit; residual={residual_in_flight}"
);
assert_eq!(
peak_in_flight, WORKER_COUNT,
"OVERLAP REFUTED: peak concurrent in-flight workers was {peak_in_flight}, expected \
{WORKER_COUNT}. Background workers did not all run concurrently. lines: {lines:?}"
);
eprintln!("OVERLAP CONFIRMED: N={WORKER_COUNT}, peak in-flight={peak_in_flight}");
}