Syntropy.Usage (syntropy v0.2.0)

Copy Markdown

LLM usage aggregation and the fair-use token budget.

Every finished run writes one row to usage_records (see Syntropy.TaskScheduler); this module aggregates those rows into the report served by GET /api/usage and enforces the rolling 30-day token budget on task submission.

The budget is persisted in runtime_settings (0 means unlimited) and can be seeded with SYNTROPY_USAGE_BUDGET_TOKENS. Enforcement requires persistence: without durable usage rows there is no window aggregate to compare against, so submissions are never rejected.

Summary

Functions

Validates and applies a token budget. The budget is written through to runtime_settings (best effort) and applied to the Application environment for persistence-disabled runtimes.

Budget posture: limit, rolling-window consumption, and whether the budget is currently enforced (requires persistence).

Effective fair-use token budget for the rolling 30-day window. 0 means unlimited.

Fair-use gate applied on task submission. Rejects only when persistence is enabled, a budget is set, and the rolling window aggregate has reached it.

Usage report for the given window: totals, per-day series, per-model breakdown, recent runs, and budget status. Providers that report no usage (mock, Ollama) still contribute run counts with zero tokens.

Types

window()

@type window() :: String.t()

Functions

apply_budget(tokens)

@spec apply_budget(term()) :: {:ok, map()} | {:error, String.t()}

Validates and applies a token budget. The budget is written through to runtime_settings (best effort) and applied to the Application environment for persistence-disabled runtimes.

budget_report()

@spec budget_report() :: map()

Budget posture: limit, rolling-window consumption, and whether the budget is currently enforced (requires persistence).

budget_tokens()

@spec budget_tokens() :: non_neg_integer()

Effective fair-use token budget for the rolling 30-day window. 0 means unlimited.

check_budget()

@spec check_budget() :: :ok | {:error, :quota_exceeded}

Fair-use gate applied on task submission. Rejects only when persistence is enabled, a budget is set, and the rolling window aggregate has reached it.

report(window)

@spec report(term()) :: {:ok, map()} | {:error, String.t()}

Usage report for the given window: totals, per-day series, per-model breakdown, recent runs, and budget status. Providers that report no usage (mock, Ollama) still contribute run counts with zero tokens.

windows()

@spec windows() :: [window()]