Skip to main content

Runtime

Struct Runtime 

Source
pub struct Runtime { /* private fields */ }
Expand description

Entry point for configuring providers, tools, and agent lifecycles.

A runtime composes four main subsystems:

  • execution: providers, policies, hooks, and command execution
  • persistence: agent state, runs, tasks, leases, and memory
  • tooling: registered tools, skills, and app context
  • collaboration: persistent teams and background task coordination

Implementations§

Source§

impl Runtime

Source

pub fn builder() -> RuntimeBuilder

Returns a builder with Mentra’s builtin tools enabled.

Source

pub fn empty_builder() -> RuntimeBuilder

Returns a builder with no builtin tools registered.

Source

pub fn skill_body(&self, name: &str) -> Result<String, String>

Returns a skill’s body, whether or not the model may invoke it.

The path a host uses to run a skill itself — as a slash command, say. load_skill refuses a skill whose frontmatter set disable-model-invocation, and that refusal is the point; without this such a skill appeared in skills and could be run by nobody, which made the flag’s promise false.

Source

pub fn register_tool<T>(&self, tool: T)
where T: ExecutableTool + 'static,

Registers a custom tool on the runtime after construction.

Source

pub fn register_prepared_tool(&self, prepared: PreparedTool)

Registers a custom tool from an already validated descriptor snapshot.

Construction of PreparedTool evaluates the tool descriptor exactly once. This method consumes that prepared value and uses its captured name and metadata without re-evaluation. Like register_tool, it deliberately replaces a same-name registration.

Source

pub fn try_register_tool<T>(&self, tool: T) -> Result<(), ToolNameCollision>
where T: ExecutableTool + 'static,

Registers a custom tool unless its name is already taken.

register_tool replaces a tool of the same name, which is right for deliberately overriding a builtin and wrong for a loader that did not mean to shadow one. This reports the collision instead.

Source

pub fn try_register_prepared_tool( &self, prepared: PreparedTool, ) -> Result<(), ToolNameCollision>

Registers an already prepared custom tool unless its captured name is taken.

Use this after validating PreparedTool::descriptor when validation identity and registry identity must be the same immutable snapshot.

Source

pub fn try_register_tool_for_audience<T>( &self, audience: ToolAudience, tool: T, ) -> Result<AudienceToolRegistration, ToolNameCollision>
where T: ExecutableTool + 'static,

Registers a custom tool visible only to agents in audience.

Registration refuses a global tool of the same name or another tool in the same audience, while a different audience may use the same name. The returned guard owns the registration lifetime and exposes the exact descriptor snapshot evaluated by this call.

Source

pub fn try_register_prepared_tool_for_audience( &self, audience: ToolAudience, prepared: PreparedTool, ) -> Result<AudienceToolRegistration, ToolNameCollision>

Registers an already prepared tool for one audience.

The collision key and the descriptor returned by the registration guard both come from the exact snapshot the caller could validate before this call. The tool definition is not evaluated again.

Source

pub fn unregister_tool(&self, name: &str) -> bool

Removes a registered tool by name, reporting whether one was there.

Source

pub fn tools(&self) -> Vec<RuntimeToolDescriptor>

Returns descriptors for registered tools in a deterministic order.

Source

pub fn tools_for_audience( &self, audience: Option<&ToolAudience>, ) -> Vec<RuntimeToolDescriptor>

Returns the name-ordered tool descriptors visible to audience.

Some(audience) resolves the matching audience namespace before the runtime-global fallback. None returns only runtime-global tools and is identical to tools.

No agent identity is supplied, so exact-agent registrations are intentionally excluded. The returned descriptor snapshot is cloned under one registry read lock and grants no authority to execute a tool.

Source

pub fn tool_descriptor(&self, name: &str) -> Option<RuntimeToolDescriptor>

Returns the descriptor for a registered tool by name.

Source

pub fn register_context(&self, context: Arc<dyn Any + Send + Sync>)

Registers typed application state that tools can retrieve from their context.

Source

pub fn app_context<T>(&self) -> Result<Arc<T>, String>
where T: Any + Send + Sync + 'static,

Returns typed application state previously registered on this runtime.

Source

pub fn register_pre_hook<H>(&self, hook: H) -> PreExecutionHookRegistration
where H: PreExecutionHook + 'static,

