Skip to main content

harn_vm/vm/
async_builtin.rs

1use std::cell::RefCell;
2
3use super::Vm;
4
5thread_local! {
6    pub(super) static CURRENT_ASYNC_BUILTIN_CHILD_VM: RefCell<Vec<Vm>> =
7        const { RefCell::new(Vec::new()) };
8}
9
10/// Clone the VM at the top of the async-builtin child VM stack, returning a
11/// fresh `Vm` instance the caller owns. Enables concurrent tool-handler
12/// execution within a single agent_loop iteration — the VM shares its heavy
13/// state (env, builtins, bridge, module_cache) via `Arc`/`Rc`, so cloning is
14/// cheap and each handler gets its own execution context.
15///
16/// Returns `None` if no parent VM is currently pushed on the stack.
17pub fn clone_async_builtin_child_vm() -> Option<Vm> {
18    CURRENT_ASYNC_BUILTIN_CHILD_VM.with(|slot| slot.borrow().last().map(|vm| vm.child_vm()))
19}
20
21pub struct AsyncBuiltinChildVmGuard;
22
23pub fn install_async_builtin_child_vm(vm: Vm) -> AsyncBuiltinChildVmGuard {
24    CURRENT_ASYNC_BUILTIN_CHILD_VM.with(|slot| {
25        slot.borrow_mut().push(vm);
26    });
27    AsyncBuiltinChildVmGuard
28}
29
30impl Drop for AsyncBuiltinChildVmGuard {
31    fn drop(&mut self) {
32        CURRENT_ASYNC_BUILTIN_CHILD_VM.with(|slot| {
33            slot.borrow_mut().pop();
34        });
35    }
36}
37
38/// Legacy API preserved for out-of-tree callers; new code should use
39/// `clone_async_builtin_child_vm()`. `take/restore` serialized concurrent
40/// callers because only one could hold the popped value at a time.
41#[deprecated(
42    note = "use clone_async_builtin_child_vm() — take/restore serialized concurrent callers"
43)]
44pub fn take_async_builtin_child_vm() -> Option<Vm> {
45    clone_async_builtin_child_vm()
46}
47
48/// Legacy no-op retained for backward compatibility.
49#[deprecated(note = "clone_async_builtin_child_vm does not need a matching restore call")]
50pub fn restore_async_builtin_child_vm(_vm: Vm) {
51    CURRENT_ASYNC_BUILTIN_CHILD_VM.with(|slot| {
52        let _ = slot;
53    });
54}