pub struct Tasks { /* private fields */ }Expand description
One workspace’s durable tasks.
Clone because a handful of this type’s own async fns need an owned
copy to move onto a blocking thread (see blocking, below) — every field
is already cheap to clone (a path, an Arc), so this costs nothing a
caller could not already do by hand.
Implementations§
Source§impl Tasks
impl Tasks
Sourcepub fn open(workspace: impl Into<PathBuf>) -> Result<Self, Error>
pub fn open(workspace: impl Into<PathBuf>) -> Result<Self, Error>
Opens the durable task store: BASIS_DATA_DIR, else an absolute
XDG_DATA_HOME, else the platform data home (created private on first
use). workspace is read by spawn and
list only; every handle-scoped method resolves
straight from the handle, so opening Tasks is cheap and does not
itself touch workspace on disk.
Sourcepub fn open_at(
data_dir: impl Into<PathBuf>,
workspace: impl Into<PathBuf>,
) -> Result<Self, Error>
pub fn open_at( data_dir: impl Into<PathBuf>, workspace: impl Into<PathBuf>, ) -> Result<Self, Error>
Opens the durable task store at an explicit root, bypassing the
BASIS_DATA_DIR/XDG discovery open performs.
For a host that manages its own data directory location rather than
the process environment — several Tasks in one process, each with
its own root, for one — and for a test that wants no dependency on
std::env at all.
Sourcepub fn with_prompt_host(self, prompt_host: Arc<dyn PromptHost>) -> Self
pub fn with_prompt_host(self, prompt_host: Arc<dyn PromptHost>) -> Self
Supplies how this Tasks answers Approve::Prompt while it drives a
task, and whether it can be asked at all — see PromptHost. Without
one, Prompt refuses the same way an unaskable process always did;
basis-cli is the first caller of this.
Sourcepub fn can_ask(&self) -> bool
pub fn can_ask(&self) -> bool
Whether this Tasks can currently put an Approve::Prompt question
to whoever answers for it — false with no PromptHost supplied.
Sourcepub fn store_dir(workspace: &Path) -> Result<PathBuf, Error>
pub fn store_dir(workspace: &Path) -> Result<PathBuf, Error>
The mentra store directory workspace resolves to, without minting or
reading any task.
What a host’s attended, one-shot route — no durable task, no handle —
needs to land its conversation store on the same directory
spawn would use for the same workspace, so the two
share one conversation history and one memory root rather than
falling back to two.
Sourcepub fn spawn(&self, spec: RunSpec) -> Result<TaskHandle, Error>
pub fn spawn(&self, spec: RunSpec) -> Result<TaskHandle, Error>
Mints a task and returns its handle immediately. Durable and resumable from the moment this returns: nothing has attached yet, and nothing has to for the handle to be good.
Sourcepub fn send(
&self,
handle: &TaskHandle,
message: impl Into<String>,
) -> Result<String, Error>
pub fn send( &self, handle: &TaskHandle, message: impl Into<String>, ) -> Result<String, Error>
Enqueues a follow-up turn. Never blocks and never drives: the message
is durable the moment this returns, and progress happens only once
something attaches — ask, wait, or any other attacher.
Sourcepub async fn ask(
&self,
handle: &TaskHandle,
caller: Option<&TaskHandle>,
message: impl Into<String>,
timeout: Duration,
) -> Result<Reply, Error>
pub async fn ask( &self, handle: &TaskHandle, caller: Option<&TaskHandle>, message: impl Into<String>, timeout: Duration, ) -> Result<Reply, Error>
Enqueues a follow-up turn and awaits its correlated reply, attaching
to drive the task whenever the attach lock is free. send plus
wait_message, as one call — the edge is
validated before the enqueue, so a rejected wait cannot leave a
message behind.
Threading: the edge check and the enqueue are this call’s own
synchronous prelude and run through this crate’s own blocking
helper; the wait after it is attach::wait_for_message’s own.
Sourcepub async fn wait_message(
&self,
handle: &TaskHandle,
caller: Option<&TaskHandle>,
message_id: &str,
timeout: Duration,
) -> Result<WaitOutcome, Error>
pub async fn wait_message( &self, handle: &TaskHandle, caller: Option<&TaskHandle>, message_id: &str, timeout: Duration, ) -> Result<WaitOutcome, Error>
Awaits one already-enqueued message’s correlated reply — the wait --message shape: repeatable without any policy check once the reply
exists, and edge-validated only for the wait that has to actually
happen.
Threading: the dispatch check and the edge check are this call’s
own synchronous prelude and run through this crate’s own blocking
helper; the wait after it, when one is still needed, is
attach::wait_for_message’s own.
Sourcepub async fn wait(
&self,
handle: &TaskHandle,
caller: Option<&TaskHandle>,
timeout: Duration,
live: Option<Arc<dyn LiveSink>>,
) -> Result<WaitOutcome, Error>
pub async fn wait( &self, handle: &TaskHandle, caller: Option<&TaskHandle>, timeout: Duration, live: Option<Arc<dyn LiveSink>>, ) -> Result<WaitOutcome, Error>
Awaits the task’s terminal record, attaching to drive it whenever the
attach lock is free — repeatable: a settled task’s record is read
straight off disk, never rerun. live, when given, is shown every
event while (and only while) this call is the one driving.
Threading: the terminal read and the edge check are this call’s
own synchronous prelude and run through this crate’s own blocking
helper; the wait after it, when one is still needed, is this crate’s
own wait_unvalidated’s.
Sourcepub async fn spawn_and_wait(
&self,
spec: RunSpec,
timeout: Duration,
live: Option<Arc<dyn LiveSink>>,
) -> Result<(TaskHandle, WaitOutcome), Error>
pub async fn spawn_and_wait( &self, spec: RunSpec, timeout: Duration, live: Option<Arc<dyn LiveSink>>, ) -> Result<(TaskHandle, WaitOutcome), Error>
Mints a task and immediately attaches to drive it to a terminal
result — spawn --await’s shape, and the one place a wait skips edge
validation: see this crate’s private wait_unvalidated for why that
is safe only here.
Threading: spawn is a synchronous unit in its own
right — a directory scan, the continuation lock, create_dir,
save_meta — and runs through this crate’s own blocking helper here
exactly as it would if this crate wrote it as its own
blocking-wrapped prelude; the wait after it is this crate’s own
wait_unvalidated’s.
Sourcepub fn validate_wait_edge(
&self,
caller: Option<&TaskHandle>,
target: &TaskHandle,
) -> Result<(), Error>
pub fn validate_wait_edge( &self, caller: Option<&TaskHandle>, target: &TaskHandle, ) -> Result<(), Error>
Whether caller (or nobody, for a host outside any task) may
wait or ask target — the ownership
rule ADR-0017 states: a descendant or an independent root is safe, an
ancestor or a peer is not (send it instead, and read the reply from
inbox). Err names which rule the edge breaks; a
caller that only wants the yes/no can ask for .is_ok().
Sourcepub fn validate_cancel_target(
&self,
caller: Option<&TaskHandle>,
target: &TaskHandle,
) -> Result<(), Error>
pub fn validate_cancel_target( &self, caller: Option<&TaskHandle>, target: &TaskHandle, ) -> Result<(), Error>
Whether caller (or nobody, for a host outside any task) may
cancel target — downward-only, ADR-0017’s rule:
itself or a descendant, never an ancestor or a peer. Err names which
rule the target breaks; a caller that wants the refusal to win over an
idempotent observation of an already-settled target checks this
first, the way basis cancel does.
Sourcepub fn cancel(
&self,
handle: &TaskHandle,
caller: Option<&TaskHandle>,
) -> Result<(), Error>
pub fn cancel( &self, handle: &TaskHandle, caller: Option<&TaskHandle>, ) -> Result<(), Error>
Requests downward cancellation of target and every attached,
non-terminal descendant. Idempotent: cancelling an already-settled
task is a no-op, and this call never blocks on one settling.
Sourcepub fn watch(&self, handle: &TaskHandle) -> Result<EventCursor, Error>
pub fn watch(&self, handle: &TaskHandle) -> Result<EventCursor, Error>
Opens a cursor over the task’s event journal, replay-from-start. Pure
observation — this never attaches or drives; poll it in a loop beside
terminal for basis watch’s own shape, or just
long enough to catch up on a run already in progress.
Sourcepub fn terminal(&self, handle: &TaskHandle) -> Result<Option<Value>, Error>
pub fn terminal(&self, handle: &TaskHandle) -> Result<Option<Value>, Error>
The raw terminal record, or None for a task still resumable.
Repeatable and lock-free: existence of terminal.json is the
completion signal (ADR-0019).
Sourcepub fn is_attached(&self, handle: &TaskHandle) -> Result<bool, Error>
pub fn is_attached(&self, handle: &TaskHandle) -> Result<bool, Error>
Whether a live executor currently holds the task’s attach lock.
Sourcepub fn inbox(&self, handle: &TaskHandle) -> Result<Value, Error>
pub fn inbox(&self, handle: &TaskHandle) -> Result<Value, Error>
Every message accepted on the task’s inbox, bounded 4 KiB summaries
with truncation metadata — the basis inbox payload shape.
Sourcepub fn workspace_of(&self, handle: &TaskHandle) -> Result<PathBuf, Error>
pub fn workspace_of(&self, handle: &TaskHandle) -> Result<PathBuf, Error>
The workspace the task was spawned against, as it was recorded at
spawn — not necessarily Tasks::open’s own workspace, since a handle
resolves purely from itself.