Registers a live pre-execution hook for every agent on this runtime.

Agents and sessions that already exist observe the hook on their next tool call. Builder-time hooks are permanent and run first; live global and matching-audience hooks then run together in registration order. Keep the returned guard alive for as long as the hook should apply.

Source

pub fn register_pre_hook_for_audience<H>( &self, audience: ToolAudience, hook: H, ) -> PreExecutionHookRegistration
where H: PreExecutionHook + 'static,

Registers a live pre-execution hook for one ToolAudience.

The audience is opaque execution scope, not a working directory. Agents with another audience, and agents with no audience, never run this hook.

Source

pub fn register_pre_hook_shared( &self, key: impl Into<String>, hook: Arc<dyn PreExecutionHook>, ) -> Result<SharedPreExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one runtime-global pre-execution hook under a caller-supplied key.

Reusing key with the same Arc allocation returns another holder of the existing chain entry. Reusing it with another hook or audience returns SharedHookRegistrationConflict. The entry remains until its last holder (including guard clones) is dropped. Ordinary register_pre_hook calls remain independent.

Source

pub fn register_pre_hook_shared_for_audience( &self, key: impl Into<String>, audience: ToolAudience, hook: Arc<dyn PreExecutionHook>, ) -> Result<SharedPreExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one audience-scoped pre-execution hook under a caller key.

The audience and exact Arc allocation are part of the registration identity. The key namespace belongs only to the pre-execution chain.

Source

pub fn register_post_hook<H>(&self, hook: H) -> PostExecutionHookRegistration
where H: PostExecutionHook + 'static,

Registers a live post-execution hook for every agent on this runtime.

Builder-time hooks are permanent and outermost. Live hooks join one registration order with them, then the complete post-execution chain runs in exact reverse so the earliest registration has the final say. A post-hook invocation already snapshotted may finish after its guard is dropped; this does not retain the hook across the whole tool call.

Source

pub fn register_post_hook_for_audience<H>( &self, audience: ToolAudience, hook: H, ) -> PostExecutionHookRegistration
where H: PostExecutionHook + 'static,

Registers a live post-execution hook for one ToolAudience.

The audience is opaque execution scope, not a working directory. Agents with another audience, and agents with no audience, never run this hook.

Source

pub fn register_post_hook_shared( &self, key: impl Into<String>, hook: Arc<dyn PostExecutionHook>, ) -> Result<SharedPostExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one runtime-global post-execution hook under a caller-supplied key.

The same key and exact Arc allocation produce holder-counted guards for one chain entry. A different hook or audience conflicts. The key namespace is independent from the pre-execution and mixed chains.

Source

pub fn register_post_hook_shared_for_audience( &self, key: impl Into<String>, audience: ToolAudience, hook: Arc<dyn PostExecutionHook>, ) -> Result<SharedPostExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one audience-scoped post-execution hook under a caller key.

Source

pub fn register_execution_hook<H>( &self, participant: H, ) -> ExecutionHookRegistration
where H: ExecutionHookParticipant + 'static,

Registers one live runtime-global participant in the ordered mixed chain.

Source

pub fn register_execution_hooks<I>( &self, participants: I, ) -> ExecutionHookRegistration

Atomically registers one ordered runtime-global participant batch.

Source

pub fn register_execution_hook_shared( &self, key: impl Into<String>, participant: Arc<dyn ExecutionHookParticipant>, ) -> Result<SharedExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one runtime-global mixed-hook participant under a caller key.

Source

pub fn register_execution_hooks_shared<I>( &self, key: impl Into<String>, participants: I, ) -> Result<SharedExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one ordered runtime-global mixed-hook batch under a caller key.

Reusing key shares the existing chain entry only when the ordered list contains the exact same Arc allocations. Length or order changes are conflicts. Independent non-shared batches keep their existing additive composition.

Source

pub fn register_execution_hook_for_audience<H>( &self, audience: ToolAudience, participant: H, ) -> ExecutionHookRegistration
where H: ExecutionHookParticipant + 'static,

Registers one live participant for an exact crate::tool::ToolAudience.

Source

pub fn register_execution_hooks_for_audience<I>( &self, audience: ToolAudience, participants: I, ) -> ExecutionHookRegistration

Atomically registers one ordered batch for an exact ToolAudience.

