AI.Endpoint behaviour (fnord v0.9.30)

View Source

API endpoint abstraction.

This behaviour centralizes HTTP JSON POST calls via Http.post_json/3 and applies provider-agnostic retry/backoff. Provider endpoint modules implement endpoint_path/0 and a small error classifier that inspects the raw HTTP/transport outcome and returns a normalized decision (:ok, {:retry, reason, wait_ms} or {:fail, reason, human}), allowing provider-specific error shapes (e.g., OpenAI, Venice, Cloudflare plaintext) to be handled without leaking details into this module.

Callers implement endpoint_path/0 and then call AI.Endpoint.post_json/3.

Summary

Functions

Perform a JSON POST request against the endpoint module's endpoint_path/0. Retries up to 3 times when the server indicates throttling.

The fixed retry limit for API calls.

Types

endpoint()

@type endpoint() :: module()

headers()

@type headers() :: [{String.t(), String.t()}]

http_error()

@type http_error() :: {:http_error, {http_status(), String.t()}}

http_status()

@type http_status() :: integer()

payload()

@type payload() :: map()

response()

@type response() :: success() | http_error() | transport_error()

success()

@type success() :: {:ok, %{body: map(), headers: headers(), status: http_status()}}

transport_error()

@type transport_error() :: {:transport_error, any()}

Callbacks

endpoint_error_classify(status, body, headers, transport_reason)

@callback endpoint_error_classify(
  status :: integer() | nil,
  body :: binary() | nil,
  headers :: list() | nil,
  transport_reason :: term() | nil
) ::
  :ok
  | {:retry, reason :: atom(), wait_ms :: non_neg_integer() | nil}
  | {:fail, reason :: atom(), human :: binary()}

Classify a non-success HTTP/transport result.

This callback receives either an HTTP status + body (for HTTP errors) or a transport reason (for transport errors). Providers should return one of:

  • :ok — no retry; Endpoint returns the original result
  • {:retry, reason, wait_ms | nil}— retry; optional provider-suggested delay (ms)

  • {:fail, reason, human} — stop retrying; human-friendly message for logs

headers is currently nil for error cases as the lower-level HTTP client does not expose them. This can be extended in the future without breaking existing implementations.

endpoint_path()

@callback endpoint_path() :: String.t()

Functions

post_json(endpoint_module, headers, payload)

@spec post_json(endpoint(), headers(), payload()) :: response()

Perform a JSON POST request against the endpoint module's endpoint_path/0. Retries up to 3 times when the server indicates throttling.

retry_limit()

@spec retry_limit() :: pos_integer()

The fixed retry limit for API calls.