All notable changes to this project will be documented in this file.
The format is based on Keep a Changelog and this project adheres to Semantic Versioning.
Unreleased
0.4.0 - 2026-05-18
Changed
Omni.Session.Storeis now a struct — stores are initialised viaStore.init/1(accepts{module, keyword}, a bare module, or an already-initialised%Store{}).Session.start_link/1andManager.start_link/1callinit/1internally, so callers can still pass tuples. Adapters must implement the newc:init/1callback.Omni.Session.Store.FileSystemrenamed toOmni.Session.Stores.FileSystem— follows the convention that behaviour modules are singular (Store) and implementation namespaces are plural (Stores). Also::base_pathoption renamed to:base_dir;:base_dirmust be absolute;:otp_appoption removed (resolve app-relative paths before constructing the store).
0.3.1 - 2026-05-12
Changed
omnidependency relaxed to~> 1.3— allows any1.x >= 1.3to avoid version clashes with downstream packages tracking newer1.xreleases.
0.3.0 - 2026-05-01
This release introduces the Session and Manager layers on top of Omni.Agent — conversation lifetime, a branching message tree, pluggable persistence, pub/sub, and multi-session supervision.
Added
Omni.Session— GenServer wrapping a linkedOmni.Agentwith session identity, a branching message tree, pluggable storage, and pub/sub.start_link/1supportsnew: :auto | binary()andload: binary()modes; the public API covers turn passthroughs, tree navigation, branching (regen / edit-next-user / new-root), titles, subscribers with:controller | :observermodes, and optional idle-shutdown.Omni.Session.Manager—use-pattern Supervisor for multi-session lifecycle. Apps define their own Manager module (use Omni.Session.Manager, otp_app: :my_app) and drop it into a supervision tree. Handles create / open / close / delete,list_open, and per-Manager pub/sub over a live cross-session feed of session status, title, and lifecycle events.Omni.Session.Store— persistence contract (behaviour + dispatch).Omni.Session.Store.FileSystemships as the reference adapter; sessions live in<base_path>/<id>/asnodes.jsonl+session.json.Omni.Session.Tree— pure-data branching message tree with auto-assigned node IDs, navigation, andEnumerableover the active path. The data structure backing Session's conversation state.- New Agent events —
:message(per message appended),:state(perset_statemutation), and:status(per transition, fires before its derived event). Session forwards all three re-tagged.
Changed
Agent
init/1shape — now receives the fully-resolved%State{}and returns{:ok, state} | {:error, term}. Callbacks can set any field, including defaults for:systemand:tools.Agent status
:runningrenamed to:busy— vocabulary is now:idle | :busy | :paused. Status-gated operations return the current status atom as their error reason (e.g.{:error, :busy}).Agent
:stopand:continueevents collapsed into:turn— now{:agent, pid, :turn, {:stop | :continue, response}}. Both variants commit pending messages tostate.messages, so every:turnevent is a reliable commit point.- Per-step and per-turn response messages —
:step.responsecarries only that step's messages;:turn.responsecarries only that turn's committed messages and usage. Prevents double-counting for subscribers that persist per-turn. omnidependency bumped to~> 1.3.0— hex release containingOmni.Codec, used byFileSystemto serialise messages, usage, and opts.
Fixed
turn_usagereset across continuations —turn_usagewasn't cleared when a turn ended with:continue, so the next turn's:turnevent double-counted usage.- Tool-result ordering — when an assistant message contained multiple
%ToolUse{}blocks, the resulting tool-result user message could come out of order. Results are now reassembled in tool-use order, insensitive to decision type and to sync-vs-resume and parallel-execution arrival order.
0.2.0 - 2026-04-02
Added
:stepevent —{:agent, pid, :step, %Response{}}emitted after each LLM request-response completes, giving consumers per-step visibility into multi-step turns.
Changed
:doneevent renamed to:stop—{:agent, pid, :done, response}is now{:agent, pid, :stop, response}. The:continueevent retains the same shape. Both event names now directly mirror thehandle_turn/2callback return values (:stopor:continue).
Fixed
- Structured output not propagated to response — when using the
output:option with a schema, the parsedoutputfrom the LLM response was not being set on theResponsedelivered with:stopevents. The output is now correctly carried through from the underlying step response.
0.1.0 - 2026-03-24
Initial release of Omni Agent as a standalone package, extracted from the omni package where it previously lived as Omni.Agent. The agent system was separated to allow the stateless LLM API layer (omni) to remain stable while the agent layer continues to evolve through rapid experimentation.
The agent internals were simplified — the loop hierarchy was flattened from three levels (round > turn > step) to two (turn > step), several callbacks were renamed for clarity, and the tool use flow was unified so that every tool use passes through handle_tool_use regardless of whether it has a handler.
Added
Omni.Agent— GenServer-based building block for stateful, multi-turn LLM conversations with lifecycle callbacks, tool approval with pause/resume, and prompt queuing/steering.Omni.Agent.State— public state struct passed to all callbacks.
Changed (relative to Omni.Agent in omni)
- Two-level loop model — "round" concept removed. A turn (prompt to done) contains one or more steps (LLM request-response cycles). Continuations stay within the same turn.
handle_stoprenamed tohandle_turn— fires when the model completes without executable tools.handle_tool_callrenamed tohandle_tool_use— aligns with%ToolUse{}and Anthropic terminology.:turnevent renamed to:continueevent — avoids collision with "turn" as the top-level concept.- Unified tool use flow — all tool uses flow through
handle_tool_usewith four return variants (:execute,:reject,:result,:pause). No morehas_executable_tools?all-or-nothing check.