Finds what a policy describes in a document and cites the caller's own passages behind each finding, unchanged.

Three steps:

defmodule MyApp.Riddles do                       # declare the policy once
  use Cite.Policy

  concern :riddle do
    detect do
      question "Does {passage} pose a riddle?"
      yes "A question asked to be puzzled over."
      no "A plain question, a statement, or a remark."
    end
  end
end

source = Cite.source(lines)                      # hand over the passages
report = Cite.judge(client, source, MyApp.Riddles) # judge the source against it

judge/4 runs two fixed rounds: a screen of every passage for every detect, then one judgment per finding. A decision model answers typed questions about the passages; it never writes text and never sees a passage the caller did not list.

The client

client/2 builds one from a Cite.Provider module. Any 1-arity function of the same shape works in its place:

request -> {:ok, verdict} | {:error, reason}

request is %{"state" => map(), "questions" => map()}; a value in "state" may be a Cite.Wire.Object, a JSON object that keeps its keys in order. verdict is %{answers: map(), usage: usage | nil}, plus :model, the versioned id that answered, when the provider reports it.

Summary

Functions

A client backed by provider, a module implementing Cite.Provider; opts are the provider's. Build it once, where the credentials live, and pass it in.

Judges source against policy_module, a module that uses Cite.Policy. Raises ArgumentError before any request on an option it cannot use or a module that is not a policy, and mid-run when the client returns something outside its contract.

The source: the caller's passages, each a text or %{text: text} with optional :id and :meta. See Cite.Source.

Types

client()

@type client() :: (map() -> {:ok, verdict()} | {:error, term()})

usage()

@type usage() :: Cite.Report.usage()

verdict()

@type verdict() :: %{
  :answers => map(),
  :usage => usage() | nil,
  optional(:model) => String.t()
}

Functions

client(provider, opts \\ [])

@spec client(module(), keyword()) :: client()

A client backed by provider, a module implementing Cite.Provider; opts are the provider's. Build it once, where the credentials live, and pass it in.

client = Cite.client(Cite.Provider.TypeSafe, api_key: System.fetch_env!("JEV_API_KEY"))

judge(client, source, policy_module, opts \\ [])

@spec judge(client(), Cite.Source.t(), module(), keyword()) :: Cite.Report.t()

Judges source against policy_module, a module that uses Cite.Policy. Raises ArgumentError before any request on an option it cannot use or a module that is not a policy, and mid-run when the client returns something outside its contract.

Options

  • :threshold - The round-1 score a filter, factor, or detect must exceed, from 0 to 1. It decides which passages are gathered, and a finding's confirms read every passage gathered with it, so it changes verdicts as well as recall. Below 0.5, measured on transcripts, it invents findings in concerns with no match at 0.5 and multiplies review load. The default value is 0.5.

  • :review_band - {low, high}, 0 <= low < high <= 1. At or below low a passage is dropped and a check fails; at or above high either holds. The default value is {0.4, 0.6}.

  • :window (pos_integer/0) - Passages per round-1 request. The default value is 40.

source(units, opts \\ [])

@spec source([String.t() | map()], keyword()) :: Cite.Source.t()

The source: the caller's passages, each a text or %{text: text} with optional :id and :meta. See Cite.Source.

Options

  • :as - The word the passages sit under in every request, such as "utterances". It is part of every path the model reads, so it must be UTF-8 with no whitespace, ., backtick, [, or ]; passage ids follow the same rule. The default value is "passages".

  • :show - The meta keys the model sees beside id and text, as given in meta (:speaker finds %{speaker: _}, not %{"speaker" => _}). It may not name id or text. The default value is [].