localharness 0.51.0

Agents that own themselves: one Rust crate that's both an agent SDK (streaming, tools, hooks, policies, triggers, MCP) and a wallet-owning, self-sovereign agent that runs in the browser.
Documentation
//! Per-target async runtime helpers.
//!
//! On native, this delegates to tokio's multi-threaded runtime. On
//! wasm32 the only available scheduler is the browser event loop, which
//! `wasm_bindgen_futures::spawn_local` drives. The two APIs differ on
//! `Send` bounds — tokio requires futures be `Send`; the wasm scheduler
//! is single-threaded so it does not — so each platform gets its own
//! signature.
//!
//! Use `crate::runtime::spawn` instead of `tokio::spawn` anywhere the
//! call site needs to compile on both targets.

use std::future::Future;

/// A marker that is `Send + Sync` on native and a no-op on wasm32.
///
/// Use as a supertrait — `pub trait Tool: MaybeSendSync { ... }` — so
/// concrete implementations whose internals (e.g., reqwest's browser
/// fetch client) aren't `Send` can still satisfy the bound on wasm.
#[cfg(not(target_arch = "wasm32"))]
pub trait MaybeSendSync: Send + Sync {}
#[cfg(not(target_arch = "wasm32"))]
impl<T: ?Sized + Send + Sync> MaybeSendSync for T {}

#[cfg(target_arch = "wasm32")]
pub trait MaybeSendSync {}
#[cfg(target_arch = "wasm32")]
impl<T: ?Sized> MaybeSendSync for T {}

/// Spawn a fire-and-forget future onto the platform's async runtime.
///
/// The future's output is discarded; there is no `JoinHandle` because
/// wasm_bindgen_futures doesn't return one. If you need to await the
/// result, await the future directly instead of spawning it.
#[cfg(not(target_arch = "wasm32"))]
pub fn spawn<F>(f: F)
where
    F: Future<Output = ()> + Send + 'static,
{
    tokio::spawn(f);
}

#[cfg(target_arch = "wasm32")]
pub fn spawn<F>(f: F)
where
    F: Future<Output = ()> + 'static,
{
    wasm_bindgen_futures::spawn_local(f);
}

/// Sleep for `ms` milliseconds on either target.
///
/// Native: `tokio::time::sleep`. wasm32: a `setTimeout`-backed Promise on the
/// browser event loop. The wasm flavor requires a `window` — inside a Web
/// Worker the promise never resolves (identical to the historical per-module
/// copies this canonicalizes; workers schedule via their own runtime).
#[cfg(not(target_arch = "wasm32"))]
pub async fn sleep_ms(ms: u32) {
    tokio::time::sleep(std::time::Duration::from_millis(ms as u64)).await;
}

#[cfg(target_arch = "wasm32")]
pub async fn sleep_ms(ms: u32) {
    use wasm_bindgen_futures::JsFuture;
    let promise = js_sys::Promise::new(&mut |resolve, _| {
        if let Some(window) = web_sys::window() {
            let _ = window.set_timeout_with_callback_and_timeout_and_arguments_0(
                &resolve,
                ms as i32,
            );
        }
    });
    let _ = JsFuture::from(promise).await;
}