# `JidoGralkor.ContextRotator`
[🔗](https://github.com/elimydlarz/jido_gralkor/blob/main/lib/jido_gralkor/context_rotator.ex#L1)

Memory consolidation for a long-lived Jido agent.

Rotation = flush the active Gralkor session to long-term memory, then
install a fresh `Jido.Thread` on the agent (so the next turn runs under
a new `session_id`) and replace the ReAct strategy's projected context
with a compacted version (system prompt + summary of pre-rotation turns
+ the most recent N turns verbatim). The agent process is never stopped
— any async work it supervises survives.

Consumers call `rotate_now/2` directly to trigger a rotation (e.g. on
a `/new` chat command). For periodic rotation, wrap `rotate_now/2` in
a timer loop (a separate GenServer in the consumer, or a Jido sensor).

This module talks to the AgentServer through `Jido.AgentServer.call/3`
and `Jido.AgentServer.cast/2` so all state mutations happen inside the
agent's own process — no parallel state in this module.

# `opts`

```elixir
@type opts() :: [flush_timeout_ms: pos_integer(), keep_last_n: non_neg_integer()]
```

# `rotate_now`

```elixir
@spec rotate_now(pid(), opts()) :: :ok | {:error, term()}
```

Rotate the agent's active session immediately.

On success: the buffered turns are flushed to long-term memory and a
fresh Jido thread is installed (new session id). The rotated thread is
seeded with two slices:

  1. The most recent `:keep_last_n` entries that existed BEFORE the
     flush — for short-range conversational continuity (these are
     in long-term memory now; we keep them for the LLM's immediate
     working set).
  2. Any thread entries appended DURING the flush — those represent
     turns that weren't part of the just-flushed batch (an in-flight
     turn arriving while the rotation was running). They're preserved
     so the rotator never drops un-captured work.

Entries that existed pre-flush and aren't in the `:keep_last_n` tail
are dropped from the in-memory context — they've been moved to
long-term memory, recall is the path back.

Returns `:ok` on success, `{:error, reason}` if the flush fails (in
which case the active thread and session id are unchanged so the next
attempt sees the same buffer).

Options:

  * `:flush_timeout_ms` — timeout passed to `Gralkor.Client.flush_and_await/2`.
    Default `30000`.
  * `:keep_last_n` — number of most-recent pre-flush entries to retain
    in the rotated thread for continuity. Default
    `4`. Pass `0` to drop everything that was
    flushed (preserving only in-flight entries).

When the agent has no committed thread yet, returns `:ok` without any
side effects.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
