# enact-runner
> Robust agent loop runner for Enact — retries, compaction, multi-format parsing.
## What Is This?
`enact-runner` is the **"missing middle"** between the apps (`cli`, `api`) and `enact-core`'s deterministic kernel. It implements the robust agent loop mandated by the technical specs but never built.
## Quick Start
```rust
use enact_runner::{AgentRunner, DefaultAgentRunner, RunnerConfig, LoopOutcome};
// Default config (max 25 iterations, compaction at 40 messages)
let mut runner = DefaultAgentRunner::default_new()
.add_tool(my_search_tool)
.add_tool(my_read_file_tool);
let outcome = runner.run(&my_llm_callable, "user input").await?;
match outcome {
LoopOutcome::Completed(output) => println!("Done: {}", output),
LoopOutcome::MaxIterationsReached { .. } => println!("Hit limit"),
LoopOutcome::Cancelled => println!("Cancelled"),
LoopOutcome::TimedOut { .. } => println!("Timed out"),
}
```
## Presets
```rust
// Short interactive sessions (10 iterations, 2 min timeout)
let config = RunnerConfig::interactive();
// Long-running background agents (100 iterations, 1 hour timeout)
let config = RunnerConfig::long_running();
```
## Features
| **Multi-format parsing** | Parses tool calls from JSON, XML, and Markdown |
| **Retry with backoff** | Exponential backoff for rate-limits and transient errors |
| **Error classification** | Distinguishes retryable (rate-limit, network) from fatal (auth, invalid) |
| **Auto-compaction** | Summarizes older messages when history exceeds threshold |
| **Checkpointing** | Saves state at configurable intervals |
| **Cancel/Pause** | Delegates to `enact-core::Runner` for cancel/pause signals |
| **Stream events** | Emits `StreamEvent`s for real-time observability |
## Module Structure
```
src/
├── lib.rs # Module root + re-exports
├── config.rs # RunnerConfig, RetryConfig, presets
├── loop_driver.rs # AgentRunner::run() — the core loop
├── parser.rs # Multi-format tool call parsing
├── compaction.rs # Auto context summarization
└── retry.rs # Error classification + backoff
tests/
└── integration.rs # Full loop integration tests
```
## Testing
```bash
# All tests (31 total)
cargo test -p enact-runner
# Only integration tests
cargo test -p enact-runner --test integration
# Specific test
cargo test -p enact-runner test_retry_on_transient_error
```