ExAgent. OutputSchema
(ExAgent v2.2.2)
View Source
Structured output via Ecto schemas and changesets.
Given any module defining an embedded_schema (plus a changeset/2), this
module:
json_schema/1derives the JSON Schema the model is told to produce, by walking the schema's fields and types (scalars, enums, arrays, embedded schemas, datetimes).validate/2builds a changeset from the model's data, applies the schema's validations, and returns either{:ok, struct}or{:error, errors}— feeding the errors back to the model for a retry.
The convention is the standard Ecto one: a changeset(struct, attrs) callback.
Its declared required fields are authoritative, including an empty list.
Optional fields accept omission or null through an anyOf branch, keeping
reflected non-null constraints intact. Optional embeds_many is the Ecto
exception: it accepts omission or an array, not null. Required fields are
not nullable. These rules apply recursively to embedded schemas. Schemas
without a changeset keep the default that casts and requires all fields.
Reflection inspects a changeset built with empty attributes; it cannot fully
describe arbitrary custom or conditional validations. validate/2 always
runs the actual changeset and remains the final authority. Provider support
for this JSON Schema (including anyOf and strict-mode restrictions) must
be checked against the actual backend.
Reflected inclusion/exclusion values retain their JSON types. Ecto.Enum schemas
advertise the declared storage values with their integer or string type, and
inclusion/exclusion constraints map enum members to that same vocabulary.
Plain atom enums still use their string names, including boolean-named members.
Array lengths use
minItems/maxItems, while string lengths use minLength/maxLength, including
exact (:is) bounds. Length bounds intersect across options and validation calls;
contradictory bounds remain unsatisfiable, as in the changeset. JSON string
lengths count Unicode codepoints. Ecto's default grapheme counting and optional
byte counting can differ; use count: :codepoints when exact alignment is
required. The real changeset remains authoritative for those count modes.
Example
defmodule WeatherReport do
use Ecto.Schema
embedded_schema do
field :city, :string
field :temp_c, :float
field :condition, Ecto.Enum, values: [:sunny, :rainy, :cloudy]
end
def changeset(schema, attrs) do
schema
|> Ecto.Changeset.cast(attrs, [:city, :temp_c, :condition])
|> Ecto.Changeset.validate_required([:city, :temp_c])
|> Ecto.Changeset.validate_number(:temp_c, greater_than: -100, less_than: 100)
end
end
ExAgent.OutputSchema.json_schema(WeatherReport)
# => %{type: "object", properties: %{city: %{type: "string"}, ...}, required: [...]}
ExAgent.OutputSchema.validate(WeatherReport, %{"city" => "Madrid", "temp_c" => 22.0})
# => {:ok, %WeatherReport{city: "Madrid", temp_c: 22.0, ...}}
Summary
Functions
Derive a JSON Schema from an Ecto schema module.
Validate data (a map, typically decoded from the model's JSON) against an
Ecto schema, returning {:ok, struct} or {:error, [error_map]}.
Functions
Derive a JSON Schema from an Ecto schema module.
Validate data (a map, typically decoded from the model's JSON) against an
Ecto schema, returning {:ok, struct} or {:error, [error_map]}.