Skip to main content

AppServerController

Struct AppServerController 

Source
pub struct AppServerController {
    block_id: String,
    inner: Arc<Mutex<AppServerInner>>,
    broker: Option<Arc<Broker>>,
    event_bus: Option<Arc<EventBus>>,
    mstore: Option<Arc<Store>>,
    filestore: Option<Arc<FileStore>>,
    health_monitor: Arc<TurnActivityTracker>,
    self_ref: Mutex<Option<Weak<Self>>>,
}
Expand description

Controller for one isolated codex app-server --listen stdio:// child.

Fields§

§block_id: String§inner: Arc<Mutex<AppServerInner>>§broker: Option<Arc<Broker>>§event_bus: Option<Arc<EventBus>>§mstore: Option<Arc<Store>>§filestore: Option<Arc<FileStore>>§health_monitor: Arc<TurnActivityTracker>§self_ref: Mutex<Option<Weak<Self>>>

Implementations§

Source§

impl AppServerController

Source

pub fn new( block_id: String, broker: Option<Arc<Broker>>, event_bus: Option<Arc<EventBus>>, mstore: Option<Arc<Store>>, filestore: Option<Arc<FileStore>>, ) -> Self

Source

pub fn set_self_ref(self: &Arc<Self>)

Source

fn set_status(&self, status: &str)

Source

fn publish_status(&self)

Source

fn command_from_meta( &self, block_meta: &HashMap<String, Value>, ) -> Result<Command, String>

Source

fn publish_protocol_frame(&self, frame: Value, global_zone: Option<&str>)

global_zone is resolved once per process by spawn_event_loop, not per frame: resolving reads the block from the store, and frames arrive many times a second while a turn streams.

Source

fn spawn_event_loop( &self, process: Arc<AppServerProcess>, session: Arc<CodexAppServerSession>, )

Source

fn spawn_turn(&self, session: Arc<CodexAppServerSession>, message: String)

Source

pub fn send_message(&self, message: String) -> Result<(), String>

Source

fn clear_process_and_session(&self)

Clear a dead process/session so a later start() (resync) doesn’t see its own stale process.is_some() guard and wrongly no-op instead of respawning. ReAgent P1 on PR #3215’s third review: start()’s own initialize/thread-setup failure branches set STATUS_DONE and shut the process down without this, unlike the analogous EOF path in spawn_event_loop — a handshake failure permanently bricked the block with no recovery short of replacing the controller entirely.

Source

fn stop_process(&self)

Trait Implementations§

Source§

impl Controller for AppServerController

Source§

fn start( &self, block_meta: HashMap<String, Value>, _rt_opts: Option<Value>, _force: bool, ) -> Result<(), String>

Start the controller. May spawn background tasks. force restarts even if already running.
Source§

fn stop(&self, _graceful: bool, new_status: &str) -> Result<(), String>

Stop the controller. graceful waits for process to exit; new_status is the target state.
Source§

fn get_runtime_status(&self) -> BlockControllerRuntimeStatus

Get the current runtime status.
Source§

fn send_input( &self, input: BlockInputUnion, _seq: Option<u64>, ) -> Result<(), String>

Send input (terminal data, signal, or resize) to the controller. seq is the per-TermViewModel monotonic counter; None means fire-and-forget (no ordering).
Source§

fn turn_tracker(&self) -> Option<Arc<TurnActivityTracker>>

This controller’s turn tracker, for the turn ledger’s bookkeeping from outside the controller (a held message’s join hint). None for controllers that track no turns.
Source§

fn controller_type(&self) -> &str

Get the controller type (e.g., “shell”, “cmd”).
Source§

fn block_id(&self) -> &str

Get the block ID.
Source§

fn as_any(&self) -> &dyn Any

Downcast support for concrete controller types.
Source§

fn stop_for_replace(&self, new_status: &str) -> Result<(), String>

Stop this controller because it’s being REPLACED by a new one for the same block (session restart / resync’s needs_replace path), NOT because the block itself is being closed. Must terminate this controller’s own CLI process so it doesn’t linger, but — unlike stop() — must NOT reach any declared-background descendant the process may have spawned (e.g. a task dev instance launched via run_in_background: true); those must survive the replace. See docs/specs/SPEC_BACKGROUND_TASK_TEARDOWN_SURVIVAL_2026_08_20.md. Read more
Source§

