pub struct ModularAgent { /* private fields */ }Expand description
The central orchestrator for the modular agent system.
ModularAgent manages agent lifecycle, connections, and message routing.
It maintains agent instances, connection maps, and handles ModularAgentEvents.
§Lifecycle
init()- Create instance and register agent definitionsready()- Start the internal message loop- Load presets with
open_preset_from_file()oradd_preset() start_preset()- Start agents in a preset- Interact via
write_external_input()andsubscribe() stop_preset()- Stop agentsquit()- Shut down
§Example
use modular_agent_core::{ModularAgent, AgentValue, ModularAgentEvent};
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// Initialize and start
let ma = ModularAgent::init()?;
ma.ready().await?;
// Load a preset
let preset_id = ma.open_preset_from_file("my_preset.json", None).await?;
ma.start_preset(&preset_id).await?;
// Send external input
ma.write_external_input("input".to_string(), AgentValue::string("hello")).await?;
// Cleanup
ma.stop_preset(&preset_id).await?;
ma.quit();
Ok(())
}Implementations§
Source§impl ModularAgent
impl ModularAgent
Sourcepub fn new() -> Self
pub fn new() -> Self
Create a new ModularAgent instance without registering agents.
For most use cases, prefer init() which also registers
all agent definitions from the inventory.
Sourcepub fn init() -> Result<Self, AgentError>
pub fn init() -> Result<Self, AgentError>
Sourcepub async fn ready(&self) -> Result<(), AgentError>
pub async fn ready(&self) -> Result<(), AgentError>
Start the internal message loop.
This must be called after init before loading presets or sending messages.
The message loop handles routing between agents and external output events.
§Example
use modular_agent_core::ModularAgent;
#[tokio::main]
async fn main() {
let ma = ModularAgent::init().unwrap();
ma.ready().await.unwrap(); // Start the message loop
}Sourcepub fn quit(&self)
pub fn quit(&self)
Shut down the ModularAgent.
This stops the internal message loop. Call stop_preset
for each running preset before calling this method for graceful shutdown.
§Example
// Stop all presets first
ma.stop_preset(preset_id).await.unwrap();
// Then quit
ma.quit();Sourcepub fn new_preset(&self) -> Result<String, AgentError>
pub fn new_preset(&self) -> Result<String, AgentError>
Create a new empty preset.
Returns the id of the new preset. The preset is created with default settings and contains no agents or connections initially.
Sourcepub fn new_preset_with_name(&self, name: String) -> Result<String, AgentError>
pub fn new_preset_with_name(&self, name: String) -> Result<String, AgentError>
Create a new empty preset with the given name.
Returns the id of the new preset.
Sourcepub fn get_preset(&self, id: &str) -> Option<Arc<AsyncMutex<Preset>>>
pub fn get_preset(&self, id: &str) -> Option<Arc<AsyncMutex<Preset>>>
Get a preset by id.
Returns None if no preset exists with the given id.
Sourcepub fn add_preset(&self, spec: PresetSpec) -> Result<String, AgentError>
pub fn add_preset(&self, spec: PresetSpec) -> Result<String, AgentError>
Add a new preset with the given spec, and returns the id of the new preset.
The ids of the given spec, including agents and connections, are changed to new unique ids. This allows the same spec to be added multiple times without id conflicts.
Sourcepub fn add_preset_with_name(
&self,
spec: PresetSpec,
name: String,
) -> Result<String, AgentError>
pub fn add_preset_with_name( &self, spec: PresetSpec, name: String, ) -> Result<String, AgentError>
Add a new preset with the given name and spec, and returns the id of the new preset.
The ids of the given spec, including agents and connections, are changed to new unique ids.
Sourcepub async fn rename_preset(
&self,
id: &str,
new_name: String,
) -> Result<(), AgentError>
pub async fn rename_preset( &self, id: &str, new_name: String, ) -> Result<(), AgentError>
Rename a preset by id.
Sourcepub async fn remove_preset(&self, id: &str) -> Result<(), AgentError>
pub async fn remove_preset(&self, id: &str) -> Result<(), AgentError>
Remove a preset by id.
Stops the preset if running, then removes all associated agents and connections.
Sourcepub async fn start_preset(&self, id: &str) -> Result<(), AgentError>
pub async fn start_preset(&self, id: &str) -> Result<(), AgentError>
Start a preset by id.
This starts all agents in the preset, enabling message flow between them.
Each agent’s start() method is called.
Sourcepub async fn stop_preset(&self, id: &str) -> Result<(), AgentError>
pub async fn stop_preset(&self, id: &str) -> Result<(), AgentError>
Stop a preset by id.
This stops all agents in the preset, terminating message processing.
Each agent’s stop() method is called.
Sourcepub async fn open_preset_from_file(
&self,
path: &str,
name: Option<String>,
) -> Result<String, AgentError>
pub async fn open_preset_from_file( &self, path: &str, name: Option<String>, ) -> Result<String, AgentError>
Open a preset from a JSON file.
Reads the file, parses the JSON as a PresetSpec, and adds it to the system.
Optionally provide a custom name for the preset.
§Arguments
path- Path to the JSON preset filename- Optional custom name for the preset
Sourcepub async fn save_preset(&self, id: &str, path: &str) -> Result<(), AgentError>
pub async fn save_preset(&self, id: &str, path: &str) -> Result<(), AgentError>
Save a preset to a JSON file.
Serializes the current preset state (including agent configs) to JSON and writes it to the specified path.
Sourcepub async fn get_preset_spec(&self, id: &str) -> Option<PresetSpec>
pub async fn get_preset_spec(&self, id: &str) -> Option<PresetSpec>
Get the current preset spec by id.
Sourcepub async fn update_preset_spec(
&self,
id: &str,
value: &Value,
) -> Result<(), AgentError>
pub async fn update_preset_spec( &self, id: &str, value: &Value, ) -> Result<(), AgentError>
Update the preset spec
Sourcepub async fn get_preset_info(&self, id: &str) -> Option<PresetInfo>
pub async fn get_preset_info(&self, id: &str) -> Option<PresetInfo>
Get info of the preset by id.
Sourcepub async fn get_preset_infos(&self) -> Vec<PresetInfo>
pub async fn get_preset_infos(&self) -> Vec<PresetInfo>
Get infos of all presets.
Sourcepub fn register_agent_definiton(&self, def: AgentDefinition)
pub fn register_agent_definiton(&self, def: AgentDefinition)
Register an agent definition.
This makes the agent type available for use in presets. The definition includes metadata (title, category), input/output ports, and config specs.
Note: Agents using #[modular_agent] macro are registered automatically via inventory.
Sourcepub fn get_agent_definitions(&self) -> AgentDefinitions
pub fn get_agent_definitions(&self) -> AgentDefinitions
Get all registered agent definitions.
Returns a map of definition name to AgentDefinition.
Sourcepub fn get_agent_definition(&self, def_name: &str) -> Option<AgentDefinition>
pub fn get_agent_definition(&self, def_name: &str) -> Option<AgentDefinition>
Get an agent definition by name.
The name is typically in the format module::path::StructName.
Sourcepub fn get_agent_config_specs(&self, def_name: &str) -> Option<AgentConfigSpecs>
pub fn get_agent_config_specs(&self, def_name: &str) -> Option<AgentConfigSpecs>
Get the config specs of an agent definition by name.
Sourcepub async fn get_agent_spec(&self, agent_id: &str) -> Option<AgentSpec>
pub async fn get_agent_spec(&self, agent_id: &str) -> Option<AgentSpec>
Get the agent spec by id.
Sourcepub async fn update_agent_spec(
&self,
agent_id: &str,
value: &Value,
) -> Result<(), AgentError>
pub async fn update_agent_spec( &self, agent_id: &str, value: &Value, ) -> Result<(), AgentError>
Update the agent spec by id.
Sourcepub fn new_agent_spec(&self, def_name: &str) -> Result<AgentSpec, AgentError>
pub fn new_agent_spec(&self, def_name: &str) -> Result<AgentSpec, AgentError>
Create a new agent spec from the given agent definition name.
Sourcepub async fn add_agent(
&self,
preset_id: String,
spec: AgentSpec,
) -> Result<String, AgentError>
pub async fn add_agent( &self, preset_id: String, spec: AgentSpec, ) -> Result<String, AgentError>
Add an agent to the specified preset.
Creates a new agent instance from the given spec and adds it to the preset.
Returns the id of the newly created agent. The agent is not started automatically;
call start_preset or start_agent to start it.
Sourcepub fn get_agent(
&self,
agent_id: &str,
) -> Option<Arc<AsyncMutex<Box<dyn Agent>>>>
pub fn get_agent( &self, agent_id: &str, ) -> Option<Arc<AsyncMutex<Box<dyn Agent>>>>
Get the agent by id.
Sourcepub async fn add_connection(
&self,
preset_id: &str,
connection: ConnectionSpec,
) -> Result<(), AgentError>
pub async fn add_connection( &self, preset_id: &str, connection: ConnectionSpec, ) -> Result<(), AgentError>
Add a connection between two agents in the specified preset.
When the source agent outputs a value on the source handle (port), it will be delivered to the target agent’s target handle (port).
Sourcepub async fn add_agents_and_connections(
&self,
preset_id: &str,
agents: &Vec<AgentSpec>,
connections: &Vec<ConnectionSpec>,
) -> Result<(Vec<AgentSpec>, Vec<ConnectionSpec>), AgentError>
pub async fn add_agents_and_connections( &self, preset_id: &str, agents: &Vec<AgentSpec>, connections: &Vec<ConnectionSpec>, ) -> Result<(Vec<AgentSpec>, Vec<ConnectionSpec>), AgentError>
Add agents and connections to the specified preset.
The ids of the given agents and connections are changed to new unique ids. The agents are not started automatically, even if the preset is running.
Sourcepub async fn remove_agent(
&self,
preset_id: &str,
agent_id: &str,
) -> Result<(), AgentError>
pub async fn remove_agent( &self, preset_id: &str, agent_id: &str, ) -> Result<(), AgentError>
Remove an agent from the specified preset.
If the agent is running, it will be stopped first.
Sourcepub async fn remove_connection(
&self,
preset_id: &str,
connection: &ConnectionSpec,
) -> Result<(), AgentError>
pub async fn remove_connection( &self, preset_id: &str, connection: &ConnectionSpec, ) -> Result<(), AgentError>
Remove a connection from the specified preset.
Sourcepub async fn start_agent(&self, agent_id: &str) -> Result<(), AgentError>
pub async fn start_agent(&self, agent_id: &str) -> Result<(), AgentError>
Start an agent by id.
Creates a message channel for the agent and spawns its event loop.
The agent’s start() method is called, then
the agent begins processing incoming messages.
If the agent’s definition has native_thread = true, the agent runs
on a dedicated OS thread instead of the tokio runtime.
Sourcepub async fn stop_agent(&self, agent_id: &str) -> Result<(), AgentError>
pub async fn stop_agent(&self, agent_id: &str) -> Result<(), AgentError>
Stop an agent by id.
Sends a stop message to the agent, closes its message channel,
and calls the agent’s stop() method.
Sourcepub async fn set_agent_configs(
&self,
agent_id: String,
configs: AgentConfigs,
) -> Result<(), AgentError>
pub async fn set_agent_configs( &self, agent_id: String, configs: AgentConfigs, ) -> Result<(), AgentError>
Set configs for an agent by id.
Sourcepub fn get_global_configs(&self, def_name: &str) -> Option<AgentConfigs>
pub fn get_global_configs(&self, def_name: &str) -> Option<AgentConfigs>
Get global configs for the agent definition by name.
Sourcepub fn set_global_configs(&self, def_name: String, configs: AgentConfigs)
pub fn set_global_configs(&self, def_name: String, configs: AgentConfigs)
Set global configs for the agent definition by name.
Sourcepub fn get_global_configs_map(&self) -> AgentConfigsMap
pub fn get_global_configs_map(&self) -> AgentConfigsMap
Get the global configs map.
Sourcepub fn set_global_configs_map(&self, new_configs_map: AgentConfigsMap)
pub fn set_global_configs_map(&self, new_configs_map: AgentConfigsMap)
Set the global configs map.
Sourcepub async fn send_agent_out(
&self,
agent_id: String,
ctx: AgentContext,
port: String,
value: AgentValue,
) -> Result<(), AgentError>
pub async fn send_agent_out( &self, agent_id: String, ctx: AgentContext, port: String, value: AgentValue, ) -> Result<(), AgentError>
Send output from an agent. (Async version)
Sourcepub fn try_send_agent_out(
&self,
agent_id: String,
ctx: AgentContext,
port: String,
value: AgentValue,
) -> Result<(), AgentError>
pub fn try_send_agent_out( &self, agent_id: String, ctx: AgentContext, port: String, value: AgentValue, ) -> Result<(), AgentError>
Send output from an agent.
Sourcepub async fn write_external_input(
&self,
name: String,
value: AgentValue,
) -> Result<(), AgentError>
pub async fn write_external_input( &self, name: String, value: AgentValue, ) -> Result<(), AgentError>
Write a value to a named channel.
This is the primary method for sending external input into the agent network.
The value will be delivered to all ExternalInputAgent
instances listening to the specified channel name, which will then forward it to
their connected agents.
§Arguments
name- The channel name to write to. Must match thenameconfig of anExternalInputAgent.value- The value to send.
§Example
// Send a string to the "input" channel
ma.write_external_input("input".to_string(), AgentValue::string("hello")).await.unwrap();
// Send an integer
ma.write_external_input("numbers".to_string(), AgentValue::integer(42)).await.unwrap();Sourcepub async fn write_local_input(
&self,
preset_id: &str,
name: &str,
value: AgentValue,
) -> Result<(), AgentError>
pub async fn write_local_input( &self, preset_id: &str, name: &str, value: AgentValue, ) -> Result<(), AgentError>
Write a value to the local variable channel.
Sourcepub fn subscribe(&self) -> Receiver<ModularAgentEvent>
pub fn subscribe(&self) -> Receiver<ModularAgentEvent>
Subscribe to all ModularAgent events.
Returns a broadcast receiver that receives all ModularAgentEvents.
For filtered subscriptions, use subscribe_to_event.
Note: Subscribe before starting presets to avoid missing events.
Sourcepub fn subscribe_to_event<F, T>(&self, filter_map: F) -> UnboundedReceiver<T>
pub fn subscribe_to_event<F, T>(&self, filter_map: F) -> UnboundedReceiver<T>
Subscribe to filtered ModularAgentEvents.
This method creates a filtered subscription to events. The provided closure filters and maps events, and only successfully mapped events are forwarded to the returned receiver.
Important: Subscribe to events BEFORE starting presets to avoid missing events due to race conditions.
§Arguments
filter_map- A closure that receives each event and returnsSome(T)for events you want to receive, orNoneto skip them.
§Returns
An unbounded receiver that will receive the filtered and mapped events.
§Example
use modular_agent_core::{ModularAgent, ModularAgentEvent, AgentValue};
// Subscribe to a specific channel's output
let output_channel = "output".to_string();
let mut output_rx = ma.subscribe_to_event(move |event| {
if let ModularAgentEvent::ExternalOutput(name, value) = event {
if name == output_channel {
return Some(value);
}
}
None
});
// Now start the preset and receive events
while let Some(value) = output_rx.recv().await {
println!("Received: {:?}", value);
}Trait Implementations§
Source§impl Clone for ModularAgent
impl Clone for ModularAgent
Source§fn clone(&self) -> ModularAgent
fn clone(&self) -> ModularAgent
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for ModularAgent
impl RefUnwindSafe for ModularAgent
impl Send for ModularAgent
impl Sync for ModularAgent
impl Unpin for ModularAgent
impl UnsafeUnpin for ModularAgent
impl UnwindSafe for ModularAgent
Blanket Implementations§
Source§impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
impl<S, D, Swp, Dwp, T> AdaptInto<D, Swp, Dwp, T> for S
Source§fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<Swp, Dwp, T>,
fn adapt_into_using<M>(self, method: M) -> Dwhere
M: TransformMatrix<Swp, Dwp, T>,
Source§fn adapt_into(self) -> D
fn adapt_into(self) -> D
Source§impl<Src, Scheme> ApproxFrom<Src, Scheme> for Srcwhere
Scheme: ApproxScheme,
impl<Src, Scheme> ApproxFrom<Src, Scheme> for Srcwhere
Scheme: ApproxScheme,
Source§fn approx_from(src: Src) -> Result<Src, <Src as ApproxFrom<Src, Scheme>>::Err>
fn approx_from(src: Src) -> Result<Src, <Src as ApproxFrom<Src, Scheme>>::Err>
Source§impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Srcwhere
Dst: ApproxFrom<Src, Scheme>,
Scheme: ApproxScheme,
impl<Dst, Src, Scheme> ApproxInto<Dst, Scheme> for Srcwhere
Dst: ApproxFrom<Src, Scheme>,
Scheme: ApproxScheme,
Source§type Err = <Dst as ApproxFrom<Src, Scheme>>::Err
type Err = <Dst as ApproxFrom<Src, Scheme>>::Err
Source§fn approx_into(self) -> Result<Dst, <Src as ApproxInto<Dst, Scheme>>::Err>
fn approx_into(self) -> Result<Dst, <Src as ApproxInto<Dst, Scheme>>::Err>
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T, Dst> ConvAsUtil<Dst> for T
impl<T, Dst> ConvAsUtil<Dst> for T
Source§impl<T> ConvUtil for T
impl<T> ConvUtil for T
Source§fn approx_as<Dst>(self) -> Result<Dst, Self::Err>where
Self: Sized + ApproxInto<Dst>,
fn approx_as<Dst>(self) -> Result<Dst, Self::Err>where
Self: Sized + ApproxInto<Dst>,
Source§fn approx_as_by<Dst, Scheme>(self) -> Result<Dst, Self::Err>
fn approx_as_by<Dst, Scheme>(self) -> Result<Dst, Self::Err>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
impl<T, U> IntoColor<U> for Twhere
U: FromColor<T>,
Source§fn into_color(self) -> U
fn into_color(self) -> U
Source§impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
impl<T, U> IntoColorUnclamped<U> for Twhere
U: FromColorUnclamped<T>,
Source§fn into_color_unclamped(self) -> U
fn into_color_unclamped(self) -> U
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.Source§impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
impl<T, U> TryIntoColor<U> for Twhere
U: TryFromColor<T>,
Source§fn try_into_color(self) -> Result<U, OutOfBounds<U>>
fn try_into_color(self) -> Result<U, OutOfBounds<U>>
OutOfBounds error is returned which contains
the unclamped color. Read more