LLMDB.Spec (LLM DB v2026.9.4)

Copy Markdown View Source

Canonical "provider:model" spec parsing and resolution.

This module provides functions to parse and resolve model specifications in various formats, including "provider:model" strings, "model@provider" strings (filename-safe), tuples, and bare model IDs with provider scope.

String Formats

Two string formats are supported:

  • "provider:model" - Traditional colon separator (default)
  • "model@provider" - Email-like format, filesystem-safe for filenames

Both formats parse to the same internal representation and can be used interchangeably. The @ format is recommended when model specs are used in filenames, CI artifact names, or other filesystem contexts.

Amazon Bedrock Inference Profiles

For Amazon Bedrock models, inference profile IDs with region prefixes (us., eu., ap., apac., ca., au., jp., us-gov., global.) are supported. A regional catalog entry supplies its own metadata and pricing. If no regional entry exists, lookup can use an alias or the base model, while preserving the region prefix in the returned model ID. For example:

iex> LLMDB.Spec.resolve("amazon_bedrock:us.anthropic.claude-opus-4-1-20250805-v1:0")
{:ok, {:amazon_bedrock, "us.anthropic.claude-opus-4-1-20250805-v1:0", %LLMDB.Model{}}}

When the catalog has only the base entry "anthropic.claude-opus-4-1-20250805-v1:0", the lookup uses its metadata, but the returned model ID retains the "us." prefix for API routing purposes.

Summary

Functions

Builds a model specification string from various inputs.

Formats a model specification as a string.

Normalizes a model specification to tuple format.

Parses and validates a provider identifier.

Parses a model specification string in either "provider:model" or "model@provider" format.

Parses a model specification string, raising on error.

Resolves a model specification to a canonical model record.

Splits a declared provider prefix from a model ID.

Functions

build_spec(input, opts \\ [])

@spec build_spec(String.t() | {atom(), String.t()}, keyword()) :: String.t()

Builds a model specification string from various inputs.

Accepts strings (in any supported format) or tuples and outputs a string in the desired format.

Parameters

  • input - Model spec as string or tuple
  • opts - Keyword list with optional :format for output format

Examples

iex> LLMDB.Spec.build_spec("openai:gpt-4", format: :filename_safe)
"gpt-4@openai"

iex> LLMDB.Spec.build_spec({:openai, "gpt-4"}, format: :model_at_provider)
"gpt-4@openai"

format_spec(arg, format \\ nil)

@spec format_spec({atom(), String.t()}, atom() | nil) :: String.t()

Formats a model specification as a string.

Converts a {provider, model_id} tuple to string format. The output format can be controlled via the format parameter or falls back to the application config :llm_db, :model_spec_format (default: :provider_colon_model).

Parameters

  • spec - {provider_atom, model_id} tuple
  • format - Optional format override (atom)

Supported Formats

  • :provider_colon_model - "provider:model" (default)
  • :model_at_provider - "model@provider" (filename-safe)
  • :filename_safe - alias for :model_at_provider

Examples

iex> LLMDB.Spec.format_spec({:openai, "gpt-4"})
"openai:gpt-4"

iex> LLMDB.Spec.format_spec({:openai, "gpt-4"}, :model_at_provider)
"gpt-4@openai"

iex> LLMDB.Spec.format_spec({:openai, "gpt-4o-mini"}, :filename_safe)
"gpt-4o-mini@openai"

normalize_spec(input)

@spec normalize_spec(String.t() | {atom(), String.t()}) :: {atom(), String.t()}

Normalizes a model specification to tuple format.

Accepts either a string (in any supported format) or a tuple and returns a normalized {provider, model_id} tuple.

Examples

iex> LLMDB.Spec.normalize_spec("openai:gpt-4")
{:openai, "gpt-4"}

iex> LLMDB.Spec.normalize_spec("gpt-4@openai")
{:openai, "gpt-4"}

iex> LLMDB.Spec.normalize_spec({:openai, "gpt-4"})
{:openai, "gpt-4"}

parse_provider(input)

@spec parse_provider(atom() | binary()) ::
  {:ok, atom()} | {:error, :unknown_provider | :bad_provider}

Parses and validates a provider identifier.

Accepts atom or binary input, normalizes to atom, and verifies the provider exists in the current catalog.

Parameters

  • input - Provider identifier as atom or binary

Returns

  • {:ok, atom} - Normalized provider atom if valid and exists in catalog
  • {:error, :unknown_provider} - Provider not found in catalog
  • {:error, :bad_provider} - Invalid provider format

Examples

iex> LLMDB.Spec.parse_provider(:openai)
{:ok, :openai}