fn shutdown( &self, _deadline: Instant, ) -> Pin<Box<dyn Future<Output = StopOutcome> + Send>>

Stop gracefully because the block is being CLOSED: end any turn in progress, ask the process to exit, force-kill at deadline. The returned future resolves once the process has actually exited (or there was none). Does NOT drop the block’s process tracker — the caller does that after this resolves, so nothing the agent started outlives it. See docs/specs/SPEC_AGENT_PANE_CLOSE_GRACEFUL_SHUTDOWN_2026_09_18.md §9.3. Read more
Source§

fn agent_id(&self) -> Option<String>

This block’s own live, spawn-time-captured jekt/muxbus identity, if it has one — an independent source of truth for the recipient- identity check in ReactiveHandler::inject_message_inner, deliberately NOT derived from ReactiveHandler’s own name_to_blocks/agent_info maps (checking a registry against itself would be a tautology and catch nothing). Default None for controller types that aren’t jekt-addressable at all (e.g. plain terminals) — only ShellController and PersistentSubprocessController currently override this, mirroring the two paths that already resolve a jekt-registration identity at spawn time (resolve_agent_id_for_jekt, muxbus_agent_id_from_env).
Source§

fn turn_provenance(&self) -> Option<TurnProvenance>

What started this agent’s current turn (SPEC_AGENT_SELF_QUIT §6.3), if the controller tracks it. None = unknown, which never counts as the user — the safe answer for controllers that can’t tell (ACP, App Server, subprocess: both origins reach them through one method).
Source§

fn set_agent_id(&self, _id: Option<String>)

Refresh this block’s own captured jekt/muxbus identity (see agent_id’s doc comment). Called whenever ReactiveHandler::register_agent/register_agent_with_nonce (re-)registers THIS block’s block_id under a (possibly different) agent_id, so the two independently-written copies never drift apart (#2697: agent_id() was captured once at spawn and never refreshed, while the registry’s name bindings get re-keyed on every register_agent call — e.g. handle_reactive_register’s frontend-initiated HTTP path — causing a legitimately renamed or reconfigured agent’s own messages to be falsely rejected as an identity mismatch). Default no-op for controller types that don’t override agent_id either.
Source§

fn stable_agent_id(&self) -> Option<String>

This block’s STABLE jekt identity — AGENTMUX_AGENT_ID as captured once at spawn, never refreshed. Distinct from agent_id, which tracks the LIVE, renameable display name and is deliberately refreshed every turn (see that method’s doc comment on #2697). AGENTMUX_AGENT_ID is embedded verbatim in PR-body tags specifically because it does NOT change if the agent is later renamed — but ReactiveHandler’s registry only tracks one key per block, and every turn’s agent_id() refresh evicts whatever this block was previously registered under. ReactiveHandler::inject_message_inner’s recipient-identity check (#2695) uses this alongside agent_id() so a jekt addressed to the stable ID is validated correctly even after the primary registry key has moved on to the live display name. See INCIDENT_2026_09_09_JEKT_STABLE_ID_ALIAS.md. Default None, mirroring agent_id’s default — only PersistentSubprocessController currently overrides this.
Source§

fn stable_agent_uid(&self) -> Option<String>

Identity M2: this block’s UID (db_agents.id) as carried in its spawn env (AGENTMUX_AGENT_UID, set by build_persistent_spawn_env since M1a), captured once at spawn like [stable_agent_id]. Backs the registry’s UID confirmer: consulted only for targets that resolved by UID, and None — a registered-but-not-yet-spawned controller, or a block with no row — is “unverifiable”, not a mismatch. Default None; only PersistentSubprocessController overrides this.

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
§

impl<T> Downcast for T
where T: Any,

§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync> ⓘ

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

§

impl<T> Instrument for T

§

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

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

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
§

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

§

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
§

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, 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.
§

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

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self> ⓘ

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