Skip to main content

AgentCapabilities & AgentRequirements

The capability system enables agent discovery, matching, and routing based on required features and tags. It consists of two main types:
  • AgentCapabilities - Describes what an agent can do
  • AgentRequirements - Describes what is needed for a task
Location: mofa-kernel/src/agent/capabilities.rs

AgentCapabilities

Type Definition

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AgentCapabilities {
    pub tags: HashSet<String>,
    pub input_types: HashSet<InputType>,
    pub output_types: HashSet<OutputType>,
    pub max_context_length: Option<usize>,
    pub reasoning_strategies: Vec<ReasoningStrategy>,
    pub supports_streaming: bool,
    pub supports_conversation: bool,
    pub supports_tools: bool,
    pub supports_coordination: bool,
    pub custom: HashMap<String, serde_json::Value>,
}

Fields

tags
HashSet<String>
default:"{}"
Capability tags like "llm", "coding", "research" for discovery and matching
input_types
HashSet<InputType>
default:"{}"
Supported input types (Text, Image, Audio, Video, Structured, Binary)
output_types
HashSet<OutputType>
default:"{}"
Supported output types (Text, Json, Stream, Binary, Multimodal)
max_context_length
Option<usize>
Maximum context length for LLM-based agents (in tokens)
reasoning_strategies
Vec<ReasoningStrategy>
default:"[]"
Supported reasoning strategies (Direct, ReAct, ChainOfThought, etc.)
supports_streaming
bool
default:"false"
Whether streaming output is supported
supports_conversation
bool
default:"false"
Whether multi-turn conversation is supported
supports_tools
bool
default:"false"
Whether tool calling is supported
supports_coordination
bool
default:"false"
Whether multi-agent coordination is supported
custom
HashMap<String, serde_json::Value>
default:"{}"
Custom capability flags for domain-specific features

Constructor Methods

impl AgentCapabilities {
    pub fn new() -> Self;
    pub fn builder() -> AgentCapabilitiesBuilder;
}

Query Methods

has_tag
fn(&self, tag: &str) -> bool
Checks if a specific tag is present
if caps.has_tag("llm") {
    println!("This is an LLM agent");
}
supports_input
fn(&self, input_type: &InputType) -> bool
Checks if a specific input type is supported
if caps.supports_input(&InputType::Image) {
    println!("Agent can process images");
}
supports_output
fn(&self, output_type: &OutputType) -> bool
Checks if a specific output type is supported
matches
fn(&self, requirements: &AgentRequirements) -> bool
Checks if capabilities match the given requirements
if caps.matches(&requirements) {
    println!("Agent meets requirements");
}
match_score
fn(&self, requirements: &AgentRequirements) -> f64
Calculates match score (0.0 - 1.0+) for ranking agents
let score = caps.match_score(&requirements);
println!("Match score: {:.2}", score);

AgentCapabilitiesBuilder

Builder Methods

new
fn() -> Self
Creates a new builder
tag
fn(self, tag: impl Into<String>) -> Self
Adds a capability tag
let builder = AgentCapabilitiesBuilder::new()
    .tag("llm")
    .tag("coding");
tags
fn(self, tags: impl IntoIterator<Item = impl Into<String>>) -> Self
Adds multiple tags at once
let builder = AgentCapabilitiesBuilder::new()
    .tags(vec!["llm", "research", "analysis"]);
input_type
fn(self, input_type: InputType) -> Self
Adds a supported input type
output_type
fn(self, output_type: OutputType) -> Self
Adds a supported output type
max_context_length
fn(self, length: usize) -> Self
Sets maximum context length
reasoning_strategy
fn(self, strategy: ReasoningStrategy) -> Self
Adds a supported reasoning strategy
supports_streaming
fn(self, supports: bool) -> Self
Sets streaming support flag
supports_conversation
fn(self, supports: bool) -> Self
Sets conversation support flag
supports_tools
fn(self, supports: bool) -> Self
Sets tool support flag
supports_coordination
fn(self, supports: bool) -> Self
Sets coordination support flag
custom
fn(self, key: impl Into<String>, value: serde_json::Value) -> Self
Adds a custom capability
build
fn(self) -> AgentCapabilities
Builds the capabilities object

Example Usage

use mofa_sdk::kernel::{AgentCapabilities, InputType, OutputType, ReasoningStrategy};

let caps = AgentCapabilities::builder()
    .tag("llm")
    .tag("coding")
    .tag("assistant")
    .input_type(InputType::Text)
    .output_type(OutputType::Text)
    .output_type(OutputType::Json)
    .max_context_length(128000)
    .reasoning_strategy(ReasoningStrategy::ReAct { max_iterations: 10 })
    .supports_streaming(true)
    .supports_conversation(true)
    .supports_tools(true)
    .custom("model", json!("gpt-4o"))
    .build();

AgentRequirements

Type Definition

#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AgentRequirements {
    pub required_tags: HashSet<String>,
    pub preferred_tags: HashSet<String>,
    pub input_types: HashSet<InputType>,
    pub output_types: HashSet<OutputType>,
    pub requires_streaming: bool,
    pub requires_tools: bool,
    pub requires_conversation: bool,
    pub requires_coordination: bool,
}

Fields

required_tags
HashSet<String>
default:"{}"
Tags that the agent MUST have (hard requirement)
preferred_tags
HashSet<String>
default:"{}"
Tags that are nice to have (used for ranking)
input_types
HashSet<InputType>
default:"{}"
Required input types the agent must support
output_types
HashSet<OutputType>
default:"{}"
Required output types the agent must support
requires_streaming
bool
default:"false"
Whether streaming output is required
requires_tools
bool
default:"false"
Whether tool support is required
requires_conversation
bool
default:"false"
Whether multi-turn conversation is required
requires_coordination
bool
default:"false"
Whether multi-agent coordination is required

