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

Breaking

  • Removed the reserved persistence field from Agentix.Conversation.Config (documented as unused in 0.3.0; it was never consulted). Config.new/1 now raises on a :persistence key — persistence is configured at the application level only (config :agentix, :persistence), and ephemeral one-shots clean up via Agentix.Persistence.delete_conversation/1.

[0.3.0] - 2026-07-07

Added

  • Per-conversation api_key on Agentix.Conversation.Config — a string or a 0-arity resolver fun (re-evaluated on every model call) passed to the provider as a per-request option. nil keeps ReqLLM's own key resolution. The Ecto persistence adapter's settings sanitizer drops it, so key material never lands in a durable row; a conversation revived from persisted settings alone is key-less and the host must re-pass a fresh config:.
  • Agentix.Conversation.stop/1 — public verb to release an idle conversation's agent process without ending the conversation (persisted events remain; the next ensure_started/2 revives it). Replaces hosts reaching into Agentix.Registry / Agentix.ConversationSupervisor internals.
  • {:turn_failed, turn_ref, reason} live event — provider/stream failures now get their own terminal event carrying the reason. Previously they broadcast the same {:cancelled, turn_ref} as a user-initiated cancel, so consumers could not distinguish "your key/provider failed" (e.g. an auth rejection) from "you cancelled".

Changed

  • A per-conversation api_key resolver fun is now evaluated inside the monitored streaming task: a raising resolver fails the turn ({:turn_failed, …}) instead of crashing the conversation's agent process.

  • The ETS persistence owner now starts unconditionally (previously only when ETS was the app-configured adapter), so ETS is usable in tests and tools regardless of the app default.

  • Config.persistence is documented as Reserved: the agent persists through the application-level adapter only; the field was never consulted and the old doc implied otherwise.

  • Agents now trap exits: Conversation.stop/1 and supervisor shutdown drain the in-flight callback before terminating, so an agent mid-write to durable persistence is never killed between statements (previously a stop could sever a checked-out DB connection mid-query).

Breaking

  • New required Agentix.Persistence behaviour callback delete_conversation/1 (implemented by both bundled adapters): removes a conversation and everything under it (events, summaries, tool calls, audit rows) — ephemeral one-shot tasks call it after reading usage so throwaway conversations never accumulate. Third-party adapters must implement it.
  • Turns that fail on a provider/stream error no longer emit {:cancelled, turn_ref} — subscribe to {:turn_failed, turn_ref, reason} for that terminal. {:cancelled, …} is now exclusively user-initiated.

0.2.0 - 2026-06-25

Added

  • Provider retry & backoff — a per-conversation retry policy on Agentix.Conversation.Config (%{max_attempts, base_ms, max_ms} or false). Transient pre-stream failures (HTTP 429, 5xx, connection drops) are retried with exponential backoff + jitter, honoring a retry-after header (capped at 60s); 4xx and unrecognized errors fail fast. A failure after the first streamed token is never retried. Classification/backoff live in the new public Agentix.Retry. Each retry emits a [:agentix, :turn, :retry] telemetry event.
  • Structured output — make the model return typed data conforming to a schema. Pass schema: to Agentix.Conversation.send_message/4 (one-shot) or set response_format on the config (default); schema: false opts out per turn. The parsed object is surfaced via Agentix.object/1 and the Agentix.Chat :last_object assign, and persisted in the assistant message's metadata["object"] (no migration). A schema turn is terminal (the tool loop is skipped). Agentix.Provider.ReqLLM branches to ReqLLM.stream_object/4.
  • Agentix.Test.error/2, Agentix.Test.transport_error/1, and a :object option on Agentix.Test.completion/2 for driving retry and structured-output scenarios with the mock provider.
  • New guide: Reliability & structured output.

0.1.0 - 2026-06-25

First public release.

Added

  • Agent runtime — one event-sourced :gen_statem per conversation (Agentix.Conversation), with non-blocking streaming turns, in-process tool execution, and mid-turn cancellation. Conversations are started on demand via Agentix.Conversation.ensure_started/2 and survive process death.
  • Provider seamAgentix.Provider behaviour with a streaming + cancel + finalize contract; Agentix.Provider.ReqLLM adapts ReqLLM's canonical typed model and provider abstraction.
  • Tools & HITL — an explicit executor model (:server, :human, :client, :provider) with gated approval, durable suspension into awaiting_input, and a public, socket-independent Agentix.resolve/4 (LiveView, webhook, job, or timeout). Suspended turns revive from durable state.
  • Hook pipeline — per-turn pre/post hooks (Agentix.Hook), parallel append-only injections with a token reserve, halt semantics, and a per-chunk stream-transformer seam.
  • Compaction — reducer pipeline (tool-result stubbing, sliding window, async cumulative summarization) gated by a token budget, behind a pluggable Agentix.Tokenizer behaviour (default char/4 heuristic, no extra dependency).
  • Persistence — the Agentix.Persistence behaviour with two adapters sharing one conformance suite: Agentix.Persistence.ETS (default, no database) and Agentix.Persistence.Ecto (Postgres, kill-and-resume, optional Oban-backed suspension expiry). Both LiveView and Ecto/Oban are optional dependencies.
  • Headless LiveView layerAgentix.Chat (use macro + on_mount projection of the live-event plane onto assigns, streamed deltas to a JS hook), optional ownable Agentix.Components, and mix agentix.gen.components / mix agentix.gen.migration generators.
  • Live-event union — a typed event plane broadcast over Phoenix.PubSub (Agentix.Notifier behaviour; PubSub default, None no-op) consumable by any transport.
  • Test storyAgentix.Test assertions and a scriptable Agentix.Test.MockProvider for driving conversations deterministically with no API key.
  • Modern tooling: Credo, Dialyxir, Styler, ExCoveralls, MixAudit, ExDoc, and a mix check quality gate.