Harness
Think→Act loop, state machine, stop-hooks, context budget, and emergency compaction.
Harness
The AgentHarness drives the Think → Act loop for all Gateway chat requests. It is constructed by the Orchestrator and receives pre-resolved dependencies (SessionService, ToolService, Sandbox, AiProvider).
Location: src/harness/
Migration complete: The legacy
src/agent_loop/directory was deleted in Phase 7 (2026-04-21). All agent execution — includingSubagentTool— now routes through Orchestrator → Harness.
Inner Loop Diagram
┌─────────────────────────────────────────┐
│ AgentHarness │
├─────────────────────────────────────────┤
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │PREPARE │──▶│ THINK │──▶│RESOLVE │ │
│ │• Budget│ │ • LLM │ │• Parse │ │
│ │• Context│ │ • Decide│ │• Decision││
│ │• Preflight│ └────────┘ └────┬───┘ │
│ └────────┘ │ │
│ ┌────┴───┐ │
│ │ ACT │ │
│ │• Execute│ │
│ │• Tools │ │
│ └────┬───┘ │
│ │ │
│ ┌────┴───┐ │
│ │FINALIZE│ │
│ │• Eval │ │
│ │• Compress││
│ │• Decision││
│ └────────┘ │
└─────────────────────────────────────────┘Core Structure
pub struct AgentHarness {
deps: HarnessDeps, // All dependencies injected at construction
hit_limit: AtomicBool, // Set when context budget forces early exit
}AgentHarness is stateless — all mutable state lives in SessionService. Dependencies are injected at construction via HarnessDeps:
State Machine
The Harness trait defines the Think→Act contract. TurnState is a simple binary outcome:
| Variant | Meaning |
|---|---|
Continue | The session should run another Think→Act turn |
Done | The session is complete; no further turns needed |
The outer loop (Harness::run) repeatedly calls run_turn until it returns Done or the cancel token fires.
Source Map
| File | Role |
|---|---|
src/harness/agent.rs | AgentHarness — concrete Think→Act implementation |
src/harness/trait_def.rs | Harness trait + TurnState + HarnessError |
src/harness/deps.rs | HarnessDeps — dependency bundle |
src/harness/callback.rs | HarnessCallback trait for event streaming |
src/harness/loop_callback.rs | LoopCallback / NoopCallback |
src/harness/trace.rs | Trace event types |
src/harness/trace_sink.rs | TraceSink trait for observability |
src/harness/chain_context.rs | Chain-of-thought context management |
Sleep Inhibitor
Each Think→Act turn acquires an IOPMAssertion of type PreventUserIdleSystemSleep with the reason string "Aleph agent loop". The assertion is held by an RAII InhibitorGuard whose Drop implementation releases it the moment the turn returns. Long-running agent turns can no longer be silently cut short by macOS putting the host to sleep mid-flight.
The guard is acquired at the start of run_turn in src/harness/agent.rs and released automatically when the function returns, whether it succeeds, returns an error, or is cancelled.
To verify that an assertion is active while a turn is in flight:
pmset -g assertions | grep "Aleph agent loop"The assertion disappears from the list the moment the turn completes.
Implementation files:
PowerCapabilitytrait:desktop/shared/src/traits/power.rs- macOS IOPMAssertion FFI:
desktop/macos/src/sleep_inhibitor.rs - Agent loop wiring:
src/harness/agent.rs::run_turn
See Also
- Thinker — LLM interaction layer
- Dispatcher — Task orchestration
- Session Service — Append-only event log
- Sandbox — Execution environment