Skip to main content
An adapter sits between a signature and the LM: it formats typed inputs into the prompt the model sees and parses the LM’s response back into typed outputs. The default adapter is ChatAdapter, and Predict drives it for you, so you touch it directly only to inspect what the model sees.

What adapters do

ChatAdapter handles both formatting and parsing.

ChatAdapter

Prompt structure

The system message has four parts (in this order):
  1. Field descriptions - Lists input/output fields with types and descriptions
  2. Field structure - Shows the marker format + type schemas
  3. Response instructions - “Respond with [[ ## field ## ]]…”
  4. Task description - Your instruction from the signature docstring (at the end)
Example system message (simplified):

Marker protocol

Fields are delimited by markers:
This protocol (inspired by DSPy) allows mixing natural language with structured output.

Type schemas

For complex types, the adapter renders full schemas with typesys::render: type_name produces the short inline label, and schema_block expands class field layouts and enum value lists:
Type names are simplified for readability:
  • Module paths stripped: my_crate::SentimentSentiment
  • class/enum prefixes removed
  • " | "" or " (more natural)

Tolerant parsing with typesys::coerce

Response parsing uses typesys::coerce, a tolerant coercer that turns raw LM field text into typed values, guided by the expected field type. It handles:
  • Markdown fences - Strips ```json fences before parsing
  • Lists from prose - Parses bulleted or numbered lists into arrays
  • Type coercion - "42"42, "yes"true (loose bool and number spellings)
  • Surrounding text - Ignores extra prose around a JSON object or array
  • Partial recovery - Per-field failures aggregate; you get every error plus what did parse
Each non-fatal fix (a stripped fence, a coerced scalar) is recorded as a Flag on the returned Coerced value.

Constraint evaluation

After parsing, the adapter runs constraints:
  • #[check] results → stored in metadata
  • #[assert] failures → returns ParseError::AssertFailed

Error handling

Parse errors aggregate - you get all problems, not just the first:

Using the adapter directly

Usually you do not touch the adapter - Predict handles it. But for debugging:
This is useful for understanding what the LM sees.

Input formatting options

Input fields support two rendering paths:
  • #[format("json" | "yaml" | "toon")]: serialize a field using that format.
  • #[render(jinja = "...")]: render a field with a MiniJinja template.
  • #[format] and #[render] are mutually exclusive on the same field.
#[render] context in ChatAdapter:
  • this: current field value
  • input: full input object (plus top-level alias overlays)
  • field: { name, rust_name, type }
  • vars: adapter/surface vars (currently {})
ChatAdapter configures MiniJinja with strict undefined behavior. Available filters include:
  • MiniJinja built-ins
  • regex_match and sum helpers
  • truncate for length-limited string rendering
If template rendering fails at runtime (for example, missing variables), ChatAdapter panics. Compiled templates are cached process-wide by template string.

Real example: Insurance claim extraction

This is what a prompt looks like for a complex nested type (from examples/16-insurance-claim-prompt.rs):
Generated system message:
Generated user message:
Notice how:
  • Enums with many variants become “Definitions” at the top
  • Doc comments become inline // comments in the schema
  • Option<T> renders as T or null
  • Nested objects show their full structure
  • The instruction comes from the signature docstring

Design notes

  • DSPy inspiration: Marker protocol from DSPy’s ChatAdapter
  • BAML heritage: Schema rendering and tolerant parsing were originally built on the vendored BAML stack (jsonish and its schema renderer). The in-house typesys module (typesys::render, typesys::coerce) replaced that stack while keeping the same prompt-facing schema style.
  • Separation of concerns: Adapter does not know about LMs - just formatting/parsing

See also