Existing matching agents observe the complete batch on their next admitted call. The returned guard removes the batch as one unit.

Source

pub fn register_execution_hook_shared_for_audience( &self, key: impl Into<String>, audience: ToolAudience, participant: Arc<dyn ExecutionHookParticipant>, ) -> Result<SharedExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one mixed-hook participant for an exact audience under a caller key.

Source

pub fn register_execution_hooks_shared_for_audience<I>( &self, key: impl Into<String>, audience: ToolAudience, participants: I, ) -> Result<SharedExecutionHookRegistration, SharedHookRegistrationConflict>

Shares one ordered mixed-hook batch for an exact audience under a caller key.

The audience and ordered Arc identities are part of the registration identity. The last holder drop removes the complete batch atomically.

Source

pub fn register_skills_dir( &self, path: impl AsRef<Path>, ) -> Result<(), SkillLoadError>

Registers a skills directory and enables the builtin load_skill tool.

Additive: calling this again adds a second root rather than replacing the first. Register the most specific root first — a name two roots both define resolves to the one registered earlier, and the shadowed skill is outranked rather than discarded, so unregister_skills_dir on the winner brings it back.

A root already registered is reloaded in place, keeping the precedence it had: one entry per directory, so one unregister always suffices to drop it.

Nothing is registered when the root fails to load.

Source

pub fn register_skills_dirs<I, P>(&self, paths: I) -> Result<(), SkillLoadError>
where I: IntoIterator<Item = P>, P: AsRef<Path>,

Registers several skills directories at once, strongest first.

Equivalent to calling register_skills_dir for each in order, with one difference that matters to a host: the call is atomic. Every root is loaded and validated before any is committed, so an Err leaves the runtime exactly as it was and names the root that failed. Fixing that root and calling again is a clean retry rather than a second, overlapping registration.

Within a single root a repeated name is still SkillLoadError::DuplicateSkillName: across roots it is layering, inside one root it is a mistake.

Source

pub fn unregister_skills_dir(&self, path: impl AsRef<Path>) -> bool

Drops every skill registered from path, reporting whether the root was there.

The inverse of register_skills_dir, for a host that outlives the thing a root belongs to — an editor server closing one repository while other repositories keep running on the same runtime. A dropped skill is unreachable, not merely unlisted: load_skill refuses it, and it leaves the model-facing skill list. A name this root had shadowed resolves to the weaker root again.

The root is matched by canonical path, so a path spelled differently than at registration still names it; a root whose directory has since been deleted is matched by the exact path that registered it.

Dropping the last root also withdraws the load_skill tool, which the next registration restores.

Source

pub fn unregister_skills_dirs<I, P>(&self, paths: I) -> bool
where I: IntoIterator<Item = P>, P: AsRef<Path>,

Drops several skills directories at once, reporting whether any of them was registered.

Every path that names a registered root is dropped regardless of the others, so a host closing a workspace can pass the same list it registered without first checking which roots still exist.

Source

pub fn skills(&self) -> Vec<SkillInfo>

Every loaded skill, name-ordered, with its description, source path and registered root but not its body.

Shadowed skills are left out: this is what a name resolves to today.

Source

pub fn mcp_servers(&self) -> &[McpServerSummary]

How each configured MCP server fared while the runtime was built.

Empty when none were configured, or when the runtime came from build, which refuses to be given any. A failed server is present with its error rather than absent: a host telling a user which tools they have needs to name what is missing.

Source

pub fn task_board(&self, namespace: impl AsRef<Path>) -> TaskBoard

Returns a lead-privileged task-board view for namespace.

The namespace is an opaque store key; no directory is created. Reads are live and every mutation passes through the same validation and transactional store path as the builtin task tools.

Source

pub fn spawn( &self, name: impl Into<String>, model: ModelInfo, ) -> Result<Agent, RuntimeError>

Spawns a new agent with the default AgentConfig.

Source

pub fn spawn_with_config( &self, name: impl Into<String>, model: ModelInfo, config: AgentConfig, ) -> Result<Agent, RuntimeError>

Spawns a new agent with an explicit configuration.

Source

pub fn spawn_with_config_for_audience( &self, name: impl Into<String>, model: ModelInfo, config: AgentConfig, audience: ToolAudience, ) -> Result<Agent, RuntimeError>

Spawns a new agent in an ephemeral tool audience.

