PtcRunner.LLM.Registry behaviour (PtcRunner v0.10.1)

Copy Markdown View Source

Behaviour and unified interface for model resolution.

Resolves model aliases (e.g., "haiku") to full provider:model strings (e.g., "openrouter:anthropic/claude-haiku-4.5"). This enables simple model references in SubAgent.run:

# Instead of building callbacks manually:
{:ok, step} = SubAgent.run(agent, llm: "haiku")
{:ok, step} = SubAgent.run(agent, llm: "bedrock:haiku")

Configuration

The default implementation uses built-in aliases. To swap registries:

config :ptc_runner, :model_registry, MyApp.ModelRegistry

Or configure the default provider:

config :ptc_runner, :default_provider, :bedrock

Custom Registry

Implement the behaviour to add custom aliases:

defmodule MyApp.ModelRegistry do
  @behaviour PtcRunner.LLM.Registry

  @impl true
  def resolve("fast"), do: {:ok, "anthropic:claude-haiku-4-5-20251001"}
  def resolve("smart"), do: {:ok, "anthropic:claude-sonnet-4-5-20250929"}
  def resolve(name), do: PtcRunner.LLM.DefaultRegistry.resolve(name)

  @impl true
  def resolve!(name) do
    case resolve(name) do
      {:ok, model_id} -> model_id
      {:error, reason} -> raise ArgumentError, reason
    end
  end

  @impl true
  def validate(model_string) do
    case resolve(model_string) do
      {:ok, _} -> :ok
      {:error, reason} -> {:error, reason}
    end
  end

  # Delegate remaining callbacks to DefaultRegistry
  @impl true
  defdelegate default_model(), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate default_provider(), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate aliases(), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate list_models(), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate preset_models(provider), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate available_providers(), to: PtcRunner.LLM.DefaultRegistry
  @impl true
  defdelegate provider_from_model(model), to: PtcRunner.LLM.DefaultRegistry
end

Summary

Callbacks

Get list of all alias names.

Get list of available providers based on environment.

Get the default model using the default provider.

Get the default provider atom.

List all models with availability status.

Get model presets for a provider as alias -> model_id map.

Extract the provider atom from a model string.

Resolve a model name or alias to a full provider:model string.

Resolve a model name, raising on error.

Validate a model string format.

Callbacks

aliases()

@callback aliases() :: [String.t()]

Get list of all alias names.

available_providers()

@callback available_providers() :: [atom()]

Get list of available providers based on environment.

default_model()

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

Get the default model using the default provider.

default_provider()

@callback default_provider() :: atom()

Get the default provider atom.

list_models()

@callback list_models() :: [map()]

List all models with availability status.

preset_models(atom)

@callback preset_models(atom()) :: %{required(String.t()) => String.t()}

Get model presets for a provider as alias -> model_id map.

provider_from_model(t)

@callback provider_from_model(String.t()) :: atom() | nil

Extract the provider atom from a model string.

resolve(t)

@callback resolve(String.t()) :: {:ok, String.t()} | {:error, String.t()}

Resolve a model name or alias to a full provider:model string.

Formats

  • "alias" - Resolves using default provider (e.g., "haiku" -> "openrouter:...")
  • "provider:alias" - Resolves with specific provider (e.g., "bedrock:haiku")
  • "provider:full/model/id" - Passes through as-is

Examples

iex> PtcRunner.LLM.Registry.resolve("haiku")
{:ok, "openrouter:anthropic/claude-haiku-4.5"}

iex> PtcRunner.LLM.Registry.resolve("bedrock:haiku")
{:ok, "amazon_bedrock:anthropic.claude-haiku-4-5-20251001-v1:0"}

resolve!(t)

@callback resolve!(String.t()) :: String.t()

Resolve a model name, raising on error.

validate(t)

@callback validate(String.t()) :: :ok | {:error, String.t()}

Validate a model string format.