car-ffi-common 0.14.0

Shared logic for FFI bindings (NAPI, PyO3) — JSON wrappers for verify, multi-agent, scheduler
Documentation
//! JSON wrappers for car-multi pattern runners.
//!
//! Each function takes JSON strings for specs, an AgentRunner, and returns result JSON.
//! The caller provides the AgentRunner impl (NAPI or PyO3 specific).

use car_multi::{AgentRunner, AgentSpec, SharedInfra, SwarmMode};
use std::sync::Arc;

/// Run a Swarm pattern from JSON inputs.
pub async fn run_swarm(
    mode: &str,
    agents_json: &str,
    task: &str,
    synthesizer_json: Option<&str>,
    runner: Arc<dyn AgentRunner>,
) -> Result<String, String> {
    let agent_specs: Vec<AgentSpec> =
        serde_json::from_str(agents_json).map_err(|e| format!("invalid agents JSON: {}", e))?;
    let swarm_mode: SwarmMode = serde_json::from_str(&format!("\"{}\"", mode))
        .map_err(|e| format!("invalid mode '{}': {}", mode, e))?;
    let synth: Option<AgentSpec> = synthesizer_json
        .map(|s| serde_json::from_str(s))
        .transpose()
        .map_err(|e| format!("invalid synthesizer JSON: {}", e))?;

    let infra = SharedInfra::new();
    let mut swarm = car_multi::Swarm::new(agent_specs, swarm_mode);
    if let Some(s) = synth {
        swarm = swarm.with_synthesizer(s);
    }

    let result = swarm
        .run(task, &runner, &infra)
        .await
        .map_err(|e| format!("swarm error: {}", e))?;
    serde_json::to_string(&result).map_err(|e| e.to_string())
}

/// Run a Pipeline pattern from JSON inputs.
pub async fn run_pipeline(
    stages_json: &str,
    task: &str,
    runner: Arc<dyn AgentRunner>,
) -> Result<String, String> {
    let stage_specs: Vec<AgentSpec> =
        serde_json::from_str(stages_json).map_err(|e| format!("invalid stages JSON: {}", e))?;

    let infra = SharedInfra::new();
    let result = car_multi::Pipeline::new(stage_specs)
        .run(task, &runner, &infra)
        .await
        .map_err(|e| format!("pipeline error: {}", e))?;
    serde_json::to_string(&result).map_err(|e| e.to_string())
}

/// Run a Supervisor pattern from JSON inputs.
pub async fn run_supervisor(
    workers_json: &str,
    supervisor_json: &str,
    task: &str,
    max_rounds: u32,
    runner: Arc<dyn AgentRunner>,
) -> Result<String, String> {
    let worker_specs: Vec<AgentSpec> =
        serde_json::from_str(workers_json).map_err(|e| format!("invalid workers JSON: {}", e))?;
    let supervisor_spec: AgentSpec = serde_json::from_str(supervisor_json)
        .map_err(|e| format!("invalid supervisor JSON: {}", e))?;

    let infra = SharedInfra::new();
    let result = car_multi::Supervisor::new(worker_specs, supervisor_spec)
        .with_max_rounds(max_rounds)
        .run(task, &runner, &infra)
        .await
        .map_err(|e| format!("supervisor error: {}", e))?;
    serde_json::to_string(&result).map_err(|e| e.to_string())
}

/// Run a MapReduce pattern from JSON inputs.
pub async fn run_map_reduce(
    mapper_json: &str,
    reducer_json: &str,
    task: &str,
    items_json: &str,
    runner: Arc<dyn AgentRunner>,
) -> Result<String, String> {
    let mapper_spec: AgentSpec =
        serde_json::from_str(mapper_json).map_err(|e| format!("invalid mapper JSON: {}", e))?;
    let reducer_spec: AgentSpec =
        serde_json::from_str(reducer_json).map_err(|e| format!("invalid reducer JSON: {}", e))?;
    let item_list: Vec<String> =
        serde_json::from_str(items_json).map_err(|e| format!("invalid items JSON: {}", e))?;

    let infra = SharedInfra::new();
    let result = car_multi::MapReduce::new(mapper_spec, reducer_spec)
        .run(task, &item_list, &runner, &infra)
        .await
        .map_err(|e| format!("map_reduce error: {}", e))?;
    serde_json::to_string(&result).map_err(|e| e.to_string())
}

/// Run a Vote pattern from JSON inputs.
pub async fn run_vote(
    agents_json: &str,
    task: &str,
    synthesizer_json: Option<&str>,
    runner: Arc<dyn AgentRunner>,
) -> Result<String, String> {
    let agent_specs: Vec<AgentSpec> =
        serde_json::from_str(agents_json).map_err(|e| format!("invalid agents JSON: {}", e))?;
    let synth: Option<AgentSpec> = synthesizer_json
        .map(|s| serde_json::from_str(s))
        .transpose()
        .map_err(|e| format!("invalid synthesizer JSON: {}", e))?;

    let infra = SharedInfra::new();
    let mut vote = car_multi::Vote::new(agent_specs);
    if let Some(s) = synth {
        vote = vote.with_synthesizer(s);
    }

    let result = vote
        .run(task, &runner, &infra)
        .await
        .map_err(|e| format!("vote error: {}", e))?;
    serde_json::to_string(&result).map_err(|e| e.to_string())
}