Source

pub fn resume_agent(&self, agent_id: &str) -> Result<Agent, RuntimeError>

Restores a previously persisted agent by identifier.

Source

pub fn resume_agent_for_audience( &self, agent_id: &str, audience: ToolAudience, ) -> Result<Agent, RuntimeError>

Restores a persisted agent in the supplied live tool audience.

Source

pub fn resume( &self, runtime_identifier: &str, ) -> Result<Vec<Agent>, RuntimeError>

Restores every persisted agent that belongs to the provided runtime identifier.

Source

pub fn resume_for_audience( &self, runtime_identifier: &str, audience: ToolAudience, ) -> Result<Vec<Agent>, RuntimeError>

Restores every persisted agent under an ephemeral tool audience.

Source

pub fn list_persisted_agents( &self, runtime_identifier: &str, ) -> Result<Vec<PersistedAgentSummary>, RuntimeError>

Lists persisted agents for a runtime identifier without reviving them.

Source

pub fn delete_agent(&self, agent_id: &str) -> Result<(), RuntimeError>

Removes a persisted agent and everything stored under it.

Deleting the record without its memory would leave a row that resume refuses with “missing persisted memory”, so this removes both, along with remembered permission rules scoped to the agent’s session. Project- and global-scoped rules are shared and remain. It does not stop a live Agent already holding that id — an agent in memory keeps running, and persists itself again on its next write.

Source

pub fn resume_all(&self) -> Result<Vec<Agent>, RuntimeError>

Restores every persisted agent known to the runtime store.

Source§

impl Runtime

Source

pub fn providers(&self) -> Vec<ProviderDescriptor>

Returns descriptors for registered providers.

Source

pub fn fresh_provider_session_scope( &self, provider: Option<&ProviderId>, ) -> Result<ProviderSessionScope, RuntimeError>

Mints the selected provider’s configuration into an independent session scope.

None selects the runtime’s default provider. The operation is local and synchronous: it allocates provider-owned scope state but does not open or warm a connection. The returned ProviderSessionScope implements Provider and can be passed directly to RuntimeBuilder::with_provider_instance. Ordinary clones share the returned scope; call Provider::fresh_session_scope again to split it.

Source

pub fn responses_transport(&self) -> Option<ResponsesTransport>

The Responses transport this runtime chose for every request it makes, or None when it left the choice to each request’s own options — which is HTTP+SSE unless a host set otherwise.

The reader for RuntimeBuilder::with_responses_transport. A transport is otherwise the one piece of a runtime’s configuration nothing can observe: a registered tool shows up in tools, a provider in providers, but a transport reaches only the requests the runtime sends. That makes the wiring between a host’s choice and this runtime untestable except by running a turn against a provider that records what it was handed — and leaves a host that wants to report its own configuration with no way to ask.

Source

pub fn register_provider( &mut self, id: BuiltinProvider, api_key: impl Into<String>, ) -> Result<(), String>

Registers a builtin provider from an API key.

Source

pub fn register_ollama(&mut self)

Registers the local Ollama provider using its default OpenAI-compatible endpoint.

Source

pub fn register_lmstudio(&mut self)

Registers the local LM Studio provider using its default OpenAI-compatible endpoint.

Source

pub fn register_openai_compatible( &mut self, id: impl Into<ProviderId>, base_url: impl AsRef<str>, api_key: impl Into<String>, )

Registers any endpoint speaking the OpenAI chat/completions wire.

id is the name this runtime will know the provider by. Almost every OpenAI-compatible endpoint — DeepSeek, Groq, Together, Fireworks, Mistral, xAI, vLLM, llama.cpp — serves this wire and not OpenAI’s own v1/responses.

runtime.register_openai_compatible(
    "groq",
    "https://api.groq.com/openai/",
    std::env::var("GROQ_API_KEY").unwrap(),
);
Source

pub fn register_openai_compatible_without_credentials( &mut self, id: impl Into<ProviderId>, base_url: impl AsRef<str>, )

Registers an OpenAI-compatible endpoint that wants no credentials, such as a local vLLM or llama.cpp server.

Source

pub fn register_provider_instance<P>(&mut self, provider: P)
where P: Provider + 'static,

Registers a custom runtime provider implementation.

This is the supported seam for injecting a scripted provider in tests or embedding Mentra on top of a custom transport.

