pub struct EngineHost { /* private fields */ }Implementations§
Source§impl EngineHost
impl EngineHost
Sourcepub async fn boot(opts: HostOpts) -> Result<Arc<Self>>
pub async fn boot(opts: HostOpts) -> Result<Arc<Self>>
Every step of the old setup::boot() that does NOT mention a session:
profile, logging, HTTP client, registry, config, skills, MCP, extension
manager. Touches NO process static: the OpenAI routing static is
written by Self::install for the winning host only, and the global
broker is installed in Self::foreground_runtime via apply_config,
exactly where the old boot did it relative to session resolution.
Sourcepub fn install(host: Arc<Self>) -> Result<(), Arc<Self>>
pub fn install(host: Arc<Self>) -> Result<(), Arc<Self>>
Idempotent, atomic install of the process host. Exactly one host ever
wins the OnceLock; the winner’s extension manager becomes the
OpenAI routing static in the same step. A different host arriving
later (or losing a race) is returned as Err(rejected) and never
replaces the installed one — nor touches any static.
Sourcepub async fn boot_and_install(opts: HostOpts) -> Result<Arc<Self>>
pub async fn boot_and_install(opts: HostOpts) -> Result<Arc<Self>>
The process host: the installed one, else boot + install. Under a
race the loser is discarded and the installed host returned, so a
caller never ends up on a host that current() does not agree with.
pub fn current() -> Option<Arc<Self>>
Sourcepub fn flush_logs(&self)
pub fn flush_logs(&self)
Flush the non-blocking log writer: drops the appender guard, which
drains the channel and joins the writer thread (≤ 1 s). Idempotent.
Lines logged AFTER this call are dropped, so it belongs at the very
last exit point (main return, panic hook), not at session shutdown.
Sourcepub fn flush_installed_logs()
pub fn flush_installed_logs()
Self::flush_logs on the installed host, if any.
pub fn parts(&self) -> &HostParts
pub fn config(&self) -> Guard<Arc<SynapsConfig>>
pub fn ext_manager(&self) -> &Arc<RwLock<ExtensionManager>> ⓘ
pub fn command_registry(&self) -> &Arc<CommandRegistry> ⓘ
pub fn keybind_registry(&self) -> &Arc<RwLock<KeybindRegistry>> ⓘ
pub fn mcp_server_count(&self) -> usize
Sourcepub async fn foreground_runtime(&self) -> Result<Runtime>
pub async fn foreground_runtime(&self) -> Result<Runtime>
The foreground runtime for an interactive session: shares client,
tools, hook_bus, credential source, token cache, MCP/extension lease
managers. Everything else is fresh (exactly Runtime::new()’s values).
apply_config runs here — the ONLY place the broker is (re)installed.
disabled_tools is NOT re-applied: boot() did it once on the fresh
registry, before skills/MCP registered, exactly where the old boot did.
Sourcepub async fn foreground_runtime_for(
&self,
cwd: Option<PathBuf>,
) -> Result<Runtime>
pub async fn foreground_runtime_for( &self, cwd: Option<PathBuf>, ) -> Result<Runtime>
foreground_runtime() for a session whose cwd is not the process cwd
(daemon-hosted sessions). The cwd is set BEFORE apply_config so the
memory binding (apply_memory_backend_config, one-shot) scopes to the
session’s project, not the daemon’s — A-engine-merge §4. None =
process cwd, byte-identical to foreground_runtime().
Sourcepub async fn worker_runtime(&self) -> Result<Runtime>
pub async fn worker_runtime(&self) -> Result<Runtime>
A worker (subagent) runtime. Shares credential source and token cache
(so NO broker re-install and NO cache eviction) and takes a CLONE of
the cached worker registry template. Does NOT share: the HTTP client
(fresh — see below), hook_bus (fresh, empty — hooks do not fire for
subagent tool calls), session_manager (fresh + reaper),
mcp_runtime/extension_runtime (None, as Runtime::new()).
Own client: workers block_on a throwaway current_thread runtime
and hyper parks each connection’s I/O driver on the runtime that
opened it. A pooled connection born on a worker would be handed to
the foreground (LIFO checkout) and die mid-stream when that worker’s
runtime dropped. A per-worker pool dies with its runtime, as before.
Sourcepub async fn worker_registry(&self) -> ToolRegistry
pub async fn worker_registry(&self) -> ToolRegistry
Cached-or-rebuilt worker registry: without_subagent_with_extensions
is a pure function of the shared registry’s tool set, which is a pure
function of its catalog generation, so caching by generation returns
exactly what a rebuild would.
Sourcepub fn reload_config(&self)
pub fn reload_config(&self)
Re-read config from disk into the host’s snapshot. Phase 1 callers
keep load_config() where they use it today.
Sourcepub async fn create_session(
self: &Arc<Self>,
cfg: SessionConfig,
) -> Result<SessionHandle>
pub async fn create_session( self: &Arc<Self>, cfg: SessionConfig, ) -> Result<SessionHandle>
Create a session on this host: builds the SessionActor (the one
Runtime + ConversationState), spawns its task, registers the
handle. The task removes itself from the map when it ends.
Attach-if-live: when cfg.continue_session resolves to a session
that is already running on this host (--continue X twice,
Attach::Create twice, --continue latest while latest is live),
the existing handle is returned and NO second actor is built. Two
actors on one id would share the session file, and the second’s
spawn_session_background would unlink the first’s per-session UDS
and overwrite its registry entry. cfg’s other fields (cwd, model
override, …) are ignored in that case — the live session wins.
Sourcepub fn adopt_session(&self, handle: SessionHandle)
pub fn adopt_session(&self, handle: SessionHandle)
Register a handle built elsewhere (daemon test factories). The
caller owns the task; remove_session when it ends.
Sourcepub fn session_handles(&self) -> Vec<SessionHandle>
pub fn session_handles(&self) -> Vec<SessionHandle>
Every registered handle (B4: THE session map; DaemonState
delegates here). Dead handles are dropped defensively: the actor
task drops cmd_rx when run() returns and remove_session runs
after — a listing in that window sees is_alive() == false. That
is an ordering window, not an invariant violation, so it is logged
at debug, never asserted.
Sourcepub fn attach(&self, id: &SessionId) -> Option<SessionHandle>
pub fn attach(&self, id: &SessionId) -> Option<SessionHandle>
Handle for a live session, if any.
Sourcepub fn sessions(&self) -> Vec<SessionMeta>
pub fn sessions(&self) -> Vec<SessionMeta>
Metadata of every live session, with the live cells filled (lifecycle, clients, input_owner, awaiting_input, journal_id).
Sourcepub fn remove_session(&self, id: &SessionId) -> Option<SessionHandle>
pub fn remove_session(&self, id: &SessionId) -> Option<SessionHandle>
Drop the host’s handle for a session (the actor keeps running until
its command queue closes or it receives End).
Sourcepub fn note_extensions_loading(&self)
pub fn note_extensions_loading(&self)
Loader seam (C2): a discovery pass for this host’s manager has been
dispatched. Called synchronously by spawn_discover_and_load before
its task runs, so extensions_ready() cannot slip through the gap.
Sourcepub fn mark_extensions_ready(&self)
pub fn mark_extensions_ready(&self)
Loader seam (C2): discovery finished — every extensions_ready()
waiter proceeds. Idempotent.
Sourcepub fn extensions_loading_guard(self: &Arc<Self>) -> ExtensionsLoadingGuard
pub fn extensions_loading_guard(self: &Arc<Self>) -> ExtensionsLoadingGuard
Loader seam (C2): note_extensions_loading() now, and
mark_extensions_ready() when the guard drops — however the loader
task ends (return, cancel, panic). Hold it inside the task so a
panicking walk cannot strand extensions_ready() waiters.
Sourcepub async fn extensions_ready(&self)
pub async fn extensions_ready(&self)
Resolve once extension discovery on this host is known-finished, so a
session’s on_session_start lands on subscribed extensions. Resolves
IMMEDIATELY when no loader was dispatched (hosts that never load
extensions, --no-extensions, tests) or discovery already completed
on the manager (in-process discover_and_load() callers such as
synaps chat); otherwise awaits mark_extensions_ready().
The watch sender is a field of the host, so “sender dropped” is NOT a
wake-up path while the host lives. Liveness comes from
ExtensionsLoadingGuard (the loader task marks ready on any exit,
including panic); callers that must not trust the loader at all
(SessionActor::create) additionally bound the await with
budgets::EXTENSIONS_READY_TIMEOUT.
Sourcepub async fn broadcast_extension_notification(
&self,
ext_id: &str,
method: &str,
params: Value,
) -> usize
pub async fn broadcast_extension_notification( &self, ext_id: &str, method: &str, params: Value, ) -> usize
C3: push one extension notification frame to every live session (non-blocking; a session whose command queue is full drops it with a warning — widget upserts are idempotent last-writer-wins). Frames carry no session id today, hence broadcast. Returns how many sessions accepted it.
Auto Trait Implementations§
impl !Freeze for EngineHost
impl !RefUnwindSafe for EngineHost
impl !UnwindSafe for EngineHost
impl Send for EngineHost
impl Sync for EngineHost
impl Unpin for EngineHost
impl UnsafeUnpin for EngineHost
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
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
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.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.