Skip to main content

AgentContext

Struct AgentContext 

Source
pub struct AgentContext {
Show 32 fields pub agent_id: String, pub config: Arc<AgentConfig>, pub broker: AnyBroker, pub sessions: Arc<SessionManager>, pub memory: Option<Arc<LongTermMemory>>, pub router: Option<Arc<AgentRouter>>, pub peers: Option<Arc<PeerDirectory>>, pub mcp: Option<Arc<SessionMcpRuntime>>, pub session_id: Option<Uuid>, pub effective: Option<Arc<EffectiveBindingPolicy>>, pub effective_tools: Option<Arc<ToolRegistry>>, pub credentials: Option<Arc<AgentCredentialResolver>>, pub breakers: Option<Arc<BreakerRegistry>>, pub redactor: Option<Arc<Redactor>>, pub transcripts_index: Option<Arc<TranscriptsIndex>>, pub link_extractor: Option<Arc<LinkExtractor>>, pub context_optimization: Option<ResolvedContextOptimization>, pub event_emitter: Option<Arc<dyn AgentEventEmitter>>, pub dispatch: Option<Arc<DispatchToolContext>>, pub repl_registry: Option<Arc<ReplRegistry>>, pub sender_trusted: bool, pub inbound_origin: Option<(String, String, String)>, pub plan_mode: Arc<RwLock<PlanModeState>>, pub plan_approval_registry: Arc<PlanApprovalRegistry>, pub todos: Arc<RwLock<TodoList>>, pub team_id: Option<String>, pub team_member_name: Option<String>, pub inbox: Arc<RwLock<Vec<DmMessage>>>, pub proactive_enabled: bool, pub binding_role: Option<String>, pub binding: Option<BindingContext>, pub inbound: Option<InboundMessageMeta>, /* private fields */
}

Fields§

§agent_id: String§config: Arc<AgentConfig>§broker: AnyBroker§sessions: Arc<SessionManager>§memory: Option<Arc<LongTermMemory>>§router: Option<Arc<AgentRouter>>§peers: Option<Arc<PeerDirectory>>

Snapshot of peer agents running in this process. Feeds the auto-generated # PEERS system-prompt block so the LLM knows which ids to pass to delegate(...). None in test/bootstrap contexts where peer discovery doesn’t apply.

§mcp: Option<Arc<SessionMcpRuntime>>

MCP runtime scoped to this session (if MCP is enabled).

§session_id: Option<Uuid>

Active session id when the context is built inside an LLM turn. None for contexts built outside the loop (heartbeat bootstrap, tests). Used by tool handlers that opt into context passthrough.

§effective: Option<Arc<EffectiveBindingPolicy>>

Per-binding capability snapshot resolved at intake. Some when the runtime matched the inbound event to an InboundBinding for this agent; None for paths without a binding match (delegation receive, heartbeat, tests). Use AgentContext::effective_policy to access a policy that always has a value — it synthesises one from the agent-level config when effective is None.

§effective_tools: Option<Arc<ToolRegistry>>

Per-binding tool registry — shares handlers with the agent’s base registry but only exposes tools that survive the binding’s allowed_tools filter. None on code paths without a binding match (delegation receive, heartbeat, tests); consumers fall back to the behavior’s base registry in that case.

§credentials: Option<Arc<AgentCredentialResolver>>

Resolver that maps this agent’s id to the opaque credential handles it is allowed to use for outbound traffic. None in early-boot / test contexts; consumers must treat that as “no credentials configured” (tools return an unbound error rather than publishing from an arbitrary account).

§breakers: Option<Arc<BreakerRegistry>>

Per-(channel, instance) breaker registry shared by plugin outbound tools. None for runtimes without credentials.

§redactor: Option<Arc<Redactor>>

Pre-persistence redactor for transcript content. None in test/bootstrap contexts → behavior keeps content untouched.

§transcripts_index: Option<Arc<TranscriptsIndex>>

FTS5 index over transcript content. None when the subsystem is disabled or initialization failed; consumers fall back to JSONL-only persistence + substring scan.

§link_extractor: Option<Arc<LinkExtractor>>

Shared link extractor (HTTP client + LRU cache). None in early-boot / test contexts; llm_behavior treats that as “link understanding disabled regardless of config”.

§context_optimization: Option<ResolvedContextOptimization>

Current effective enables for the four context-optimization mechanisms (hot-reloadable). Set per-event by AgentRuntime from RuntimeSnapshot::context_optimization, so a config reload that flips a flag is observed on the next turn without restarting the behavior. None for legacy / test contexts that haven’t been wired through the snapshot — in that case llm_behavior falls back to the boot-time prompt_cache_enabled / compaction_runtime.enabled flags.

§event_emitter: Option<Arc<dyn AgentEventEmitter>>

