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
Changed
- The README, the tutorials, and the
Citedocs read the API key fromTYPESAFE_API_KEYinstead ofJEV_API_KEY. Cite itself reads no environment variable, so only code copied from the examples is affected.
0.2.0 - 2026-10-01
Added
concurrencyonCite.judge/4: the most requests in flight at once within a round, 4 by default. Given the same replies, the report is the same at any setting. Setconcurrency: 1to send one request at a time, as 0.1 did.
Changed
- A client that returns something outside its contract raises
RuntimeErrorinstead ofArgumentError.Cite.judge/4itself raisesArgumentErroronly on a bad argument, before any request. What the client raises passes through as is. - The client runs in a task process, even at
concurrency: 1. Logger metadata and process level carry over, and Cite carries nothing else: OpenTelemetry context, for one, does not. In the client,self()is the task, not the caller. Cite.Providerasks two more things of a provider.judge/2must be safe to call from several processes at once with the same handle. And it must not raise on a condition that concurrency makes routine, such as waiting for a connection. A custom client must be safe to call concurrently too, or be run atconcurrency: 1.- In a caller that traps exits, a crash in a process the client links to
now makes
Cite.judge/4exit with the same reason. As with a raise, the exit comes once the requests before it have answered, and it stops the rest as a raise does. Before, such a caller (a GenServer, say) received an:EXITmessage and the run carried on. A caller that doesn't trap exits still dies at once, through the link. - At
concurrencyabove 1, a raise mid-run comes once the requests before it have answered. Once a call raises, throws, or exits, no new request starts. A request before it still finishes, including the halves Cite sends when it is too large and any retries the client makes. One after it is stopped at once, but the provider may already have received and billed it. Cite.Provider.TypeSafewaits for a pooled connection with no time limit, instead of raising after 5 seconds. Apool_timeoutunderfinch:, inreq_optionsor the app'sReq.default_options/0, still sets one.Cite.Provider.TypeSafeapplies its:retry_delaycheck to the app'sReq.default_options/0as well asreq_options: a:retry_delayfrom either needs a:retryinreq_options. Aretry_delay: nilnow passes, as Req reads it as unset.- The RAG grounding tutorial runs at the default window: screening an answer's sentences together costs no more and makes no more mistakes than one at a time.
Fixed
Cite.source/2raises on shown meta whose value holds a key as both an atom and a string, such astags: %{k: 1, "k" => 2}withshow: [:tags], and on ashowthat names one key both ways. On the wire they were one key, and which value the model saw depended on map order.Cite.client/2raisesArgumentErroron an atom that is not a provider module, instead ofUndefinedFunctionError.Cite.client/2,Cite.source/2,Cite.judge/4, andCite.Provider.TypeSafe'snew/1raiseArgumentErroron options that are not a keyword list, such as[1, 2], instead ofFunctionClauseError.
0.1.1 - 2026-09-28
Added
- Tutorial: Checking RAG answers against their sources. It finds the sentences of a generated answer that its retrieved documents contradict or never state, with a filter for sentences that assert nothing.
- Tutorial: Filtering RAG retrieval results. It keeps the retrieved passages that answer a query, judging each query's candidates together.
- A roadmap for 0.2.0, marking each item planned, exploring, or not planned.
- A logo, shown in the docs sidebar, as the favicon, and beside the README heading.
Changed
- The guides say what one round-1 request holds, and that shown meta is
the only context a passage carries besides its text: a value every
passage shares, such as the question they are judged against, goes on
each passage. The
windowdocs say it takes any positive integer, including 1. - Writing policies defines
not_foragainst its own block'swhat, so it can go in anoblock as well as ayes. - Each tutorial opens by saying what you write and build, and what Cite does in between.
Security
- Mint, the HTTP client under Req, has three advisories fixed in 1.11.0
(EEF-CVE-2026-91043, EEF-CVE-2026-92103, EEF-CVE-2026-94194). Cite's own
lockfile now pins 1.11.0. Hex packages do not ship a lockfile, so run
mix deps.update mintin your project.
0.1.0 - 2026-09-27
Added
use Cite.Policy: a policy declared once in a module, built on Spark. Filters, concerns (screened directly with a detect and an optional confirm, or built from factors with roles and checks), factors, and Score or Choice descriptors. A passage is evidence for every concern it matches. Questions name what they read by placeholder ({passage},{household}) and Cite replaces each with a path in the request. Any question may add a one-linefocus. Every mistake in a policy is a compile error.- A DSL reference in
Cite.Policy's docs, generated from the DSL by Spark. Cite.source/2: the caller's passages, kept byte for byte, withas:for the word they sit under andshow:for the meta the model sees.Cite.judge/4: two fixed rounds. A screen of every passage for every detect in windows, fixed rules that gather matches into findings, and one judgment per finding on all of its evidence, gated by a review band. Options:threshold,review_band,window. A client, source, policy, or options of the wrong kind raiseArgumentError.- Replies are checked before they count: a reply that skips a question or answers out of range makes its whole request an error, never a verdict. Errors are reported beside the findings, one per failed request.
Cite.Report,Cite.Finding,Cite.Citation,Cite.Passage, andCite.Erroras the outputs, encodable with Jason. A finding carries its verdict, the raw answers to its checks and descriptors, the passages it cites and those its confirm dropped; the report keeps every round-1 score, token usage, and the model ids that answered.Cite.Providerbehaviour andCite.Provider.TypeSafe, a Req client for TypeSafe System One;Cite.client/2builds the client functionjudge/4takes. A request's"state"may holdCite.Wire.Objectvalues, JSON objects that keep their key order. The TypeSafe client takesapi_key,model,base_url,max_retry_delay, andreq_options. It retries 429, 529, 500–504, and connection failures up to three times, honouringRetry-After, with delays capped at 30 seconds; timeouts are not retried.- Round-1 windows over the provider's size cap (
{:error, :request_too_large}) are halved and retried; only a lone passage still over the cap becomes an error. A round-2 request refused as too large is that finding's error. - Guides: Writing policies, and How judging works. Tutorials, each building a policy from scratch: Triaging logs, Finding sponsor segments, Labelling allergens in recipes, and Checking support calls against procedure.
- Stability tiers, named in the README and grouping the docs: Core API (the SemVer contract), Providers, and Internal.
- Requires Elixir
~> 1.18.