ReqLLM.Schema (ReqLLM v1.0.0-rc.8)

View Source

Single schema authority for NimbleOptions ↔ JSON Schema conversion.

This module consolidates all schema conversion logic, providing unified functions for converting keyword schemas to both NimbleOptions compiled schemas and JSON Schema format. Supports all common NimbleOptions types and handles nested schemas.

Also supports direct JSON Schema pass-through when a map is provided instead of a keyword list, and Zoi schema structs for advanced schema definitions.

Core Functions

  • compile/1 - Convert keyword schema to NimbleOptions compiled schema, or pass through maps
  • to_json/1 - Convert keyword schema to JSON Schema format, pass through maps, or convert Zoi schemas

Basic Usage

# Compile keyword schema to NimbleOptions
{:ok, compiled} = ReqLLM.Schema.compile([
  name: [type: :string, required: true, doc: "User name"],
  age: [type: :pos_integer, doc: "User age"]
])

# Convert keyword schema to JSON Schema
json_schema = ReqLLM.Schema.to_json([
  name: [type: :string, required: true, doc: "User name"],
  age: [type: :pos_integer, doc: "User age"]
])
# => %{
#      "type" => "object",
#      "properties" => %{
#        "name" => %{"type" => "string", "description" => "User name"},
#        "age" => %{"type" => "integer", "minimum" => 1, "description" => "User age"}
#      },
#      "required" => ["name"]
#    }

# Use raw JSON Schema directly (map pass-through)
json_schema = ReqLLM.Schema.to_json(%{
  "type" => "object",
  "properties" => %{
    "location" => %{"type" => "string"},
    "units" => %{"type" => "string", "enum" => ["celsius", "fahrenheit"]}
  },
  "required" => ["location"]
})
# => Returns the map unchanged

Supported Types

All common NimbleOptions types are supported:

  • :string - String type
  • :integer - Integer type
  • :pos_integer - Positive integer (adds minimum: 1 constraint)
  • :float - Float/number type
  • :number - Generic number type
  • :boolean - Boolean type
  • {:list, type} - Array of specified type
  • :map - Object type
  • Custom types fall back to string

Nested Schemas

Nested schemas are supported through recursive type handling:

schema = [
  user: [
    type: {:list, :map},
    doc: "List of user objects",
    properties: [
      name: [type: :string, required: true],
      email: [type: :string, required: true]
    ]
  ]
]

Summary

Functions

Compiles a keyword schema to a NimbleOptions compiled schema.

Converts a NimbleOptions type to JSON Schema property definition.

Format a tool into Anthropic tool schema format.

Format a tool into AWS Bedrock Converse API tool schema format.

Format a tool into Google tool schema format.

Converts a keyword schema to JSON Schema format.

Format a tool into OpenAI tool schema format.

Validate data against a schema.

Functions

compile(schema)

@spec compile(keyword() | map() | struct() | any()) ::
  {:ok, %{schema: keyword() | map(), compiled: NimbleOptions.t() | nil}}
  | {:error, ReqLLM.Error.t()}

Compiles a keyword schema to a NimbleOptions compiled schema.

Takes a keyword list representing a NimbleOptions schema and compiles it into a validated NimbleOptions schema that can be used for validation.

When a map is provided (raw JSON Schema), returns a wrapper with the original schema and no compiled version (pass-through mode).

When a Zoi schema struct is provided, converts it to JSON Schema format.

Parameters

  • schema - A keyword list representing a NimbleOptions schema, a map for raw JSON Schema, or a Zoi schema struct

Returns

  • {:ok, compiled_result} - Compiled schema wrapper with :schema and :compiled fields
  • {:error, error} - Compilation error with details

Examples

iex> {:ok, result} = ReqLLM.Schema.compile([
...>   name: [type: :string, required: true],
...>   age: [type: :pos_integer, default: 0]
...> ])
iex> is_map(result) and Map.has_key?(result, :schema)
true

iex> {:ok, result} = ReqLLM.Schema.compile(%{"type" => "object", "properties" => %{}})
iex> result.schema
%{"type" => "object", "properties" => %{}}

iex> ReqLLM.Schema.compile("invalid")
{:error, %ReqLLM.Error.Invalid.Parameter{}}

nimble_type_to_json_schema(type, opts)

@spec nimble_type_to_json_schema(
  atom() | tuple(),
  keyword()
) :: map()

Converts a NimbleOptions type to JSON Schema property definition.

Takes a NimbleOptions type atom and options, converting them to the corresponding JSON Schema property definition with proper type mapping.

Parameters

  • type - The NimbleOptions type atom (e.g., :string, :integer, {:list, :string})
  • opts - Additional options including :doc for description

Returns

A map representing the JSON Schema property definition.

Examples

iex> ReqLLM.Schema.nimble_type_to_json_schema(:string, doc: "A text field")
%{"type" => "string", "description" => "A text field"}

iex> ReqLLM.Schema.nimble_type_to_json_schema({:list, :integer}, [])
%{"type" => "array", "items" => %{"type" => "integer"}}

iex> ReqLLM.Schema.nimble_type_to_json_schema(:pos_integer, doc: "Positive number")
%{"type" => "integer", "minimum" => 1, "description" => "Positive number"}

to_anthropic_format(tool)

@spec to_anthropic_format(ReqLLM.Tool.t()) :: map()

Format a tool into Anthropic tool schema format.

Parameters

  • tool - A ReqLLM.Tool.t() struct

Returns

A map containing the Anthropic tool schema format.

Examples

