pub trait ExecutionService: Send + Sync {
// Required methods
fn spawn<'life0, 'async_trait>(
&'life0 self,
spec: SessionSpec,
) -> Pin<Box<dyn Future<Output = Result<SessionId, SpawnError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
fn state<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<ExecutionState, StateError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn resume<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
payload: ResumePayload,
) -> Pin<Box<dyn Future<Output = Result<ResumeOutcome, ResumeError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn cancel<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
reason: CancelReason,
) -> Pin<Box<dyn Future<Output = Result<(), CancelError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn observe(
&self,
id: &SessionId,
) -> Result<Box<dyn ObserverHandle>, ObserveError>;
fn await_terminal<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<TerminalOutcome, AwaitError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
}Expand description
Pure service trait for managing execution sessions.
Implementors must ensure the following invariants hold:
- Wire-concept exclusion: no MCP/rmcp types,
progressToken,_metafields,notifications/*paths, ormcp_-prefixed identifiers are referenced by this trait or its supporting types. SessionIdis the sole handle: all verbs afterspawnaccept only a&SessionId; no session-internal handles leak through the API.- Pure value types: all inputs and outputs are value types (no callbacks,
no
Arc-leaked internals). - Cooperative cancellation only:
cancelsignals the session via aCancellationToken; noJoinHandle::abort()or process kill may be invoked. - Sink-free progress fan-out:
observereturns abroadcast::Receiverwrapper that is valid without any pre-registered observer. Multiple concurrent subscribers each receive the full event stream independently. - Immediate
SessionIdreturn:spawnreturns theSessionIdbefore execution completes. - Single trait, all verbs: CLI, Server, and programmatic callers all use this single trait.
§Async vs sync verbs
All verbs are async fn except observe, which is a synchronous fn.
observe is sync because broadcast::Sender::subscribe() is itself synchronous
and does not perform I/O — making it async would force callers to .await
without reason and obscure the sink-free subscription semantics.
Required Methods§
Sourcefn spawn<'life0, 'async_trait>(
&'life0 self,
spec: SessionSpec,
) -> Pin<Box<dyn Future<Output = Result<SessionId, SpawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
fn spawn<'life0, 'async_trait>(
&'life0 self,
spec: SessionSpec,
) -> Pin<Box<dyn Future<Output = Result<SessionId, SpawnError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Spawn a new execution session from the given specification.
Returns the SessionId immediately; execution proceeds in the background.
§Errors
SpawnError::Engine— the engine failed to initialize the session.SpawnError::InvalidSpec— the providedSessionSpecis malformed.
Sourcefn state<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<ExecutionState, StateError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn state<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<ExecutionState, StateError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Query the current state of a session.
§Errors
StateError::NotFound— no session with the given id exists.
Sourcefn resume<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
payload: ResumePayload,
) -> Pin<Box<dyn Future<Output = Result<ResumeOutcome, ResumeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn resume<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
payload: ResumePayload,
) -> Pin<Box<dyn Future<Output = Result<ResumeOutcome, ResumeError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Resume a paused session by providing LLM responses.
The payload kind must match the pause kind of the session (single vs batch).
§Errors
ResumeError::NotFound— no session with the given id exists.ResumeError::NotPaused— the session is not in thePausedstate.ResumeError::AlreadyCancelled— the session is already cancelled.ResumeError::FeedError— the underlying feed operation failed.
Sourcefn cancel<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
reason: CancelReason,
) -> Pin<Box<dyn Future<Output = Result<(), CancelError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn cancel<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
reason: CancelReason,
) -> Pin<Box<dyn Future<Output = Result<(), CancelError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Request cooperative cancellation of a session.
cancel is idempotent: calling it on a session already in a terminal state
(Done, Failed, Cancelled) returns Ok(()). The only error case is when
no session with the given id exists.
Cancellation is delivered via a CancellationToken; the engine checks at
exactly four checkpoints (A/B/C/D) and transitions cooperatively to Cancelled.
No JoinHandle::abort() or process kill path is introduced.
§Errors
CancelError::NotFound— no session with the given id exists.
Sourcefn observe(
&self,
id: &SessionId,
) -> Result<Box<dyn ObserverHandle>, ObserveError>
fn observe( &self, id: &SessionId, ) -> Result<Box<dyn ObserverHandle>, ObserveError>
Subscribe to the progress event stream for a session.
Returns a Box<dyn ObserverHandle> that delivers super::progress::ProgressEvent
events from the session’s broadcast channel. Multiple concurrent subscribers
each receive the full event stream independently (sink-free fan-out).
This is a synchronous fn (not async) because
broadcast::Sender::subscribe() is synchronous and performs no I/O.
§Errors
ObserveError::NotFound— no session with the given id exists.
Sourcefn await_terminal<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<TerminalOutcome, AwaitError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn await_terminal<'life0, 'life1, 'async_trait>(
&'life0 self,
id: &'life1 SessionId,
) -> Pin<Box<dyn Future<Output = Result<TerminalOutcome, AwaitError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Await the terminal state of a session.
Blocks (asynchronously) until the session transitions to Done, Cancelled,
or Failed. Returns the terminal outcome.
§Errors
AwaitError::NotFound— no session with the given id exists.AwaitError::Joined— the background task failed unexpectedly.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".