Skip to main content
The AgentBuilder provides a fluent API for constructing agents with plugins, capabilities, and runtime configuration.

Overview

AgentBuilder simplifies agent creation by providing:
  • Fluent builder pattern
  • Plugin registration
  • Input/output port configuration
  • Concurrency and timeout settings
  • Integration with both Dora and SimpleRuntime

Creating an Agent

use mofa_runtime::AgentBuilder;

let runtime = AgentBuilder::new("agent-1", "My Agent")
    .with_capability("chat")
    .with_capability("summarization")
    .with_plugin(Box::new(llm_plugin))
    .with_max_concurrent_tasks(20)
    .with_timeout(Duration::from_secs(60))
    .with_agent(my_agent)
    .await?;

Constructor

new

Create a new AgentBuilder.
agent_id
&str
Unique identifier for the agent
name
&str
Human-readable agent name
let builder = AgentBuilder::new("assistant-1", "AI Assistant");

Configuration Methods

with_capability

Add a single capability tag.
capability
&str
Capability identifier (e.g., “chat”, “vision”, “code”)
let builder = builder
    .with_capability("chat")
    .with_capability("vision")
    .with_capability("tool_use");

with_capabilities

Add multiple capabilities at once.
capabilities
Vec<&str>
List of capability identifiers
let builder = builder.with_capabilities(vec![
    "chat",
    "summarization",
    "translation",
]);

with_dependency

Add a dependency on another agent.
dependency
&str
Agent ID that this agent depends on
let builder = builder
    .with_dependency("storage-agent")
    .with_dependency("tool-registry");

with_plugin

Register a plugin with the agent.
plugin
Box<dyn AgentPlugin>
Plugin implementation
let builder = builder
    .with_plugin(Box::new(llm_plugin))
    .with_plugin(Box::new(storage_plugin))
    .with_plugin(Box::new(tool_plugin));

I/O Configuration

with_input

Add an input port (Dora mode only).
input
&str
Input port name
let builder = builder
    .with_input("user_messages")
    .with_input("system_events");

with_output

Add an output port (Dora mode only).
output
&str
Output port name
let builder = builder
    .with_output("responses")
    .with_output("logs");

Runtime Configuration

with_max_concurrent_tasks

Set maximum concurrent task limit.
max
usize
Maximum number of concurrent tasks (default: 10)
let builder = builder.with_max_concurrent_tasks(50);

with_timeout

Set default execution timeout.
timeout
Duration
Timeout duration (default: 30 seconds)
let builder = builder.with_timeout(Duration::from_secs(120));

with_config

Add custom configuration key-value pair.
key
&str
Configuration key
value
&str
Configuration value
let builder = builder
    .with_config("log_level", "debug")
    .with_config("enable_metrics", "true");

Build Methods

build_config

Build the agent configuration.
let config = builder.build_config();
println!("Agent ID: {}", config.agent_id);
println!("Name: {}", config.name);

build_metadata

Build the agent metadata.
let metadata = builder.build_metadata();
println!("Capabilities: {:?}", metadata.capabilities);
println!("State: {:?}", metadata.state);

with_agent

Provide the MoFAAgent implementation and build runtime.
agent
A: MoFAAgent
The agent implementation
// Non-Dora mode: Returns SimpleAgentRuntime
let runtime = builder.with_agent(my_agent).await?;

// Dora mode: Returns AgentRuntime
let runtime = builder.with_agent(my_agent).await?;

build_and_start

Build and immediately start the agent runtime.
agent
A: MoFAAgent
The agent implementation
let runtime = builder.build_and_start(my_agent).await?;
// Agent is now running and ready to process events

Complete Example

