# Public API
`ActorState` adds provider-free scheduling to `Chatend`. It reexports `BoxContent`, `BoxId`, `ChatBox`, `DispatchCall`, `ProviderCall`, `RecoveryError`, `ToolCallId`, and `TransitionError`.
```rust
let mut state = ActorState::new(false);
state.accept_user("hello".into())?;
let start = state.begin_inference()?.unwrap();
let calls = state.append_stage(start.job, "thinking".into(), vec![])?;
state.complete_inference(start.job, "answer".into())?;
# Ok::<(), StateError>(())
```
`begin_inference` opens a Chatend provider round without adding a box. Its job IDs are process-local and monotonic; `frontier` is the previous last box and `attempt` is shared with the active state. `append_stage` validates the job and returns canonical, immediately launchable calls. `complete_inference` finishes the round. Arrivals while a round is active are queued by Chatend and coalesce into one follow-up schedule after completion; idle arrivals schedule immediately. Call-only stages do not schedule.
`stall_inference` leaves the round open. `restart` makes that same round ready under a fresh job, without another `start_round`, while retaining its frontier. `halt` is first-write until taken; taking a halt-only message leaves the state quiet unless work was already forced. `recover` validates boxes through Chatend, returns idle state with fresh job numbering, and preserves future BoxId continuity.
No persistence, events, serde, runtime, provider, filesystem, or dispatch execution is included.