iex> tool = %ReqLLM.Tool{
...>   name: "get_weather",
...>   description: "Get current weather",
...>   parameter_schema: [
...>     location: [type: :string, required: true, doc: "City name"]
...>   ],
...>   callback: fn _ -> {:ok, %{}} end
...> }
iex> ReqLLM.Schema.to_anthropic_format(tool)
%{
  "name" => "get_weather",
  "description" => "Get current weather",
  "input_schema" => %{
    "type" => "object",
    "properties" => %{
      "location" => %{"type" => "string", "description" => "City name"}
    },
    "required" => ["location"]
  }
}

to_bedrock_converse_format(tool)

@spec to_bedrock_converse_format(ReqLLM.Tool.t()) :: map()

Format a tool into AWS Bedrock Converse API tool schema format.

Parameters

  • tool - A ReqLLM.Tool.t() struct

Returns

A map containing the Bedrock Converse tool schema format.

Examples

iex> tool = %ReqLLM.Tool{
...>   name: "get_weather",
...>   description: "Get current weather",
...>   parameter_schema: [
...>     location: [type: :string, required: true, doc: "City name"]
...>   ],
...>   callback: fn _ -> {:ok, %{}} end
...> }
iex> ReqLLM.Schema.to_bedrock_converse_format(tool)
%{
  "toolSpec" => %{
    "name" => "get_weather",
    "description" => "Get current weather",
    "inputSchema" => %{
      "json" => %{
        "type" => "object",
        "properties" => %{
          "location" => %{"type" => "string", "description" => "City name"}
        },
        "required" => ["location"]
      }
    }
  }
}

to_google_format(tool)

@spec to_google_format(ReqLLM.Tool.t()) :: map()

Format a tool into Google tool schema format.

Parameters

  • tool - A ReqLLM.Tool.t() struct

Returns

A map containing the Google tool schema format.

Examples

iex> tool = %ReqLLM.Tool{
...>   name: "get_weather",
...>   description: "Get current weather",
...>   parameter_schema: [
...>     location: [type: :string, required: true, doc: "City name"]
...>   ],
...>   callback: fn _ -> {:ok, %{}} end
...> }
iex> ReqLLM.Schema.to_google_format(tool)
%{
  "name" => "get_weather",
  "description" => "Get current weather",
  "parameters" => %{
    "type" => "object",
    "properties" => %{
      "location" => %{"type" => "string", "description" => "City name"}
    },
    "required" => ["location"]
  }
}

to_json(schema)

@spec to_json(keyword() | map() | struct()) :: map()

Converts a keyword schema to JSON Schema format.

Takes a keyword list of parameter definitions and converts them to a JSON Schema object suitable for LLM tool definitions or structured data schemas.

When a map is provided (raw JSON Schema), returns it unchanged (pass-through mode).

When a Zoi schema struct is provided, converts it to JSON Schema.

Parameters

  • schema - Keyword list of parameter definitions, a map for raw JSON Schema, or a Zoi schema struct

Returns

A map representing the JSON Schema object with properties and required fields.

Examples

iex> ReqLLM.Schema.to_json([
...>   name: [type: :string, required: true, doc: "User name"],
...>   age: [type: :integer, doc: "User age"],
...>   tags: [type: {:list, :string}, default: [], doc: "User tags"]
...> ])
%{
  "type" => "object",
  "properties" => %{
    "name" => %{"type" => "string", "description" => "User name"},
    "age" => %{"type" => "integer", "description" => "User age"},
    "tags" => %{
      "type" => "array",
      "items" => %{"type" => "string"},
      "description" => "User tags"
    }
  },
  "required" => ["name"]
}

iex> ReqLLM.Schema.to_json([])
%{"type" => "object", "properties" => %{}}

iex> ReqLLM.Schema.to_json(%{"type" => "object", "properties" => %{"foo" => %{"type" => "string"}}})
%{"type" => "object", "properties" => %{"foo" => %{"type" => "string"}}}

to_openai_format(tool)

@spec to_openai_format(ReqLLM.Tool.t()) :: map()

Format a tool into OpenAI tool schema format.

Parameters

  • tool - A ReqLLM.Tool.t() struct

Returns

A map containing the OpenAI tool schema format.

Examples

iex> tool = %ReqLLM.Tool{
...>   name: "get_weather",
...>   description: "Get current weather",
...>   parameter_schema: [
...>     location: [type: :string, required: true, doc: "City name"]
...>   ],
...>   callback: fn _ -> {:ok, %{}} end
...> }
iex> ReqLLM.Schema.to_openai_format(tool)
%{
  "type" => "function",
  "function" => %{
    "name" => "get_weather",
    "description" => "Get current weather",
    "parameters" => %{
      "type" => "object",
      "properties" => %{
        "location" => %{"type" => "string", "description" => "City name"}
      },
      "required" => ["location"]
    }
  }
}

validate(data, schema)

@spec validate(any(), keyword() | map() | struct()) ::
  {:ok, keyword() | map() | list() | any()} | {:error, ReqLLM.Error.t()}

Validate data against a schema.

Takes data and validates it against a schema. Supports multiple schema types:

  • NimbleOptions keyword schemas (expects maps)
  • Zoi schema structs (can handle maps, arrays, etc.)
  • Raw JSON Schemas (validated using JSV for JSON Schema draft 2020-12 compliance)

Parameters

  • data - Data to validate (map, list, or other type depending on schema)
  • schema - Schema definition (keyword list, Zoi struct, or map)

Returns

  • {:ok, validated_data} - Successfully validated data
  • {:error, error} - Validation error with details

Examples

iex> schema = [name: [type: :string, required: true], age: [type: :integer]]
iex> data = %{"name" => "Alice", "age" => 30}
iex> ReqLLM.Schema.validate(data, schema)
{:ok, [name: "Alice", age: 30]}

iex> schema = [name: [type: :string, required: true]]
iex> data = %{"age" => 30}
iex> ReqLLM.Schema.validate(data, schema)
{:error, %ReqLLM.Error.Validation.Error{...}}