use mofa_runtime::AgentBuilder;
use mofa_foundation::llm::{LLMPlugin, OpenAIProvider, OpenAIConfig};
use mofa_plugins::tool::ToolPluginAdapter;
use std::sync::Arc;
use std::time::Duration;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    // 1. Create plugins
    let llm_config = OpenAIConfig::new("sk-...")
        .with_model("gpt-4");
    let llm_provider = Arc::new(OpenAIProvider::new(llm_config));
    let llm_plugin = LLMPlugin::new("openai", llm_provider);

    let calculator = Arc::new(CalculatorTool::new());
    let tool_plugin = ToolPluginAdapter::new(calculator);

    // 2. Create agent implementation
    let agent = MyAgent::new();

    // 3. Build and start runtime
    let runtime = AgentBuilder::new("assistant", "AI Assistant")
        // Capabilities
        .with_capabilities(vec![
            "chat",
            "tool_use",
            "reasoning",
        ])
        // Dependencies
        .with_dependency("storage-service")
        // Plugins
        .with_plugin(Box::new(llm_plugin))
        .with_plugin(Box::new(tool_plugin))
        // I/O ports (Dora mode)
        .with_input("user_input")
        .with_output("agent_output")
        // Runtime config
        .with_max_concurrent_tasks(30)
        .with_timeout(Duration::from_secs(90))
        .with_config("log_level", "info")
        .with_config("enable_tracing", "true")
        // Build and start
        .build_and_start(agent)
        .await?;

    println!("Agent {} started", runtime.metadata().id);

    // 4. Inject events (Simple mode)
    #[cfg(not(feature = "dora"))]
    {
        let event = AgentEvent::TaskReceived(TaskRequest {
            task_id: "task-1".to_string(),
            content: "Hello!".to_string(),
        });
        runtime.inject_event(event).await?;
    }

    // 5. Send messages (Dora mode)
    #[cfg(feature = "dora")]
    {
        let message = AgentMessage::TaskRequest {
            task_id: "task-1".to_string(),
            content: "Analyze this data".to_string(),
        };
        runtime.send_output("agent_output", &message).await?;
    }

    Ok(())
}

Agent Configuration

The builder produces an AgentConfig:
pub struct AgentConfig {
    pub agent_id: String,
    pub name: String,
    pub node_config: HashMap<String, String>,
}

Agent Metadata

The builder produces AgentMetadata:
pub struct AgentMetadata {
    pub id: String,
    pub name: String,
    pub description: Option<String>,
    pub version: Option<String>,
    pub capabilities: AgentCapabilities,
    pub state: AgentState,
}

Dora Node Configuration

In Dora mode, the builder creates a DoraNodeConfig:
pub struct DoraNodeConfig {
    pub node_id: String,
    pub name: String,
    pub inputs: Vec<String>,
    pub outputs: Vec<String>,
    pub event_buffer_size: usize,
    pub default_timeout: Duration,
    pub custom_config: HashMap<String, String>,
}

Runtime Types

Non-Dora Mode

Returns SimpleAgentRuntime<A>:
let runtime: SimpleAgentRuntime<MyAgent> = builder
    .with_agent(my_agent)
    .await?;

Dora Mode

Returns AgentRuntime<A>:
let runtime: AgentRuntime<MyAgent> = builder
    .with_agent(my_agent)
    .await?;

Builder Pattern Example

impl MyApp {
    async fn create_agent(&self) -> Result<SimpleAgentRuntime<MyAgent>> {
        let builder = AgentBuilder::new(&self.agent_id, &self.agent_name);
        
        let builder = if self.enable_llm {
            builder.with_plugin(Box::new(self.create_llm_plugin()?))
        } else {
            builder
        };
        
        let builder = if self.enable_tools {
            builder
                .with_plugin(Box::new(self.create_tool_plugin()?))
                .with_capability("tool_use")
        } else {
            builder
        };
        
        builder
            .with_max_concurrent_tasks(self.max_tasks)
            .with_timeout(self.timeout)
            .build_and_start(self.create_agent_impl())
            .await
    }
}

Build docs developers (and LLMs) love