Skip to main content

oharness_loop/
loop_trait.rs

1//! The `Loop` trait + `LoopContext` (ยง12.1).
2
3use async_trait::async_trait;
4use oharness_core::{
5    AgentError, ApprovalChannel, BudgetHandle, Cancellation, RunOutcome, ScopedEmitter, Task,
6};
7use oharness_critic::{CompositeCritic, CriticTrigger};
8use oharness_llm::Llm;
9use oharness_memory::MemoryPolicy;
10use oharness_tools::context::Workspace;
11use oharness_tools::ToolSet;
12use std::sync::Arc;
13
14#[async_trait]
15pub trait Loop: Send + Sync {
16    async fn run(&self, task: Task, ctx: &LoopContext) -> Result<RunOutcome, AgentError>;
17}
18
19pub struct LoopContext {
20    pub llm: Arc<dyn Llm>,
21    pub tools: Arc<dyn ToolSet>,
22    pub memory: Arc<dyn MemoryPolicy>,
23    /// Optional critic (usually a [`CompositeCritic`] for multi-critic
24    /// setups). `None` disables all critic invocations regardless of
25    /// trigger setting.
26    pub critics: Option<Arc<CompositeCritic>>,
27    pub critic_trigger: CriticTrigger,
28    pub events: ScopedEmitter,
29    pub budget: Arc<dyn BudgetHandle>,
30    pub cancellation: Cancellation,
31    pub approval: Arc<dyn ApprovalChannel>,
32    /// Optional per-run workspace. Propagated into
33    /// `ToolContext.workspace` for every tool call so the shipped
34    /// `fs` / `bash` tools (which already consult
35    /// `ToolContext.workspace_path()`) scope filesystem access to
36    /// this directory. `None` leaves tools unscoped (they fall back
37    /// to cwd).
38    pub workspace: Option<Arc<Workspace>>,
39    pub revision_depth_cap: u32,
40    pub max_turns: u32,
41}