Skip to main content

Crate funera_orchestrate

Crate funera_orchestrate 

Source
Expand description

§funera-orchestrate

Easy-to-use orchestration layer for [funera-core].

This crate provides a high-level agent API (Agent) and a runtime container (AgentRuntime) that together let you integrate funera’s LLM agent runtime into your own projects with minimal boilerplate.

§Features

FeatureDefaultDescription
deepseekDeepSeek provider
openaiOpenAI provider
toolTool system (trait, registry, executor)
funera-builtin-toolsBuilt-in tools (Read, Write, Edit, Shell)
securityTool policy enforcement
middlewareEvent interception pipeline (Inspector + Mutator)
skillSkill loading and prompt injection
sandboxKernel-level subprocess isolation

§Quick Start

use funera_orchestrate::{Agent, AgentRuntime, DeepSeekProvider};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let runtime = AgentRuntime::<DeepSeekProvider>::builder()
        .api_key(std::env::var("DEEPSEEK_API_KEY")?)
        .model("deepseek-v4-flash")
        .build()?;

    let agent = Agent::builder()
        .system_prompt("You are a helpful assistant.")
        .build();

    let resp = agent.fire("Hello!", &runtime).await?;
    println!("{}", resp.content);
    Ok(())
}

§Core Concepts

ConceptTypeDescription
RuntimeAgentRuntimeShared infrastructure + conversation session
AgentAgentBehavioural config (system prompt, callbacks)
One-shotAgent::fireTemporary session, discarded after call
Multi-turnAgent::sendPersistent session across calls
Streamingfire_stream / send_streamToken-by-token streaming
Approval[ApprovalHandle]Lightweight cloneable handle for tool-call approval

§Examples

§One-shot query with stream

let runtime = AgentRuntime::<DeepSeekProvider>::builder()
    .api_key(std::env::var("DEEPSEEK_API_KEY")?)
    .model("deepseek-v4-flash")
    .build()?;

let agent = Agent::builder()
    .on_token(|t| print!("{t}"))
    .build();

let mut rx = agent.fire_stream("Explain Rust's ownership model", &runtime).await?;
while let Some(event) = rx.recv().await {
    if let AgentEvent::Text(t) = event {
        print!("{t}");
    }
}

§Multi-turn conversation with callbacks

let runtime = AgentRuntime::<DeepSeekProvider>::builder()
    .api_key(std::env::var("DEEPSEEK_API_KEY")?)
    .model("deepseek-v4-flash")
    .build()?;

let agent = Agent::builder()
    .system_prompt("You are helpful.")
    .on_tool_call(|name, _| eprintln!("[tool] {name}"))
    .on_turn_start(|| eprintln!("--- turn ---"))
    .build();

let handle = agent.send("Hi, I'm Alice.", runtime).await?;
let (runtime, _resp) = handle.await?;
let handle = agent.send("What's my name?", runtime).await?;
let (_runtime, _resp) = handle.await?;

§Switching models on the same provider

let fast = AgentRuntime::<DeepSeekProvider>::builder()
    .api_key(std::env::var("DEEPSEEK_API_KEY")?)
    .model("deepseek-v4-flash")
    .build()?;

let powerful = AgentRuntime::<DeepSeekProvider>::builder()
    .api_key(std::env::var("DEEPSEEK_API_KEY")?)
    .model("deepseek-r1")
    .build()?;

let agent = Agent::builder().build();

let (fast, _) = agent.send("Hello", fast).await?.await?;              // fast model
agent.fire("What is Rust?", &powerful).await?;                        // powerful model (temp)
let (_fast, _) = agent.send("Tell me more", fast).await?.await?;       // back to fast

§Security with tool-call approval

Requires the security feature (and optionally funera-builtin-tools, sandbox). Use [ApprovalHandle] to approve or reject tool calls from a spawned task while the agent is running — works with fire(), send(), and send_stream().

let (approval_tx, mut approval_rx) = tokio::sync::mpsc::unbounded_channel();

let runtime = AgentRuntime::<DeepSeekProvider>::builder()
    .api_key(std::env::var("DEEPSEEK_API_KEY")?)
    .model("deepseek-v4-flash")
    .on_approval_required(move |call_id, tool, reason| {
        eprintln!("[{tool}] needs approval: {reason}");
        let _ = approval_tx.send(call_id.to_string());
    })
    .with_approval_timeout(Duration::from_secs(30))
    .build()?;

// Clone the ApprovalHandle *before* send() consumes the runtime.
let approver: ApprovalHandle = runtime.approval_handle();
tokio::spawn(async move {
    while let Some(call_id) = approval_rx.recv().await {
        approver.approve_tool_call(&call_id, true).await.ok();
    }
});

let agent = Agent::builder().build();
let (_runtime, resp) = agent.send("do something", runtime).await?.await?;
println!("{}", resp.content);

§Module Structure

Re-exports§

pub use agent::Agent;
pub use agent::AgentBuilder;
pub use dispatcher::CallbackRegistry;
pub use error::OrchestrateError;
pub use event::AgentEvent;
pub use event::RawAgentEvent;
pub use response::ChatResponse;
pub use response::ToolCallInfo;
pub use runtime::Acquired;
pub use runtime::AgentRuntime;
pub use runtime::AgentRuntimeBuilder;
pub use runtime::Idle;
pub use send_handle::FireStreamHandle;
pub use send_handle::SendHandle;
pub use send_handle::SendStreamHandle;

Modules§

agent
dispatcher
error
event
response
runtime
send_handle

Structs§

DeepSeekProvider
ToolCallErrorInfo
ToolCallRequest
ToolCallResponse

Enums§

EnvStateEvent
ReactEvent
TokenEvent