ReqLLM.Schema (ReqLLM v1.0.0-rc.8)
View SourceSingle 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 unchangedSupported 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
@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- :schemaand- :compiledfields
- {: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{}}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- :docfor 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"}@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"]
  }
}@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"]
      }
    }
  }
}@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"]
  }
}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"}}}@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"]
    }
  }
}@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{...}}