Constructor Methods

impl AgentRequirements {
    pub fn new() -> Self;
    pub fn builder() -> AgentRequirementsBuilder;
}

Query Methods

matches
fn(&self, capabilities: &AgentCapabilities) -> bool
Checks if given capabilities meet these requirements
score
fn(&self, capabilities: &AgentCapabilities) -> f32
Calculates match score for ranking

AgentRequirementsBuilder

Builder Methods

new
fn() -> Self
Creates a new builder
require_tag
fn(self, tag: impl Into<String>) -> Self
Adds a required tag (hard requirement)
prefer_tag
fn(self, tag: impl Into<String>) -> Self
Adds a preferred tag (for ranking)
require_input
fn(self, input_type: InputType) -> Self
Requires a specific input type
require_output
fn(self, output_type: OutputType) -> Self
Requires a specific output type
require_streaming
fn(self) -> Self
Requires streaming support
require_tools
fn(self) -> Self
Requires tool support
require_conversation
fn(self) -> Self
Requires conversation support
require_coordination
fn(self) -> Self
Requires coordination support
build
fn(self) -> AgentRequirements
Builds the requirements object

Example Usage

use mofa_sdk::kernel::{AgentRequirements, InputType, OutputType};

let requirements = AgentRequirements::builder()
    .require_tag("llm")           // Must have
    .prefer_tag("coding")         // Nice to have
    .prefer_tag("research")
    .require_input(InputType::Text)
    .require_output(OutputType::Text)
    .require_tools()
    .require_streaming()
    .build();

ReasoningStrategy

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
#[non_exhaustive]
pub enum ReasoningStrategy {
    #[default]
    Direct,
    ReAct { max_iterations: usize },
    ChainOfThought,
    TreeOfThought { branching_factor: usize },
    Custom(String),
}

Variants

Direct
()
default:true
Direct LLM reasoning without structured approach
ReAct
{ max_iterations: usize }
ReAct-style Thought-Action-Observation loop
ReasoningStrategy::ReAct { max_iterations: 10 }
ChainOfThought
()
Chain of Thought reasoning (step-by-step)
TreeOfThought
{ branching_factor: usize }
Tree of Thought exploration with branching
ReasoningStrategy::TreeOfThought { branching_factor: 3 }
Custom
String
Custom reasoning mode
ReasoningStrategy::Custom("hybrid-reasoning".to_string())

InputType & OutputType

InputType

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum InputType {
    Text,
    Image,
    Audio,
    Video,
    Structured(String),
    Binary,
}

OutputType

#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[non_exhaustive]
pub enum OutputType {
    Text,
    Json,
    StructuredJson,
    Stream,
    Binary,
    Multimodal,
}

Complete Example

Defining Agent Capabilities

use mofa_sdk::kernel::{
    AgentCapabilities, InputType, OutputType, ReasoningStrategy
};
use serde_json::json;

// LLM coding assistant
let coding_agent_caps = AgentCapabilities::builder()
    .tags(vec!["llm", "coding", "rust"])
    .input_type(InputType::Text)
    .output_type(OutputType::Text)
    .output_type(OutputType::Json)
    .max_context_length(128000)
    .reasoning_strategy(ReasoningStrategy::ChainOfThought)
    .supports_streaming(true)
    .supports_conversation(true)
    .supports_tools(true)
    .custom("programming_languages", json!(["rust", "python", "go"]))
    .build();

// Research assistant
let research_agent_caps = AgentCapabilities::builder()
    .tags(vec!["llm", "research", "web-search"])
    .input_type(InputType::Text)
    .output_type(OutputType::Text)
    .reasoning_strategy(ReasoningStrategy::ReAct { max_iterations: 15 })
    .supports_tools(true)
    .supports_conversation(true)
    .custom("search_engines", json!(["google", "bing"]))
    .build();

Matching Agents to Requirements

use mofa_sdk::kernel::{AgentRequirements, InputType};

let requirements = AgentRequirements::builder()
    .require_tag("llm")
    .require_tag("coding")
    .prefer_tag("rust")
    .require_input(InputType::Text)
    .require_tools()
    .build();

// Check if agent matches
if coding_agent_caps.matches(&requirements) {
    let score = coding_agent_caps.match_score(&requirements);
    println!("Coding agent matches! Score: {:.2}", score);
}

if research_agent_caps.matches(&requirements) {
    let score = research_agent_caps.match_score(&requirements);
    println!("Research agent matches! Score: {:.2}", score);
} else {
    println!("Research agent doesn't match requirements");
}

Agent Registry with Capability Matching

use mofa_sdk::kernel::{AgentCapabilities, AgentRequirements};
use std::collections::HashMap;

struct AgentRegistry {
    agents: HashMap<String, AgentCapabilities>,
}

impl AgentRegistry {
    fn find_best_match(&self, requirements: &AgentRequirements) -> Option<String> {
        self.agents
            .iter()
            .filter(|(_, caps)| caps.matches(requirements))
            .max_by(|(_, caps_a), (_, caps_b)| {
                caps_a.match_score(requirements)
                    .partial_cmp(&caps_b.match_score(requirements))
                    .unwrap()
            })
            .map(|(id, _)| id.clone())
    }
}

// Usage
let mut registry = AgentRegistry { agents: HashMap::new() };
registry.agents.insert("coding-agent".to_string(), coding_agent_caps);
registry.agents.insert("research-agent".to_string(), research_agent_caps);

if let Some(agent_id) = registry.find_best_match(&requirements) {
    println!("Best match: {}", agent_id);
}

See Also

Build docs developers (and LLMs) love