# `Vibe.Context.Compactor`
[🔗](https://github.com/elixir-vibe/vibe/blob/v0.2.3/lib/vibe/context/compactor.ex#L1)

LLM-driven context compaction for long sessions.

Uses token estimation (`chars / 4`) to find optimal cut points rather than
fixed event counts. Walks backwards from the newest events, accumulating
tokens until `keep_recent_tokens` is reached. The cut always lands on a
user or assistant message boundary — never mid-tool-result.

# `compact_result`

```elixir
@type compact_result() :: %{
  summary: String.t(),
  tokens_before: non_neg_integer(),
  kept_events: [Vibe.Trajectory.t()],
  details: map()
}
```

# `compact`

```elixir
@spec compact(keyword()) :: {:ok, compact_result()} | {:error, term()}
```

# `compact`

```elixir
@spec compact(
  [Vibe.Trajectory.t()],
  keyword()
) :: {:ok, compact_result()} | {:error, term()}
```

# `find_cut_point_for_test`

```elixir
@spec find_cut_point_for_test([Vibe.Trajectory.t()], non_neg_integer()) ::
  {[Vibe.Trajectory.t()], [Vibe.Trajectory.t()]}
```

# `snap_to_boundary_for_test`

```elixir
@spec snap_to_boundary_for_test([Vibe.Trajectory.t()]) :: [Vibe.Trajectory.t()]
```

# `summarize`

```elixir
@spec summarize([Vibe.Trajectory.t()], String.t() | nil, keyword()) ::
  {:ok, String.t()} | {:error, term()}
```

# `turn_prefix_summary`

```elixir
@spec turn_prefix_summary(
  [Vibe.Trajectory.t()],
  keyword()
) :: {:ok, String.t()} | {:error, term()}
```

---

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