Agent event emitter threaded from the AgentRuntime so llm_behavior can attach it to per-turn TranscriptWriter instances. Without this, transcript appends emit through the default NoopAgentEventEmitter and never reach the bootstrap’s broadcast firehose, leaving subscribers (microapps with agent_events_subscribe_all) silent on live updates. None for test/bootstrap contexts; consumers fall back to no-op emission in that case.

§dispatch: Option<Arc<DispatchToolContext>>

Bundle of services consumed by the dispatch tool handlers (program_phase, list_agents, etc.). Populated at boot when the project tracker is enabled. None keeps the dispatch tools off — handlers return a friendly error so the LLM doesn’t pretend they worked.

§repl_registry: Option<Arc<ReplRegistry>>

REPL session registry. Some when repl-tool feature is enabled AND the binding config has repl.enabled. Holds persistent Python/Node/bash subprocesses.

§sender_trusted: bool

Sender’s pairing-trust bit, set by intake after the pairing gate runs. Defaults to false so any path that forgets to thread it through fails closed under require_trusted=true. Read-only tools bypass this gate.

§inbound_origin: Option<(String, String, String)>

(plugin, instance, sender_id) of the inbound event that produced this turn, when the runtime matched a binding. Lets the dispatch handler synthesise an OriginChannel for program_phase so notify_origin lands back in the chat.

§plan_mode: Arc<RwLock<PlanModeState>>

Plan-mode state for this goal. Shared across the dispatcher (read on every tool call) and the EnterPlanMode / ExitPlanMode tools (write). SQLite is canonical (column on agent_registry.goals.plan_mode); this is a hot cache. New contexts default to Off; the runtime hydrates the value from the registry at goal spawn / reattach.

§plan_approval_registry: Arc<PlanApprovalRegistry>

Process-shared registry of pending plan-mode approvals. EnterPlanMode does not touch it; ExitPlanMode installs a waiter when plan_mode.require_approval is on; the plan_mode_resolve operator tool fires the matching waiter. Tests construct their own registry to avoid cross-test races.

§todos: Arc<RwLock<TodoList>>

Intra-turn scratch todo list. Owned by the model (mutated via TodoWrite). Distinct from TaskFlow: Todo is in-memory + per-goal + flat; TaskFlow is persistent

  • cross-session + DAG. Reattach does not restore todos — they die with the goal because re-deriving them mid-turn is cheap and stale items are confusing.
§team_id: Option<String>

When set, this goal is running as a member of a named team. The lead’s team_id is its own team’s id; ordinary sub-agents stay None.

§team_member_name: Option<String>

Human-readable member name within team_id (e.g. "researcher"). Noneteam_id.is_none(). Some(TEAM_LEAD_NAME) for the lead’s own goal.

§inbox: Arc<RwLock<Vec<DmMessage>>>

DMs the team router delivered while this goal was running. Consumed at the start of each turn by the prompt-assembly path. Concurrent appends are serialised by the goal’s tokio task scheduler — there is no inner lock because the consume is single-threaded per-goal.

§proactive_enabled: bool

Whether this goal runs in proactive tick-loop mode. Set at goal spawn from EffectiveBindingPolicy::proactive().enabled. Read by llm_behavior to inject the proactive system hint.

§binding_role: Option<String>

Binding role tag ("coordinator", "worker", "proactive", or None). Stored here so llm_behavior can inject the coordinator hint without re-reading the binding config on every turn.

§binding: Option<BindingContext>

Composed binding context propagated to tool calls via _meta.nexo.binding. Some when intake matched an InboundBinding; None for bindingless paths (delegation receive, heartbeat bootstrap, tests).

Construct via super::binding_context_from_effective(&policy, agent_id, session_id) at the intake site that matches the binding. Tool dispatch reads this to populate the JSON-RPC params._meta block.

§inbound: Option<InboundMessageMeta>

Per-turn metadata about the inbound message that triggered this agent turn (sender id, msg id, timestamp, …). Some when the intake site populated it (whatsapp plugin, event-subscriber binding, webhook receiver, delegation receive, heartbeat tick, …); None for legacy producers not yet migrated and for tests. Surfaces under _meta.nexo.inbound via AgentContext::build_meta_value.

Implementations§

Source§

impl AgentContext

Source

pub fn new( agent_id: impl Into<String>, config: Arc<AgentConfig>, broker: AnyBroker, sessions: Arc<SessionManager>, ) -> Self

Source

pub fn with_team( self, team_id: impl Into<String>, name: impl Into<String>, ) -> Self

Mark this context as running as a teammate. name is the human-readable handle within the team ("researcher", "tester", or TEAM_LEAD_NAME).

Source

pub fn is_teammate(&self) -> bool

true when both team_id and team_member_name are set. The runtime’s teammate-cannot-spawn-teammate guard inspects this.

Source

pub fn with_plan_mode(self, state: Arc<RwLock<PlanModeState>>) -> Self

