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
impl AgentRuntime
Sourcepub fn builder() -> AgentRuntimeBuilder
pub fn builder() -> AgentRuntimeBuilder
Create a new AgentRuntimeBuilder.
Sourcepub async fn run(
&mut self,
user_text: impl Into<String>,
) -> Result<RuntimeOutcome>
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.
Sourcepub async fn enqueue(
&mut self,
text: impl Into<String>,
) -> Result<Option<RuntimeOutcome>>
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.
Sourcepub fn queue_len(&self) -> usize
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”).
Sourcepub fn transcript(&self) -> &[Message]
pub fn transcript(&self) -> &[Message]
Return a reference to the accumulated transcript.
Sourcepub fn set_transcript(&mut self, transcript: Vec<Message>)
pub fn set_transcript(&mut self, transcript: Vec<Message>)
Replace the current transcript (useful for restoring from a saved session).
Sourcepub fn truncate_transcript(&mut self, len: usize)
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.
Sourcepub fn kernel(&self) -> &AgentKernel
pub fn kernel(&self) -> &AgentKernel
Return a reference to the inner kernel.
Sourcepub fn event_sink(&self) -> &dyn EventSink
pub fn event_sink(&self) -> &dyn EventSink
Return the event sink currently in use.
Sourcepub fn set_interrupt_token(&mut self, token: CancellationToken)
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.
Sourcepub fn set_session_id(&mut self, id: impl Into<String>)
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.
Sourcepub fn set_event_sink(&mut self, sink: Arc<dyn EventSink>)
pub fn set_event_sink(&mut self, sink: Arc<dyn EventSink>)
Set a new event sink (useful for REPL mode between turns).
Sourcepub fn current_todos(&self) -> Vec<TodoItem>
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.
Sourcepub fn set_permission_hook(&mut self, hook: Arc<dyn PermissionHook>)
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.
Sourcepub fn plan_approval_gate(&self) -> Arc<PlanApprovalGate> ⓘ
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.
Sourcepub fn confirm_plan(&mut self)
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).
Sourcepub async fn compact_now(&mut self) -> Result<()>
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).
Sourcepub fn set_planning_mode(&mut self, mode: PlanningMode)
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.
Sourcepub fn approve_plan_mode_request(&self)
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.
Sourcepub fn reject_plan_mode_request(&self, reason: &str)
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.
Sourcepub fn reject_plan(&mut self, reason: &str)
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).
Sourcepub fn current_goal(&self) -> Option<GoalState>
pub fn current_goal(&self) -> Option<GoalState>
Return a clone of the current goal state (or None).
Sourcepub async fn set_goal(&self, condition: String, max_turns: u32)
pub async fn set_goal(&self, condition: String, max_turns: u32)
Set a new active goal. Emits AgentEvent::GoalSet via the event sink.
Sourcepub async fn clear_goal(&self)
pub async fn clear_goal(&self)
Clear the active goal. Emits AgentEvent::GoalCleared.
Sourcepub async fn run_goal_loop(
&mut self,
initial_prompt: impl Into<String>,
condition: impl Into<String>,
max_turns: u32,
) -> Result<Vec<RuntimeOutcome>>
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:
run(prompt)— execute one agent turn.- Increment
GoalState.turns. - If
turns >= max_turns→ emitGoalCleared(budget exceeded), break. - Call
GoalEvaluator::evaluate(condition, transcript_tail). - If
achieved→ emitGoalAchieved, break. - Else → emit
GoalContinuing { reason }, continue with auto-prompt.
Sourcepub async fn run_loop(
&mut self,
initial_goal: impl Into<String>,
wakeup_slot: &WakeupSlot,
) -> Result<Vec<RuntimeOutcome>>
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.
Sourcepub async fn run_event_loop(
&mut self,
initial_goal: impl Into<String>,
wakeup_slot: &WakeupSlot,
bg_manager: Option<&Mutex<BackgroundJobManager>>,
) -> Result<Vec<RuntimeOutcome>>
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:
- The
WakeupSlotfor an explicit wakeup request - The
BackgroundJobManagerfor 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.
Sourcepub fn enable_checkpoints(
&mut self,
shadow: Arc<ShadowRepo>,
session_id: impl Into<String>,
log_path: PathBuf,
touched_slot: Option<Arc<Mutex<TouchedFiles>>>,
) -> Result<()>
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).
Sourcepub fn checkpoints_enabled(&self) -> bool
pub fn checkpoints_enabled(&self) -> bool
Whether checkpoint snapshots are active.
Sourcepub fn turn_index(&self) -> usize
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§
Auto Trait Implementations§
impl !RefUnwindSafe for AgentRuntime
impl !UnwindSafe for AgentRuntime
impl Freeze for AgentRuntime
impl Send for AgentRuntime
impl Sync for AgentRuntime
impl Unpin for AgentRuntime
impl UnsafeUnpin for AgentRuntime
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
impl<A, B, T> HttpServerConnExec<A, B> for Twhere
B: Body,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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