Normandy.Schema.Wire (normandy v2.2.0)

View Source

A JSON Schema as the model sees it.

Normandy.Schema keeps a field's declaration order in the specification under :property_order (a plain map, so spec[:properties][name] keeps working). Elixir maps do not keep key order, so a specification encoded as it is lists its properties in an order unrelated to the declaration. The model reads (and constrained decoding generates) properties in the order they are sent, so declaration order is generation order: declare reasoning before answer to have the model reason first.

encodable/1 returns the specification ready for Normandy.JSON:

  • every properties map that has a :property_order becomes a Jason.OrderedObject in that order; :property_order itself is removed;
  • "$schema" and "title" (atom or string keys) are removed from every schema node; a property named title is kept;
  • it recurses into properties, items, additionalProperties, not, if, then, else, contains, propertyNames, unevaluatedProperties, unevaluatedItems, anyOf, oneOf, allOf, prefixItems, and the schemas of $defs, definitions, patternProperties and dependentSchemas.

A node without :property_order (a hand-written or MCP schema) keeps its properties as a map. Normandy calls it where a schema leaves for the model: tool input_schema (Normandy.Tools.Toolset.to_tool_schemas/1), the system prompt's # OUTPUT SCHEMA block and the JSON retry feedback. __schema__(:specification) and an io_schema's get_json_schema/0 return the specification unchanged.

These call sites hand Jason Jason.OrderedObject structs, which it encodes in order.

Summary

Functions

The schema with ordered properties and without $schema and title.

Functions

encodable(schema)

@spec encodable(term()) :: term()

The schema with ordered properties and without $schema and title.