Install a pre-built plan-mode handle. Used at goal hydration so the runtime can share the same Arc<RwLock> between the dispatcher (gate) and the registry mirror (write path).

Source

pub fn with_plan_approval_registry( self, registry: Arc<PlanApprovalRegistry>, ) -> Self

Install a process-shared plan-mode approval registry. Production wiring constructs one per process and hands it to every AgentContext; tests build their own to avoid cross-test races.

Source

pub fn is_interactive(&self) -> bool

true when this goal is rooted in a live channel that can deliver an operator approval message. Sub-agent goals (delegations, future TeamCreate workers), cron / poller / heartbeat-spawned goals, and bootstrap contexts all return false because they have no inbound channel through which an operator could approve a plan.

Reference: research/src/acp/session-interaction-mode.ts:4-15 — same intent, “interactive” vs “parent-owned-background”.

Source

pub fn with_sender_trusted(self, v: bool) -> Self

Source

pub fn with_inbound_origin( self, plugin: impl Into<String>, instance: impl Into<String>, sender_id: impl Into<String>, ) -> Self

Source

pub fn with_inbound_meta(self, meta: InboundMessageMeta) -> Self

Install per-turn InboundMessageMeta on the context. Producers (channel plugins, event-subscriber, delegation, heartbeat) build the meta at the intake site and the per-turn dispatch loop layers it on the cloned context before invoking tools / hooks.

Source

pub fn with_dispatch(self, d: Arc<DispatchToolContext>) -> Self

Source

pub fn with_context_optimization(self, co: ResolvedContextOptimization) -> Self

Set the per-turn context-optimization snapshot. Called by the agent runtime intake after loading the active RuntimeSnapshot, so a hot-reload that swaps the snapshot is observed without rebuilding the behavior.

Source

pub fn with_redactor(self, redactor: Arc<Redactor>) -> Self

Source

pub fn with_event_emitter(self, emitter: Arc<dyn AgentEventEmitter>) -> Self

Install the firehose emitter so per-turn TranscriptWriter instances built in llm_behavior can chain .with_emitter() and broadcast TranscriptAppended to subscribers.

Source

pub fn with_transcripts_index(self, index: Arc<TranscriptsIndex>) -> Self

Source

pub fn with_memory(self, memory: Arc<LongTermMemory>) -> Self

Source

pub fn with_router(self, router: Arc<AgentRouter>) -> Self

Source

pub fn with_peers(self, peers: Arc<PeerDirectory>) -> Self

Source

pub fn with_mcp(self, mcp: Arc<SessionMcpRuntime>) -> Self

Source

pub fn with_session_id(self, id: Uuid) -> Self

Source

pub fn with_effective(self, effective: Arc<EffectiveBindingPolicy>) -> Self

Source

pub fn with_mcp_channel_source(self, source: impl Into<String>) -> Self

Layer the MCP channel source on top of the BindingContext after with_effective has run. No-op if binding is None (paths without a binding match cannot have an MCP-channel source — the source rides alongside an already-matched binding, not as a substitute).

Source

pub fn with_effective_tools(self, tools: Arc<ToolRegistry>) -> Self

Source

pub fn with_event_source(self, meta: EventSourceMeta) -> Self

Populate binding.event_source when the inbound was synthesised from a NATS event subscriber. No-op when self.binding is None; logged at debug level so the call-site can stay branchless if the caller doesn’t want to gate the call. Caller is expected to gate at the call site for hot paths (every native-channel inbound passing through the resolver).

Source

pub fn with_credentials(self, credentials: Arc<AgentCredentialResolver>) -> Self

Source

pub fn with_breakers(self, breakers: Arc<BreakerRegistry>) -> Self

Source

pub fn effective_policy(&self) -> Arc<EffectiveBindingPolicy>

Returns the active effective policy, synthesising one from the agent-level config when no binding was matched. Cheap to call in hot paths: returns an existing Arc when available and builds a fresh one only for unbound contexts.

Source

pub fn build_meta_value(&self) -> Value

Single source of truth for the _meta payload exposed to extension tools (stdio JSON-RPC) and MCP tools (tools/call params._meta). Both surfaces must emit identical wire shapes so a microapp speaks the same dialect regardless of which transport delivered the call.

Returned value is a JSON object with two layers:

  • flat agent_id + session_id for backward-compat with older consumers,
  • nested nexo.binding carrying BindingContext when the intake matched a binding (omitted otherwise to keep the wire compact for delegation receive / heartbeat bootstrap / tests).

Trait Implementations§

Source§

impl Clone for AgentContext

Source§

fn clone(&self) -> AgentContext

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> DynClone for T
where T: Clone,

Source§

fn __clone_box(&self, _: Private) -> *mut ()

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> FromRef<T> for T
where T: Clone,

Source§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more