Skip to main content

modular_agent_core/
output.rs

1use crate::agent::Agent;
2use crate::context::AgentContext;
3use crate::error::AgentError;
4use crate::value::AgentValue;
5use std::future::Future;
6use std::pin::Pin;
7
8/// Trait for sending output values and emitting events from agents.
9///
10/// This trait is automatically implemented for all types that implement `Agent`.
11/// It provides methods for sending values to output ports and notifying the
12/// orchestrator about configuration changes and errors.
13pub trait AgentOutput {
14    /// Sends a value to an output port asynchronously (raw version with String port).
15    ///
16    /// This is the low-level method; prefer using `output()` which accepts
17    /// any type that can be converted to String.
18    fn output_raw(
19        &self,
20        ctx: AgentContext,
21        port: String,
22        value: AgentValue,
23    ) -> Pin<Box<dyn Future<Output = Result<(), AgentError>> + Send + '_>>;
24
25    /// Sends a value to an output port asynchronously.
26    ///
27    /// This method waits until the value is accepted by the channel.
28    /// Use `try_output` if you want non-blocking behavior.
29    fn output<S: Into<String>>(
30        &self,
31        ctx: AgentContext,
32        port: S,
33        value: AgentValue,
34    ) -> Pin<Box<dyn Future<Output = Result<(), AgentError>> + Send + '_>> {
35        self.output_raw(ctx, port.into(), value)
36    }
37
38    /// Tries to send a value to an output port without blocking (raw version).
39    ///
40    /// Returns immediately, even if the channel is full.
41    fn try_output_raw(
42        &self,
43        ctx: AgentContext,
44        port: String,
45        value: AgentValue,
46    ) -> Result<(), AgentError>;
47
48    /// Tries to send a value to an output port without blocking.
49    fn try_output<S: Into<String>>(
50        &self,
51        ctx: AgentContext,
52        port: S,
53        value: AgentValue,
54    ) -> Result<(), AgentError> {
55        self.try_output_raw(ctx, port.into(), value)
56    }
57
58    /// Emits a configuration update event (raw version with String key).
59    fn emit_config_updated_raw(&self, key: String, value: AgentValue);
60
61    /// Emits a configuration update event.
62    ///
63    /// Notifies the orchestrator that a configuration value has changed,
64    /// typically used when an agent updates its own configuration.
65    fn emit_config_updated<S: Into<String>>(&self, key: S, value: AgentValue) {
66        self.emit_config_updated_raw(key.into(), value);
67    }
68
69    /// Emits an agent spec update event (raw version).
70    fn emit_agent_spec_updated_raw(&self);
71
72    /// Emits an agent spec update event.
73    ///
74    /// Notifies the orchestrator that the agent's specification has changed
75    /// (e.g., ports were added or removed dynamically).
76    fn emit_agent_spec_updated(&self) {
77        self.emit_agent_spec_updated_raw();
78    }
79
80    /// Emits an error event (raw version with String message).
81    fn emit_error_raw(&self, message: String);
82
83    /// Emits an error event.
84    ///
85    /// Notifies the orchestrator that an error occurred in this agent.
86    #[allow(unused)]
87    fn emit_error<S: Into<String>>(&self, message: S) {
88        self.emit_error_raw(message.into());
89    }
90}
91
92impl<T: Agent> AgentOutput for T {
93    fn output_raw(
94        &self,
95        ctx: AgentContext,
96        port: String,
97        value: AgentValue,
98    ) -> Pin<Box<dyn Future<Output = Result<(), AgentError>> + Send + '_>> {
99        Box::pin(async move {
100            self.ma()
101                .send_agent_out(self.id().into(), ctx, port, value)
102                .await
103        })
104    }
105
106    fn try_output_raw(
107        &self,
108        ctx: AgentContext,
109        port: String,
110        value: AgentValue,
111    ) -> Result<(), AgentError> {
112        self.ma()
113            .try_send_agent_out(self.id().into(), ctx, port, value)
114    }
115
116    fn emit_config_updated_raw(&self, key: String, value: AgentValue) {
117        self.ma()
118            .emit_agent_config_updated(self.id().to_string(), key, value);
119    }
120
121    fn emit_agent_spec_updated_raw(&self) {
122        self.ma().emit_agent_spec_updated(self.id().to_string());
123    }
124
125    fn emit_error_raw(&self, message: String) {
126        self.ma()
127            .emit_agent_error(self.id().to_string(), message);
128    }
129}