Skip to main content

AgentRuntime

Struct AgentRuntime 

Source
pub struct AgentRuntime {
    pub goal_state: Arc<RwLock<Option<GoalState>>>,
    /* private fields */
}
Expand description

A stateful agent runtime that wraps AgentKernel.

AgentRuntime owns the conversation transcript and all cross-turn configuration. Each call to run appends a user message to the transcript, delegates to the kernel for one turn, and appends the kernel’s new messages back to the transcript.

Fields§

§goal_state: Arc<RwLock<Option<GoalState>>>

Goal-168: active goal state (set by /goal). None when no goal is active.

Implementations§

Source§

impl AgentRuntime

Source

pub fn builder() -> AgentRuntimeBuilder

Create a new AgentRuntimeBuilder.

Source

pub async fn run( &mut self, user_text: impl Into<String>, ) -> Result<RuntimeOutcome>

Run one turn with the given user text.

Appends Message::user(text) to the transcript, delegates to the kernel, appends the new messages back, and returns a RuntimeOutcome.

Source

pub async fn enqueue( &mut self, text: impl Into<String>, ) -> Result<Option<RuntimeOutcome>>

Enqueue a user message and drain the queue in FIFO order.

This is the preferred entry point for all interaction layers (TUI, HTTP, CLI). Unlike calling run directly, enqueue is safe to call while a turn is already in flight: the runtime is single-threaded (&mut self), so multiple callers naturally serialise. The queue ensures messages submitted before the runtime is ready are not lost and are processed in order.

user sends A → enqueue(A) → run(A)
user sends B while A runs → enqueue(B) → queue=[B]  (A already running via prior call)
A finishes → loop pops B → run(B)

In practice the outer loop (drain_queue) is what creates this ordering: a call to enqueue that arrives while another enqueue is executing on the same runtime will block on &mut self borrow, so the messages are processed strictly in order.

Source

pub fn queue_len(&self) -> usize

Number of messages currently waiting in the queue.

Callers can expose this to the UI (e.g. status bar: “+N queued”).

Source

pub fn transcript(&self) -> &[Message]

Return a reference to the accumulated transcript.

Source

pub fn set_transcript(&mut self, transcript: Vec<Message>)

Replace the current transcript (useful for restoring from a saved session).

Source

pub fn truncate_transcript(&mut self, len: usize)

Discard all transcript messages after index len, restoring the transcript to the state it had before a turn started. Used by the TUI abort path to prevent orphan tool_call entries.

Source

pub fn kernel(&self) -> &AgentKernel

Return a reference to the inner kernel.

Source

pub fn event_sink(&self) -> &dyn EventSink

Return the event sink currently in use.

Source

pub fn set_interrupt_token(&mut self, token: CancellationToken)

Set a cancellation token that interrupts the current (or next) agent turn.

When the token is cancelled the step loop exits with FinishReason::Cancelled at the next step boundary. This method replaces any previously installed token — call it before each run() so a fresh token is in place.

Source

pub fn set_session_id(&mut self, id: impl Into<String>)

Set the session id used for tracing-span labels and turn log lines.

After this is called, every run() emits a tracing span record with session_id=<id> and an info log line carrying the same field, so logs and OTEL/Datadog traces can be filtered per session via RUST_LOG=recursive[{session_id}]=debug or the session_id label.

Source

pub fn set_event_sink(&mut self, sink: Arc<dyn EventSink>)

Set a new event sink (useful for REPL mode between turns).

Source

pub fn current_todos(&self) -> Vec<TodoItem>

Goal-167: return a snapshot of the current agent task list.

Returns a clone of the list as it stands at call time. Returns an empty vec if the internal lock is poisoned.

Source

pub fn set_permission_hook(&mut self, hook: Arc<dyn PermissionHook>)

Goal-161: attach a crate::tools::PermissionHook to the underlying tool registry so every tool invocation passes through the async permission gate before execution.

Source

pub fn plan_approval_gate(&self) -> Arc<PlanApprovalGate>

Return a shared reference to the plan-approval gate.

Callers (e.g. HTTP handlers) that need to inspect pending_plan or call approve/reject without holding the runtime Mutex can clone this Arc and operate on the gate directly.

Source

pub fn confirm_plan(&mut self)

Confirm the pending plan, allowing execution to proceed on the next run.

Covers both PlanFirst mode (sets plan_confirmed flag for kernel) and Plan Mode 2.0 (wakes exit_plan_mode’s blocking wait via the gate).

Source

pub async fn compact_now(&mut self) -> Result<()>

