Skip to main content

AgentLoop

Struct AgentLoop 

Source
pub struct AgentLoop<M: Model> {
    pub model: M,
    pub tools: ToolRegistry,
    pub guides: Vec<Arc<dyn Guide>>,
    pub sensors: Vec<Arc<dyn Sensor>>,
    pub hooks: HookBus,
    pub compactor: Arc<dyn Compactor>,
    pub response_format: ResponseFormat,
    pub streaming: bool,
    pub recall: Option<Arc<dyn RecallStore>>,
    pub recall_auto_inject: bool,
    pub learning: Option<LearningConfig>,
}
Expand description

The agent loop.

Fields§

§model: M§tools: ToolRegistry§guides: Vec<Arc<dyn Guide>>§sensors: Vec<Arc<dyn Sensor>>§hooks: HookBus§compactor: Arc<dyn Compactor>§response_format: ResponseFormat

Default response format applied to every run unless overridden by run_typed. See ResponseFormat.

§streaming: bool

When true, the loop drives each model turn via Model::stream() instead of complete(), firing Event::ModelTokenDelta for each text fragment. Tool-call deltas are still assembled inside the loop; only the terminal ModelOutput shape is observable downstream.

§recall: Option<Arc<dyn RecallStore>>

Optional cross-session recall store. When set, the loop captures every turn and the session_search tool is registered. See with_recall.

§recall_auto_inject: bool

When true (and recall is set), a RecallGuide auto-injects top-k past context at session start.

§learning: Option<LearningConfig>

Implementations§

Source§

impl<M: Model> AgentLoop<M>

Source

pub fn new(model: M) -> Self

Source

pub fn with_streaming(self, enable: bool) -> Self

Opt in to streaming the model’s terminal turn token-by-token via Model::stream(). Hooks subscribed to Event::ModelTokenDelta see each fragment as it arrives; the rest of the loop is unchanged.

Source

pub fn with_compactor(self, c: Arc<dyn Compactor>) -> Self

Source

pub fn with_tool(self, t: Arc<dyn Tool>) -> Self

Source

pub fn with_guide(self, g: Arc<dyn Guide>) -> Self

Source

pub fn with_sensor(self, s: Arc<dyn Sensor>) -> Self

Source

pub fn with_hook(self, h: Arc<dyn Hook>) -> Self

Source

pub fn with_macro_hooks(self) -> Self

Pull in every #[hook]-registered hook.

Source

pub fn with_recall(self, store: Arc<dyn RecallStore>) -> Self

Enable cross-session recall: capture every turn into store and register the session_search tool. Owner + session id are read from world.profile.extra["recall_owner"|"recall_session"] at run time.

Source

pub fn auto_inject(self) -> Self

After with_recall, also auto-inject top-k relevant past context at session start (off by default — tool-only is prompt-cache friendly).

Source

pub fn with_learning_loop(self, cfg: LearningConfig) -> Self

Enable the self-evolving learning loop: after a session that made >= cfg.nudge_interval tool calls, fork a review subagent (white-listed to cfg.tools) to update skills + memory from the transcript. Best-effort.

Source

pub fn with_response_format(self, fmt: ResponseFormat) -> Self

Set the default response format for all runs through this loop. See ResponseFormat. For typed deserialisation, prefer run_typed::<T>().

Source

pub fn with_response_schema( self, name: impl Into<String>, schema: Value, ) -> Self

Shortcut for with_response_format(ResponseFormat::JsonSchema { name, schema }). Accepts a raw serde_json::Value so callers can hand-roll the schema or pull it from schemars::schema_for!(T).

Source

pub async fn run( &self, task: Task, world: &mut World, ) -> Result<Outcome, HarnessError>

Source

pub async fn run_with_max_iters( &self, task: Task, world: &mut World, max_iters: u32, ) -> Result<Outcome, HarnessError>

Source

pub async fn run_typed<T>( &self, task: Task, world: &mut World, ) -> Result<T, HarnessError>
where T: DeserializeOwned + JsonSchema + 'static,

Run the agent and deserialise the terminal reply into T.

The schema for T is derived via schemars::schema_for!(T) and installed as ResponseFormat::JsonSchema for this run only — any pre-existing self.response_format is ignored. On success the returned T is parsed from Outcome::Done.text (or, on budget exhaustion, from Outcome::BudgetExhausted.last_text).

Errors:

  • HarnessError::Other if the model returns no text at all
  • HarnessError::Other if serde_json::from_str::<T>(text) fails — the original text is included in the message for debugging.
Source

pub async fn run_typed_with_max_iters<T>( &self, task: Task, world: &mut World, max_iters: u32, ) -> Result<T, HarnessError>
where T: DeserializeOwned + JsonSchema + 'static,

Like run_typed but with explicit max_iters.

Source

pub async fn run_with_response_format( &self, task: Task, world: &mut World, max_iters: u32, fmt: ResponseFormat, ) -> Result<Outcome, HarnessError>

Run with a one-off ResponseFormat override (doesn’t touch self).

Source

pub async fn run_with_seed_history( &self, task: Task, seed: Vec<Turn>, world: &mut World, max_iters: u32, ) -> Result<Outcome, HarnessError>

Like run_with_max_iters but seeds ctx.history with seed before the current user task is appended. Use this for multi-turn REPLs so prior conversation lives in ctx.history (where the Compactor can see it) instead of being concatenated into task.description (where it previously bypassed compaction entirely — see audit #2).

Auto Trait Implementations§

§

impl<M> !RefUnwindSafe for AgentLoop<M>

§

impl<M> !UnwindSafe for AgentLoop<M>

§

impl<M> Freeze for AgentLoop<M>
where M: Freeze,

§

impl<M> Send for AgentLoop<M>

§

impl<M> Sync for AgentLoop<M>

§

impl<M> Unpin for AgentLoop<M>
where M: Unpin,

§

impl<M> UnsafeUnpin for AgentLoop<M>
where M: UnsafeUnpin,

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<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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + 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: Sized + 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