iex> LLMDB.Spec.parse_provider("google-vertex")
{:ok, :google_vertex}

iex> LLMDB.Spec.parse_provider("nonexistent")
{:error, :unknown_provider}

parse_spec(input, opts \\ [])

@spec parse_spec(String.t() | {atom() | String.t(), String.t()}, keyword()) ::
  {:ok, {atom(), String.t()}}
  | {:error,
     :invalid_format
     | :ambiguous_format
     | :unknown_provider
     | :bad_provider
     | :invalid_chars
     | :empty_segment}

Parses a model specification string in either "provider:model" or "model@provider" format.

Automatically detects the format based on separators present. Validates the provider exists in the catalog and checks for reserved characters in segments.

Parameters

  • spec - String in "provider:model" or "model@provider" format, or a {provider, model_id} tuple whose provider is an atom or string
  • opts - Keyword list with optional :format to explicitly specify format

Options

  • :format - Explicitly specify the format as :colon or :at. Required when both separators present.

Returns

  • {:ok, {provider_atom, model_id}} - Parsed and normalized spec
  • {:error, :invalid_format} - No valid separator found
  • {:error, :ambiguous_format} - Both separators present without explicit format
  • {:error, :unknown_provider} - Provider not found in catalog
  • {:error, :bad_provider} - Invalid provider format
  • {:error, :invalid_chars} - Reserved characters in provider or model segments
  • {:error, :empty_segment} - Provider or model segment is empty

Examples

iex> LLMDB.Spec.parse_spec("openai:gpt-4")
{:ok, {:openai, "gpt-4"}}

iex> LLMDB.Spec.parse_spec("gpt-4@openai")
{:ok, {:openai, "gpt-4"}}

iex> LLMDB.Spec.parse_spec("google-vertex:gemini-pro")
{:ok, {:google_vertex, "gemini-pro"}}

iex> LLMDB.Spec.parse_spec("provider:model@ambiguous", format: :colon)
{:ok, {:provider, "model@ambiguous"}}

iex> LLMDB.Spec.parse_spec("gpt-4")
{:error, :invalid_format}

parse_spec!(input, opts \\ [])

@spec parse_spec!(String.t() | {atom(), String.t()}, keyword()) ::
  {atom(), String.t()}

Parses a model specification string, raising on error.

Same as parse_spec/2 but raises ArgumentError instead of returning error tuple.

Examples

iex> LLMDB.Spec.parse_spec!("openai:gpt-4")
{:openai, "gpt-4"}

iex> LLMDB.Spec.parse_spec!("gpt-4@openai")
{:openai, "gpt-4"}

resolve(input, opts \\ [])

@spec resolve(String.t() | {atom() | String.t(), String.t()}, keyword()) ::
  {:ok, {atom(), String.t(), LLMDB.Model.t()}} | {:error, term()}

Resolves a model specification to a canonical model record.

Accepts multiple input formats:

  • "provider:model" string
  • "model@provider" string
  • {provider, model_id} tuple with an atom or string provider
  • Bare "model" string with opts[:scope] = provider_atom

Handles alias resolution and validates the model exists in the catalog.

Parameters

  • input - Model specification in one of the supported formats
  • opts - Keyword list with optional :scope for bare model resolution

Returns

  • {:ok, {provider, canonical_id, Model.t()}} - Resolved model
  • {:error, :not_found} - Model doesn't exist
  • {:error, :ambiguous} - Bare model ID exists under multiple providers without scope
  • {:error, :invalid_format} - Malformed input
  • {:error, term} - Other parsing errors

Examples

iex> LLMDB.Spec.resolve("openai:gpt-4")
{:ok, {:openai, "gpt-4", %LLMDB.Model{}}}

iex> LLMDB.Spec.resolve({:openai, "gpt-4"})
{:ok, {:openai, "gpt-4", %LLMDB.Model{}}}

iex> LLMDB.Spec.resolve("gpt-4@openai")
{:ok, {:openai, "gpt-4", %LLMDB.Model{}}}

iex> LLMDB.Spec.resolve("gpt-4", scope: :openai)
{:ok, {:openai, "gpt-4", %LLMDB.Model{}}}

iex> LLMDB.Spec.resolve("gpt-4")
{:error, :ambiguous}

strip_prefix(provider, model_id)

@spec strip_prefix(atom(), String.t()) :: {String.t(), String.t() | nil}

Splits a declared provider prefix from a model ID.

Uses the provider's extra.model_id_prefixes metadata from the loaded catalog. Amazon Bedrock retains its compatibility defaults when no override is declared. Returns {base_id, prefix} using the longest matching prefix. If the provider has no prefix rules or none matches, returns {model_id, nil} unchanged.