Force a compaction pass right now, regardless of the configured threshold. Useful for TUI / API surfaces that expose a manual “/compact” command.

No-op (returns Ok(())) when no compactor is configured or when the transcript is too small to compact (fewer than keep_recent_n + 2 messages).

Source

pub fn set_planning_mode(&mut self, mode: PlanningMode)

Update the planning mode in place. Allows the TUI’s /plan on|off command to flip plan-first vs immediate without rebuilding the runtime.

Source

pub fn approve_plan_mode_request(&self)

Goal-202: approve the plan-mode entry request.

Wakes RequestPlanModeTool’s blocking wait, returning {"approved": true} to the LLM so it can proceed with enter_plan_mode.

Source

pub fn reject_plan_mode_request(&self, reason: &str)

Goal-202: reject the plan-mode entry request with a reason.

Wakes RequestPlanModeTool’s blocking wait, returning {"approved": false, "reason": "..."} so the LLM can execute directly.

Source

pub fn reject_plan(&mut self, reason: &str)

Reject the pending plan with a reason.

Covers both PlanFirst mode (injects a user message) and Plan Mode 2.0 (wakes exit_plan_mode’s blocking wait with the rejection reason).

Source

pub fn current_goal(&self) -> Option<GoalState>

Return a clone of the current goal state (or None).

Source

pub async fn set_goal(&self, condition: String, max_turns: u32)

Set a new active goal. Emits AgentEvent::GoalSet via the event sink.

Source

pub async fn clear_goal(&self)

Clear the active goal. Emits AgentEvent::GoalCleared.

Source

pub async fn run_goal_loop( &mut self, initial_prompt: impl Into<String>, condition: impl Into<String>, max_turns: u32, ) -> Result<Vec<RuntimeOutcome>>

Run a goal loop: execute turns until the judge says the condition is met, the turn budget is exhausted, or the goal is cleared externally.

Steps per iteration:

  1. run(prompt) — execute one agent turn.
  2. Increment GoalState.turns.
  3. If turns >= max_turns → emit GoalCleared (budget exceeded), break.
  4. Call GoalEvaluator::evaluate(condition, transcript_tail).
  5. If achieved → emit GoalAchieved, break.
  6. Else → emit GoalContinuing { reason }, continue with auto-prompt.
Source

pub async fn run_loop( &mut self, initial_goal: impl Into<String>, wakeup_slot: &WakeupSlot, ) -> Result<Vec<RuntimeOutcome>>

Run a loop: execute turns until the agent stops scheduling wakeups.

Between turns, sleeps for the requested delay. If the agent doesn’t call schedule_wakeup during a turn, the loop ends.

The wakeup_slot should be the same slot registered with the ScheduleWakeup tool in the agent’s tool registry.

Source

pub async fn run_event_loop( &mut self, initial_goal: impl Into<String>, wakeup_slot: &WakeupSlot, bg_manager: Option<&Mutex<BackgroundJobManager>>, ) -> Result<Vec<RuntimeOutcome>>

Run a loop with background job awareness.

After each turn, checks both:

  1. The WakeupSlot for an explicit wakeup request
  2. The BackgroundJobManager for completed jobs

If a background job completed, its output is injected as the next turn’s goal. If a wakeup was scheduled, the runtime sleeps for the requested delay then continues. If neither is present, the loop ends.

Source

pub fn enable_checkpoints( &mut self, shadow: Arc<ShadowRepo>, session_id: impl Into<String>, log_path: PathBuf, touched_slot: Option<Arc<Mutex<TouchedFiles>>>, ) -> Result<()>

Bind this runtime to a checkpoint chain. Subsequent calls to run() will snapshot before and after each turn under refs/sessions/<session_id>/HEAD and append a record to checkpoint_log_path (a checkpoints.jsonl file).

touched_slot is the same collector previously installed on the ToolRegistry via with_touched_files. If no collector is provided, file-attribution falls back to “shell-diff” for every turn.

Side effect: registers the read-only checkpoint_list and checkpoint_diff tools, scoped to this session, onto the kernel’s tool registry — so the agent can introspect its own checkpoint chain (but cannot save or restore; those are orchestration concerns).

Source

pub fn checkpoints_enabled(&self) -> bool

Whether checkpoint snapshots are active.

Source

pub fn turn_index(&self) -> usize

Returns the 0-indexed counter that will be assigned to the next turn (i.e. the count of turns already executed).

Trait Implementations§

Source§

impl Debug for AgentRuntime

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,

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

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. 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: 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: 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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