Documentation
¶
Overview ¶
Package schema derives JSON Schema from Go types and emits provider-specific dialects. Reflection-based frameworks all trip on the same wall: the schema reflection emits ($ref/$defs, missing additionalProperties) gets rejected by OpenAI strict mode and Gemini, so everyone reinvents a sanitizer. We emit INLINE (no $ref/$defs — recursion-safe) and provide dialect transforms so the tool author never hand-edits JSON Schema.
Tools expose the neutral schema (For); each model adapter dialectizes it at request time (Anthropic accepts the neutral form; OpenAI needs OpenAIStrict; Gemini needs Gemini).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var ErrGeminiUnsupported = errors.New("schema: not expressible in Gemini's schema subset")
ErrGeminiUnsupported reports a schema Gemini's schema subset cannot express without changing which documents it admits (a map, an unconstrained value, an object with no properties).
var ErrStrictUnsupported = errors.New("schema: not expressible in OpenAI strict mode")
ErrStrictUnsupported reports a schema OpenAIStrict cannot express in strict mode without changing which documents it admits (a map, a recursive type, a free-form object).
var ErrUnsupportedType = errors.New("schema: Go type cannot be described")
ErrUnsupportedType reports a Go type For cannot describe: a document valid under any schema for it would fail to decode, so For refuses the type rather than emit such a schema.
Functions ¶
func For ¶
func For[T any]() (json.RawMessage, error)
For derives an inline JSON Schema from Go type T. Nested structs are inlined (no $ref/$defs). Descriptions come from the `desc` tag. A field is required unless it is a pointer or its json tag has ",omitempty" or ",omitzero".
It mirrors encoding/json's decoding of T exactly: the object's properties are the fields encoding/json reads, found by the same rules (json tag names, "-" and "-,", embedded structs promoted into the parent unless the tag names them, and Go's dominance rules for fields that embedding supplies more than once, where a tie removes the name altogether). A ",string" field is a JSON string holding the value. []byte is a base64 string but a byte array is an array of numbers; a Go array has exactly its length in items. An integer is bounded by its Go kind (minimum 0 for an unsigned kind, and both bounds for a kind of 32 bits or fewer), and the keys of a map with integer keys are decimal integers (propertyNames). time.Time is a date-time string; json.RawMessage and interface{} are unconstrained. A type that decodes itself is not reflected field by field (reflection cannot see the custom shape), and its DECODING methods decide, as they do for encoding/json: a json.Unmarshaler is unconstrained, and otherwise an encoding.TextUnmarshaler is a string. (A type that only marshals itself is decoded field by field, so it is reflected like any other.) A recursive reference is cut off as an unconstrained object or array.
It returns an error wrapping ErrUnsupportedType for a type encoding/json cannot decode as any schema would describe it: a field reached through an embedded pointer to an unexported struct type, which encoding/json cannot allocate; a json tag name encoding/json does not accept (one with a quote, a backslash, or another reserved character), which encoding/json reads differently depending on how it is built; a kind encoding/json decodes no value but null into (a channel, a function, a complex number, an unsafe.Pointer, an interface with methods, or a map whose key type is not a string, an integer, or an encoding.TextUnmarshaler); and a pointer type that points to itself.
func Gemini ¶ added in v0.7.0
func Gemini(neutral json.RawMessage) (json.RawMessage, error)
Gemini transforms a neutral schema into the OpenAPI 3.0 subset Gemini reads in a function declaration's parameters and in responseSchema:
- A type list with "null" becomes the type plus nullable:true; null in an enum, or a {"type":"null"} branch of anyOf, becomes nullable:true too. A string const becomes a one-value enum.
- additionalProperties:false is dropped (Gemini objects admit only their properties). Validation keywords Gemini lacks (uniqueItems, exclusiveMinimum, exclusiveMaximum, multipleOf), annotations ($schema, $id, $comment, examples, readOnly, writeOnly, deprecated), and a format Gemini does not know for the type are dropped: they only guide the model, and the tool still checks what it receives.
- A construct Gemini cannot express is an error wrapping ErrGeminiUnsupported that names its location: an object with no properties or with additionalProperties (a map, whose keys are data; a recursive type, which For cuts off as an open object), a schema with no type (interface{} or json.RawMessage, which For leaves unconstrained), a list of several non-null types, a non-string enum or const, an array with no items, and any keyword outside the subset ($ref, oneOf, allOf, not, patternProperties, ...).
A tool with no arguments has no schema to send; the Gemini adapter omits its parameters rather than calling this with an empty object, which Gemini rejects.
func OpenAIStrict ¶
func OpenAIStrict(neutral json.RawMessage) (json.RawMessage, error)
OpenAIStrict transforms a neutral schema into OpenAI structured-output "strict" form, which closes every object (additionalProperties:false) and lists every property in required. It changes no set of accepted answers beyond that:
- A property the neutral schema leaves optional (a pointer or omitempty field) stays optional in meaning: it is required but nullable (type [T, "null"], and null added to an enum), so the model sends null rather than inventing a value. encoding/json decodes null into such a field as its zero value.
- An object strict mode cannot close without changing it (a map, whose keys are data; a recursive type, which For cuts off as an open object; any object with no declared properties or with additionalProperties or patternProperties) is an error wrapping ErrStrictUnsupported that names the offending location. Closing it would admit only {}, so every answer would arrive empty.
- An untyped schema ({}, which For gives any and json.RawMessage, or the schema true) admits every value, which strict mode cannot express; it is an error wrapping ErrStrictUnsupported too. So is an array with no items schema (a recursive slice, which For cuts off that way), whose items are untyped.
Operates on the inline schema.
Types ¶
This section is empty.