kcode-k1-chat-state 0.2.3

Synchronous chat actor state and ordered job tracking
Documentation
# Public API

```rust
use std::sync::{Arc, atomic::AtomicU8};
use kcode_k1_chat_core::{ChatError, ChatView};

pub struct ActorState { /* private fields */ }

impl ActorState {
    pub fn new(primary: String, force: bool) -> Self;
    pub fn view(&self) -> ChatView;
    pub fn halted(&self) -> bool;
    pub fn halt(&mut self, text: String) -> bool;
    pub fn take_halt(&mut self) -> Option<String>;
    pub fn append_pending(&mut self, text: String);
    pub fn restart(&mut self) -> Result<(), ChatError>;
    pub fn begin_inference(&mut self) -> Option<(u64, String, Arc<AtomicU8>)>;
    pub fn finish_inference(&mut self, job: u64) -> bool;
    pub fn commit_output(&mut self, text: &str);
    pub fn commit_output_with_deferred(&mut self, text: &str, deferred: &str);
    pub fn force_inference(&mut self);
    pub fn begin_tool(&mut self, name: String) -> u64;
    pub fn begin_worker(&mut self, llm: String) -> u64;
    pub fn begin_compaction(&mut self) -> (u64, String);
    pub fn reject_compaction_batch(&mut self);
    pub fn begin_batch(&mut self);
    pub fn apply_tool_replies(&mut self, entries: Vec<(usize, u64, String, bool)>, finished: bool);
    pub fn complete_action(&mut self, job: u64, text: String);
    pub fn apply_append_update(&mut self, job: u64, identity: u64, text: String);
    pub fn accept_activity_update(&mut self, job: u64, identity: u64) -> bool;
    pub fn complete_compaction(&mut self, job: u64, frozen: String, result: Result<String, String>);
    pub fn quiet(&self) -> bool;
}
```

`ActorState` synchronously owns chat text, delta boundaries, jobs, accepted update identities, attempts, batching, compaction, force, and halt state. The caller provides exclusive `&mut ActorState` access. The only concurrently observable value is each inference attempt through its `Arc<AtomicU8>` using relaxed operations.

Job IDs start at one, increase monotonically, and panic if exhausted. Results and updates must use IDs returned by their matching begin methods. Callers begin at most one compaction, use one output-commit method for the current inference, complete it with `finish_inference`, and bracket immediate tool replies with one `begin_batch` and a final `finished=true` application. Batch entries use original call indices and tool job IDs. The batch cursor remains a UTF-8 boundary because it advances only by byte lengths of strings inserted there. Stale completion and compaction IDs and duplicate or stale update identities have no effect. Restart errors do not partially mutate state.

- `new` creates state with the supplied primary and force flag, sent boundary zero, and no pending text, history, jobs, active operation, batch, or halt. Performance: Not yet benchmarked; work and allocation are constant apart from retaining the supplied primary.
- `view` clones text and returns actions in increasing job-ID order, loading inference attempts with relaxed ordering. Performance: Not yet benchmarked; work and allocation are linear in retained text, history, and live jobs.
- `halted` reports whether halt text is installed. Performance: Not yet benchmarked; work and allocation are constant.
- `halt` installs only the first halt and reports whether installation occurred. Performance: Not yet benchmarked; work and allocation are constant apart from retaining accepted text.
- `take_halt` removes and returns the halt text. Performance: Not yet benchmarked; work and allocation are constant.
- `append_pending` concatenates exact text without a separator. Performance: Not yet benchmarked; amortized work and added memory are linear in appended bytes.
- `restart` returns `NotStalled` without a halt and `Busy` while a job or batch cursor is live; otherwise it appends pending to primary, clears pending, resets the sent boundary, forces inference, and clears the halt. Performance: Not yet benchmarked; work is linear in pending bytes and allocation follows primary growth.
- `begin_inference` returns `None` while halted, while inference, compaction, or a batch is active, or when neither forced nor pending; otherwise it moves pending into primary, clears force, creates an attempt initialized to one and an ordered job, and returns the job, exact `primary[sent..]` delta, and shared attempt. Performance: Not yet benchmarked; work and allocation are linear in pending and returned delta bytes plus logarithmic job insertion.
- `finish_inference` clears and removes only the matching active inference. Performance: Not yet benchmarked; work is logarithmic in live jobs with no input-sized allocation.
- `commit_output` appends exact output and advances the sent boundary past it. Performance: Not yet benchmarked; amortized work and added memory are linear in output bytes.
- `commit_output_with_deferred` appends exact output, advances the sent boundary past only that output, then appends exact deferred text without forcing inference. Performance: Not yet benchmarked; amortized work and added memory are linear in output plus deferred bytes.
- `force_inference` sets the force flag. Performance: Not yet benchmarked; work and allocation are constant.
- `begin_tool` allocates an ordered tool action. Performance: Not yet benchmarked; work is logarithmic in live jobs and retained memory includes the supplied name.
- `begin_worker` allocates an ordered worker action. Performance: Not yet benchmarked; work is logarithmic in live jobs and retained memory includes the supplied model name.
- `begin_compaction` allocates and activates an ordered compaction action and returns a clone of primary. Performance: Not yet benchmarked; work and allocation are linear in primary bytes plus logarithmic job insertion.
- `reject_compaction_batch` inserts `compaction must be the sole call` at pending byte zero and forces inference. Performance: Not yet benchmarked; work is linear in shifted pending bytes and allocation follows pending growth.
- `begin_batch` starts the tool-reply insertion cursor at byte zero. Performance: Not yet benchmarked; work and allocation are constant.
- `apply_tool_replies` does nothing without a batch; otherwise it sorts by call index, concatenates exact replies, removes entries marked complete, inserts at the cursor, forces inference, and advances or clears the cursor according to `finished`. Performance: Not yet benchmarked; work is `O(E log E)` plus reply and shifted-pending bytes, with temporary memory linear in reply bytes.
- `complete_action` removes a live action and only then appends exact text to pending and forces inference. Performance: Not yet benchmarked; work is logarithmic in live jobs plus amortized linear work in appended bytes.
- `apply_append_update` accepts only a live job and fresh identity, then appends exact text and forces inference. Performance: Not yet benchmarked; identity acceptance is expected amortized constant time and append work and memory are linear in text bytes.
- `accept_activity_update` records and accepts only a fresh identity for a live job without changing text or force. Performance: Not yet benchmarked; expected amortized work and retained memory are constant per accepted identity.
- `complete_compaction` ignores a non-active ID; matching success records frozen in history, replaces primary, appends and clears pending, resets the sent boundary, and forces, while matching failure appends error and pending to the old primary, preserves history and the sent boundary, and forces. Performance: Not yet benchmarked; work and allocation are linear in moved and appended text plus logarithmic job removal.
- `quiet` requires no jobs, pending text, force, or batch cursor; halt is independent. Performance: Not yet benchmarked; work and allocation are constant.