pub struct OperatorSpawnerFactory { /* private fields */ }Expand description
Factory for AgentKind::Operator. Looks up the Arc<dyn Operator>
pre-registered under spec.operator_ref and wraps it in an
OperatorSpawner.
Spec shape:
{ "operator_ref": "main_ai" } // Operator id pre-registered with the factory§Split of responsibilities with OperatorDelegateMiddleware
The two axes exist for different reasons:
-
This factory (
OperatorSpawnerFactory→OperatorSpawner) — the AgentSpec axis. Bakes a separate Operator backend into eachAgentDef. Akind = OperatorAgentDefnames its backend throughspec.operator_ref; atcompile()time theArc<dyn Operator>is baked intoroutes[agent_name]. Because theagent.mdloader (agent_md_loader) defaultskindtoOperator, agents that flow in through agent-profiles land here. -
OperatorDelegateMiddleware— the Blueprint-global (session) axis. Delegates every agent to the same Operator backend. At session-attach time you callengine.register_operator(id, op)plusattach_with_ids(.., operator_backend_id = Some(id))to bind it session-wide, and declarespawner_hints.layers = ["operator_delegate"]to opt in.ctx.agentis ignored; the operator handles every spawn in that session (a MainAI-wide driver, a human-wide console, that sort of thing).
§Exclusivity (a double fire is structurally impossible)
When both are effective — the hint is declared, the session has an
operator backend, and the Blueprint has a kind = Operator
AgentDef — OperatorDelegateMiddleware sits at the outer end of
the stack and completely bypasses inner.spawn. The
OperatorSpawner is never reached, so under those conditions this
factory’s routes entry is inert. This is not a double fire — the
session axis is overriding the agent axis. Consistent usage means
picking one axis per use case.
Interior mutability is provided by an Arc<RwLock>. Even after the
factory has been stored as Arc<dyn SpawnerFactory> in
SpawnerRegistry, a caller holding an Arc clone can still add
Operator backends dynamically via register_operator(&self, id, op).
Typical uses: registering a WSOperatorSession under the session id
on WebSocket connect, binding agents that arrive via the agent.md
loader to arbitrary backends, and so on. build() performs a
read() lookup each time.
Implementations§
Source§impl OperatorSpawnerFactory
impl OperatorSpawnerFactory
Sourcepub fn register_operator(
&self,
id: impl Into<String>,
op: Arc<dyn Operator>,
) -> &Self
pub fn register_operator( &self, id: impl Into<String>, op: Arc<dyn Operator>, ) -> &Self
Register an Operator backend dynamically through &self.
Overwrites are allowed — later wins. Callers can still reach this
after the factory has been stored as Arc<dyn SpawnerFactory> in
SpawnerRegistry, as long as they hold an Arc clone; interior
mutability is provided by the inner RwLock.
Sourcepub fn unregister_operator(&self, id: &str) -> &Self
pub fn unregister_operator(&self, id: &str) -> &Self
Dynamically unregister an id (used to clean up when a WebSocket disconnects, for example). A missing id is a no-op.
Trait Implementations§
Source§impl Default for OperatorSpawnerFactory
impl Default for OperatorSpawnerFactory
Source§impl SpawnerFactory for OperatorSpawnerFactory
impl SpawnerFactory for OperatorSpawnerFactory
Source§fn build(
&self,
agent_def: &AgentDef,
_hint: Option<&Value>,
) -> Result<Arc<dyn SpawnerAdapter>, CompileError>
fn build( &self, agent_def: &AgentDef, _hint: Option<&Value>, ) -> Result<Arc<dyn SpawnerAdapter>, CompileError>
SpawnerAdapter for one AgentDef. hint is
the matching entry (if any) from Blueprint.hints.per_agent.Source§impl SpawnerFactoryKind for OperatorSpawnerFactory
impl SpawnerFactoryKind for OperatorSpawnerFactory
Source§const KIND: AgentKind = AgentKind::Operator
const KIND: AgentKind = AgentKind::Operator
AgentKind this factory handles — used as the HashMap key
by SpawnerRegistry::register.Source§type Worker = OperatorWorker
type Worker = OperatorWorker
AgentKind — this
binds the type chain all the way from AgentKind down to Worker.
Every factory declares it so the AgentKind → Worker mapping is
explicit across all four layers. It is the source of truth for
preserving the concrete type right up until SpawnerAdapter::spawn
erases it into Box<dyn Worker>.Auto Trait Implementations§
impl Freeze for OperatorSpawnerFactory
impl RefUnwindSafe for OperatorSpawnerFactory
impl Send for OperatorSpawnerFactory
impl Sync for OperatorSpawnerFactory
impl Unpin for OperatorSpawnerFactory
impl UnsafeUnpin for OperatorSpawnerFactory
impl UnwindSafe for OperatorSpawnerFactory
Blanket Implementations§
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
impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
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> 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 more