entelix_graph/command.rs
1//! `Command<S>` — caller's instruction for `CompiledGraph::resume_with`.
2//!
3//! After an interrupt the caller has four reasonable next moves:
4//! - `Resume` as-is from the saved next-node and saved state.
5//! - `Update(s)` the state (e.g. inject the human's reply) and continue
6//! from the saved next-node.
7//! - `GoTo(node)` skip ahead to a different node, keeping the saved state.
8//! - `ApproveTool { tool_use_id, decision }` thread an out-of-band
9//! approval decision back into the graph for an `AwaitExternal`
10//! pause raised by an approval layer (`entelix-agents::ApprovalLayer`).
11//! The resume path attaches the decision to `ExecutionContext` via
12//! the typed `entelix_core::PendingApprovalDecisions` extension so
13//! the layer's override-lookup short-circuits the approver on
14//! re-entry.
15
16use entelix_core::ApprovalDecision;
17
18/// Resume directive supplied to `CompiledGraph::resume_with`.
19#[derive(Clone, Debug)]
20#[non_exhaustive]
21pub enum Command<S>
22where
23 S: Clone + Send + Sync + 'static,
24{
25 /// Continue from the saved checkpoint exactly as it stands.
26 Resume,
27 /// Replace the saved state, then continue from the saved next-node.
28 Update(S),
29 /// Continue with the saved state but jump to `node` next.
30 GoTo(String),
31 /// Resume an `AwaitExternal` pause with the operator's eventual
32 /// decision for the named `tool_use_id`. The resume path
33 /// attaches the decision to `ExecutionContext` via
34 /// `PendingApprovalDecisions` so the agent's approval layer
35 /// short-circuits the approver on re-entry; the pending tool
36 /// dispatches with `decision` applied. Saved state is kept
37 /// intact (combine with `Update(s)` outside `resume_with` if
38 /// state mutation is also needed).
39 ///
40 /// This variant does not depend on the enum's `S` parameter —
41 /// the tool-use id and decision are state-agnostic. The `S`
42 /// generic is part of the enum's shape (other variants need
43 /// it); operators reach this variant via the same
44 /// `Command::<S>::ApproveTool { ... }` path as any other.
45 ApproveTool {
46 /// Tool-use id matching the originating `ContentPart::ToolUse`
47 /// — the same id carried in the `Error::Interrupted::payload`
48 /// emitted by the layer.
49 tool_use_id: String,
50 /// Operator's decision (`Approve` to fire the dispatch,
51 /// `Reject { reason }` to short-circuit). `AwaitExternal`
52 /// is rejected at runtime — pausing again on resume is
53 /// almost certainly an operator bug.
54 decision: ApprovalDecision,
55 },
56}