LemonAi.Models (lemon_ai v0.1.0)

View Source

Registry of known AI models with their capabilities and pricing.

This module provides access to model metadata including:

  • Model identification (id, name, provider)
  • API configuration (api type, base_url)
  • Capabilities (reasoning support, input types)
  • Pricing (cost per million tokens)
  • Limits (context window, max tokens)

Usage

# Get a specific model
model = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")

# List all models for a provider
models = LemonAi.Models.get_models(:openai)

# Check capabilities
LemonAi.Models.supports_vision?(model)
LemonAi.Models.supports_reasoning?(model)

Model data is defined in per-provider submodules under LemonAi.Models.* and merged into a single compile-time registry here.

Summary

Functions

Adjust max tokens to accommodate a thinking budget for a given reasoning level.

Clamp a reasoning level, mapping :xhigh to :high for providers that don't support it.

Find a model by ID across all providers.

Get a specific model by provider and model ID.

Get model IDs for a provider.

Get all models for a provider.

List all known providers.

List all known models across all providers.

List all known models with optional runtime discovery.

Check if two models are equal by comparing both their id and provider. Returns false if either model is nil.

Check if a model supports reasoning/thinking.

Check if a model supports vision (image input).

Check if a model supports the xhigh thinking level.

Types

list_models_opt()

@type list_models_opt() ::
  {:discover_openai, boolean()}
  | {:openai_api_key, String.t()}
  | {:openai_base_url, String.t()}
  | {:openai_timeout_ms, pos_integer()}

Functions

adjust_max_tokens_for_thinking(base_max_tokens, model_max_tokens, reasoning_level, custom_budgets \\ %{})

@spec adjust_max_tokens_for_thinking(
  non_neg_integer(),
  non_neg_integer(),
  atom(),
  map()
) :: {non_neg_integer(), non_neg_integer()}

Adjust max tokens to accommodate a thinking budget for a given reasoning level.

Computes the thinking token budget for the requested level (clamping xhigh to high), then increases base_max_tokens by that amount without exceeding model_max_tokens. If the resulting max is smaller than the budget, the budget is reduced to leave at least 1024 output tokens.

Ported from Pi's adjustMaxTokensForThinking.

Parameters

  • base_max_tokens - The base output token limit before thinking
  • model_max_tokens - The model's hard maximum token limit
  • reasoning_level - One of :minimal, :low, :medium, :high, :xhigh
  • custom_budgets - Optional map overriding default budgets per level

Returns

A tuple {max_tokens, thinking_budget}.

Examples

iex> LemonAi.Models.adjust_max_tokens_for_thinking(8192, 200_000, :high)
{24576, 16384}

iex> LemonAi.Models.adjust_max_tokens_for_thinking(8192, 200_000, :medium, %{medium: 4096})
{12288, 4096}

clamp_reasoning(level)

@spec clamp_reasoning(atom() | nil) :: atom() | nil

Clamp a reasoning level, mapping :xhigh to :high for providers that don't support it.

Examples

iex> LemonAi.Models.clamp_reasoning(:xhigh)
:high

iex> LemonAi.Models.clamp_reasoning(:medium)
:medium

iex> LemonAi.Models.clamp_reasoning(nil)
nil

find_by_id(model_id)

@spec find_by_id(String.t()) :: LemonAi.Types.Model.t() | nil

Find a model by ID across all providers.

Returns the first matching model found, or nil if no match.

Examples

iex> model = LemonAi.Models.find_by_id("gpt-4o")
iex> model.provider
:openai

iex> LemonAi.Models.find_by_id("nonexistent")
nil

get_model(provider, model_id)

@spec get_model(atom(), String.t()) :: LemonAi.Types.Model.t() | nil

Get a specific model by provider and model ID.

Examples

iex> model = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> model.name
"Claude Sonnet 4"

iex> LemonAi.Models.get_model(:anthropic, "nonexistent")
nil

get_model_ids(provider)

@spec get_model_ids(atom()) :: [String.t()]

Get model IDs for a provider.

Examples

iex> ids = LemonAi.Models.get_model_ids(:anthropic)
iex> "claude-sonnet-4-20250514" in ids
true

get_models(provider)

@spec get_models(atom()) :: [LemonAi.Types.Model.t()]

Get all models for a provider.

Examples

iex> models = LemonAi.Models.get_models(:anthropic)
iex> length(models) > 0
true

iex> LemonAi.Models.get_models(:unknown_provider)
[]

get_providers()

@spec get_providers() :: [atom()]

List all known providers.

Examples

iex> providers = LemonAi.Models.get_providers()
iex> :anthropic in providers
true

list_models()

@spec list_models() :: [LemonAi.Types.Model.t()]

List all known models across all providers.

Examples

iex> models = LemonAi.Models.list_models()
iex> length(models) > 0
true

list_models(opts)

@spec list_models([list_models_opt()]) :: [LemonAi.Types.Model.t()]

List all known models with optional runtime discovery.

Options

  • :discover_openai - When true, query OpenAI /v1/models and filter the OpenAI model list to IDs reported as available for the configured key. If discovery fails, returns the static model registry.
  • :openai_api_key - Optional API key override for discovery.
  • :openai_base_url - Optional OpenAI-compatible base URL override.
  • :openai_timeout_ms - Optional request timeout in milliseconds.

models_equal?(arg1, arg2)

@spec models_equal?(LemonAi.Types.Model.t() | nil, LemonAi.Types.Model.t() | nil) ::
  boolean()

Check if two models are equal by comparing both their id and provider. Returns false if either model is nil.

Ported from Pi's modelsAreEqual.

Examples

iex> model1 = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> model2 = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> LemonAi.Models.models_equal?(model1, model2)
true

iex> model1 = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> model2 = LemonAi.Models.get_model(:openai, "gpt-4o")
iex> LemonAi.Models.models_equal?(model1, model2)
false

iex> LemonAi.Models.models_equal?(nil, model1)
false

supports_reasoning?(model)

@spec supports_reasoning?(LemonAi.Types.Model.t()) :: boolean()

Check if a model supports reasoning/thinking.

Examples

iex> model = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> LemonAi.Models.supports_reasoning?(model)
true

iex> model = LemonAi.Models.get_model(:openai, "gpt-4o")
iex> LemonAi.Models.supports_reasoning?(model)
false

supports_vision?(model)

@spec supports_vision?(LemonAi.Types.Model.t()) :: boolean()

Check if a model supports vision (image input).

Examples

iex> model = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> LemonAi.Models.supports_vision?(model)
true

iex> model = LemonAi.Models.get_model(:openai, "o3-mini")
iex> LemonAi.Models.supports_vision?(model)
false

supports_xhigh(model)

@spec supports_xhigh(LemonAi.Types.Model.t()) :: boolean()

Check if a model supports the xhigh thinking level.

Supported models:

  • GPT-5.2 / GPT-5.3 model families
  • Anthropic Opus 4.6 models (xhigh maps to adaptive effort "max")

Ported from Pi's model-resolver.

Examples

iex> model = LemonAi.Models.get_model(:openai, "gpt-5.2")
iex> LemonAi.Models.supports_xhigh(model)
true

iex> model = LemonAi.Models.get_model(:anthropic, "claude-opus-4-6")
iex> LemonAi.Models.supports_xhigh(model)
true

iex> model = LemonAi.Models.get_model(:anthropic, "claude-sonnet-4-20250514")
iex> LemonAi.Models.supports_xhigh(model)
false