use async_trait::async_trait;
use mentra::{BuiltinProvider, ModelInfo, ProviderDescriptor, Runtime};
use mentra::error::{ProviderError, RuntimeError};
use mentra::provider::{Provider, ProviderEventStream, Request};
use tokio::sync::mpsc;

struct TestProvider;

#[async_trait]
impl Provider for TestProvider {
    fn descriptor(&self) -> ProviderDescriptor {
        ProviderDescriptor::new(BuiltinProvider::Anthropic)
    }

    async fn list_models(&self) -> Result<Vec<ModelInfo>, ProviderError> {
        Ok(vec![ModelInfo::new("test-model", BuiltinProvider::Anthropic)])
    }

    async fn stream(
        &self,
        _request: Request<'_>,
    ) -> Result<ProviderEventStream, ProviderError> {
        let (_tx, rx) = mpsc::unbounded_channel();
        Ok(rx)
    }
}

let mut runtime = Runtime::empty_builder()
    .with_provider(BuiltinProvider::Anthropic, "placeholder")
    .build()?;
runtime.register_provider_instance(TestProvider);
Source

pub fn register_registered_provider<P>(&mut self, provider: P)
where P: Provider + 'static,

Registers a provider-core instance built from mentra::provider_core.

Use this when you want Mentra’s runtime with a customized provider definition, such as a custom OpenAI-compatible or Anthropic-compatible base URL.

Source

pub async fn list_models( &self, provider: Option<&ProviderId>, ) -> Result<Vec<ModelInfo>, RuntimeError>

Lists models for a specific provider, or the default provider when omitted.

Source

pub async fn resolve_model( &self, provider: impl Into<ProviderId>, selector: ModelSelector, ) -> Result<ModelInfo, RuntimeError>

Resolves a model for a registered provider using a deterministic selection strategy.

Source§

impl Runtime

Source

pub fn create_session( &self, name: impl Into<String>, model: ModelInfo, ) -> Result<Session, RuntimeError>

Creates a new session wrapping a freshly spawned agent with default config.

Source

pub fn create_session_with_config( &self, name: impl Into<String>, model: ModelInfo, config: AgentConfig, ) -> Result<Session, RuntimeError>

Creates a new session wrapping a freshly spawned agent with explicit config.

Convenience wrapper around create_session_full that passes None for project_id.

Source

pub fn create_session_with_options( &self, name: impl Into<String>, model: ModelInfo, options: SessionOptions, ) -> Result<Session, RuntimeError>

Creates a new session with full control over how it is scoped and persisted.

The reason this exists next to create_session_full: a runtime’s identifier is otherwise fixed when the runtime is built, so every session minted on one runtime carries the same tag and list_persisted_agents cannot tell them apart. A host serving several workspaces from one runtime — an editor with more than one project open — needs each session’s rows tagged with the workspace they belong to.

Source

pub fn create_session_full( &self, name: impl Into<String>, model: ModelInfo, config: AgentConfig, project_id: Option<String>, ) -> Result<Session, RuntimeError>

Creates a new session wrapping a freshly spawned agent with explicit config and an optional project identifier.

The project_id is threaded into the automatically attached SessionPermissionHandle, so project permission rules use the runtime’s PermissionRuleStore immediately.

Source

pub fn resume_session(&self, agent_id: &str) -> Result<Session, RuntimeError>

Resumes a previously persisted agent and wraps it in a session.

Convenience wrapper around resume_session_with_project that passes None for project_id.

Source

pub fn resume_session_with_project( &self, agent_id: &str, project_id: Option<String>, ) -> Result<Session, RuntimeError>

Resumes a previously persisted agent, wraps it in a session, and associates the session with an optional project identifier.

The project_id is threaded into the automatically attached SessionPermissionHandle, so project permission rules use the current runtime store immediately.

Source

pub fn resume_session_with_options( &self, agent_id: &str, options: SessionResumeOptions, ) -> Result<Session, RuntimeError>

Resumes a persisted agent with current session scope and store tagging.

By default the agent keeps its stored runtime identifier so later snapshots remain visible to the same list_persisted_agents query. Set SessionResumeOptions::runtime_identifier to change that tag on the next persist.

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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. 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> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

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 = !

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

fn try_from(value: U) -> Result<T, !>

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