made_core/ports/agent_resolver.rs
1//! [`AgentResolverPort`] — resolve agent identities into concrete
2//! [`AgentPort`] instances.
3//!
4//! The [`Council`](crate::entities::Council) aggregate stores only
5//! [`AgentId`]s to keep the domain pure of runtime objects. Use cases
6//! that need to actually ask agents to propose / critique / revise
7//! go through this port to obtain the live handles.
8//!
9//! Adapters typically back this port with an in-memory registry, a
10//! factory that materializes agents from config, or a cache in front
11//! of a remote agent service. MADE itself never knows.
12
13use std::sync::Arc;
14
15use async_trait::async_trait;
16
17use crate::error::DomainError;
18use crate::ports::agent::AgentPort;
19use crate::value_objects::AgentId;
20
21#[async_trait]
22pub trait AgentResolverPort: Send + Sync {
23 /// Resolve a single agent identity. Returns
24 /// [`DomainError::NotFound`] when the id is unknown to the adapter.
25 async fn resolve(&self, id: &AgentId) -> Result<Arc<dyn AgentPort>, DomainError>;
26
27 /// Resolve a batch of agent identities preserving input order.
28 /// Returns [`DomainError::NotFound`] on the first unresolved id.
29 ///
30 /// Default implementation calls [`Self::resolve`] in order; adapters
31 /// can override to batch lookups.
32 async fn resolve_all(&self, ids: &[AgentId]) -> Result<Vec<Arc<dyn AgentPort>>, DomainError> {
33 let mut out = Vec::with_capacity(ids.len());
34 for id in ids {
35 out.push(self.resolve(id).await?);
36 }
37 Ok(out)
38 }
39}