Expand description
A small, modular Rust framework for one linear agent session.
Applications compose an agent::Agent from explicit model, sandbox, checkpoint, and
middleware adapters. Frontends remain separate: they submit protocol::Op values and
render the frontend-neutral protocol::Event stream.
§Embedded composition
The caller owns every runtime dependency. Include exactly one message-handling middleware,
give new sessions a non-empty protocol::SessionContext::bot_id, and keep draining events
while commands are active.
use std::path::Path;
use std::sync::Arc;
use mobius::Result;
use mobius::agent::{Agent, AgentConfig, create_agent};
use mobius::backend::checkpoint::{CheckpointStore, sqlite::SqliteCheckpoint};
use mobius::backend::model::{Model, ModelRouter, openai::OpenAi};
use mobius::backend::sandbox::{ApprovalPolicy, Sandbox, local::LocalSandbox};
use mobius::middleware::{Middleware, MiddlewareStack};
use mobius::middleware::{messages::Messages, tools::Tools};
use mobius::protocol::SessionContext;
async fn build_agent(
workspace: &Path,
api_key: String,
model_id: &str,
) -> Result<Agent> {
let model: Arc<dyn Model> = Arc::new(OpenAi::new(
api_key,
"https://api.openai.com/v1",
model_id,
)?);
let models = Arc::new(ModelRouter::new("default", model));
let sandbox = Arc::new(Sandbox::new(
Arc::new(LocalSandbox::new(workspace)?),
ApprovalPolicy::Ask,
));
let checkpoints: Arc<dyn CheckpointStore> =
Arc::new(SqliteCheckpoint::new(workspace.join("mobius.sqlite3"))?);
let middleware: Vec<Arc<dyn Middleware>> = vec![
Arc::new(Messages::default()),
Arc::new(Tools::coding()),
];
create_agent(
AgentConfig::new(
models,
sandbox,
checkpoints,
MiddlewareStack::new(middleware)?,
"You are a concise coding agent.",
)
.session_context(SessionContext {
bot_id: "embedded".into(),
..SessionContext::default()
}),
)
.await
}A custom provider implements backend::model::Model and must return normalized output.
backend::model::ModelEventSink is synchronous and fallible; propagate its error rather
than silently losing a streamed event. This example also uses serde_json.
use serde_json::json;
use mobius::{BoxFuture, Result};
use mobius::backend::model::{Model, ModelEventSink, ModelOutput, ModelRequest};
use mobius::protocol::{ModelEvent, ModelInfo, TokenUsage};
struct EchoModel;
impl Model for EchoModel {
fn info(&self) -> ModelInfo {
ModelInfo {
model: "echo".into(),
reasoning_effort: None,
}
}
fn respond<'a>(
&'a self,
_request: ModelRequest<'a>,
events: ModelEventSink,
) -> BoxFuture<'a, Result<ModelOutput>> {
Box::pin(async move {
events(ModelEvent::TextDelta("done".into()))?;
ModelOutput::from_output(
vec![json!({
"type": "message",
"role": "assistant",
"content": [{"type": "output_text", "text": "done"}]
})],
true,
TokenUsage::default(),
)
})
}
}A capability implements middleware::Middleware and joins the declaration-ordered
middleware::MiddlewareStack. Static prompt sections are composed once at agent creation.
use std::sync::Arc;
use mobius::Result;
use mobius::middleware::{Middleware, MiddlewareStack, PromptSection, RuntimeContext};
use mobius::middleware::messages::Messages;
struct Policy;
impl Middleware for Policy {
fn name(&self) -> &'static str {
"policy"
}
fn prompt_section(&self, _runtime: &RuntimeContext) -> Result<Option<PromptSection>> {
Ok(Some(PromptSection::new("Follow the repository policy.")))
}
}
fn middleware_stack() -> Result<MiddlewareStack> {
MiddlewareStack::new(vec![Arc::new(Messages::default()), Arc::new(Policy)])
}§Runtime contracts
ErrorandProviderErrorpreserve actionable failure classes and retry metadata; callers should not infer policy by matching display strings.agent::create_agentvalidates composition and unwinds started middleware on startup failure.agent::AgentSenderdocuments bounded submission and sender-drop shutdown; drainagent::AgentEvents::recvuntil the stream closes.backend::checkpoint::CheckpointStore::save_with_eventsis the atomic logical boundary for checkpoint, transcript, execution, and event state. Backend contracts specify durability and which optional history operations are supported.backend::sandbox::Sandboxowns approval and background-process cleanup around an injectedbackend::sandbox::SandboxBackend. Backends must keep cancellation cleanup for resources they launch; the default authorized path fails closed.- In
mobius-gateway, signal shutdown throughGatewayServer::serve_untiland await it; dropping the serving future does not perform graceful shutdown.
Modules§
- agent
- Agent handles and the single linear command dispatch loop.
- backend
- Runtime adapters used by the agent loop.
- middleware
- Ordered middleware and capability registration.
- protocol
- The small event protocol shared by agent frontends.
Structs§
- Provider
Error - A model-provider failure with retry metadata preserved for callers.
Enums§
- Error
- Errors returned by möbius modules.