lib/openagents/operational_log.ex

58e6347eeb72 · 1 KB

defmodule OpenAgents.OperationalLog do
  @moduledoc "Reduces failures to bounded, content-free codes before logging or receipting."

  @spec code(term()) :: String.t()
  def code(reason) when is_atom(reason), do: bounded(Atom.to_string(reason))
  def code({tag, _detail}) when is_atom(tag), do: bounded(Atom.to_string(tag))
  def code({tag, _detail, _more}) when is_atom(tag), do: bounded(Atom.to_string(tag))

  def code(%{__struct__: module}) when is_atom(module) do
    module |> Module.split() |> List.last() |> Macro.underscore() |> bounded()
  end

  def code(_reason), do: "other"

  @doc """
  The one bounded, content-free number a failure carries, when it has one.

  A code alone says a call failed; it cannot say whether the credential is
  wrong, the account is rate limited, or the provider is down — and those
  need different responses from an operator. An upstream HTTP status is the
  smallest thing that distinguishes them, and it is a status line rather than
  provider content, so it crosses the same boundary the code does.

  Anything that is not a plain HTTP status is `nil`: a detail that could carry
  a prompt, a key, or a body never reaches a log or a receipt through here.
  """
  @spec status(term()) :: pos_integer() | nil
  def status({_tag, status}) when is_integer(status) and status >= 100 and status <= 599,
    do: status

  def status(_reason), do: nil

  defp bounded(value), do: String.slice(value, 0, 64)
end