Constrained generation forces the model to emit JSON matching a schema. Use the language’s native facility — Swift macros (Documentation Index
Fetch the complete documentation index at: https://docs.liquid.ai/llms.txt
Use this file to discover all available pages before exploring further.
@Generatable / @Guide) or Kotlin annotations (@Generatable / @Guide) — to define the structure, then set it on GenerationOptions. The schema is computed at compile time (Swift) or via reflection at load time (Kotlin), and the model’s output decodes directly into your type.
Define the structured type
- Swift (iOS / macOS)
- Kotlin (all platforms)
The
@Generatable macro analyzes your struct at compile time and synthesizes the jsonSchema() method. All stored properties must carry a @Guide description.Requires Swift 5.9+ (Swift macros). The
@Generatable / @Guide macros ship in the LeapSDKMacros SPM product — add it to your target alongside LeapModelDownloader (or LeapSDK) if you use constrained generation.Apply the schema in GenerationOptions
- Swift (iOS / macOS)
- Kotlin (all platforms)
Embedding the schema in the prompt
Some models do better when the JSON Schema is also included in the prompt text. Both platforms expose a helper.- Swift (iOS / macOS)
- Kotlin (all platforms)
Supported types
Composition types are supported as long as the leaf types are supported.| Schema type | Swift | Kotlin |
|---|---|---|
| String | String | String |
| Integer | Int, Int32, Int64 | Int, Long |
| Number | Double, Float | Float, Double |
| Boolean | Bool | Boolean |
| Enum | String with constrained enumValues | Kotlin enum class (plain name used as value) |
| Object | nested @Generatable struct | nested @Generatable data class |
| Array | [T] of any supported type | List<T> / MutableList<T> of supported type |
| Optional | Optional<T> (T?) | nullable T? |
Complex nested structures
- Swift (iOS / macOS)
- Kotlin (all platforms)
Best practices
Write descriptive @Guide annotations
The model uses them as natural-language hints about what each field should contain. Specific descriptions outperform generic ones.
Keep structures focused
Smaller, single-responsibility types produce better output than sprawling structures with twenty fields. If a type starts mixing concerns (profile + preferences + history), split it.Lower temperature for structured output
Temperature0.3–0.5 typically improves adherence to the schema. The default 0.7 is biased toward conversational variation that doesn’t help when you need parseable JSON.
Validate the decoded output
Even with constrained generation, you should handle parse failures gracefully. The model’s output is constrained against the schema but not against business invariants.- Swift (iOS / macOS)
- Kotlin (all platforms)
How it works
- Compile/load time —
@Generatableproduces a JSON Schema for your type. (Swift: compile-time macro; Kotlin: reflective build at load time.) - Configuration —
GenerationOptions.setResponseFormat(type:)/setResponseFormatType(...)installs the schema asjsonSchemaConstrainton the generation options. - Generation — the SDK constrains decoding so only tokens that produce schema-valid JSON are emitted. The model’s output is guaranteed to parse.
Error handling
| Error | When it happens |
|---|---|
LeapGeneratableSchematizationException (Kotlin) | The data class can’t be translated to JSON Schema (unsupported field type, missing primary-constructor declaration). |
LeapGeneratableDeserializationException (Kotlin) | The generated JSON can’t be deserialized into the target data class. |
Swift DecodingError | JSONDecoder rejects the generated payload — usually because the model output contains stray prose alongside the JSON; filter Complete.fullMessage.content for the .text fragments first. |
Troubleshooting
“External macro implementation could not be found” (Swift) — clean the build folder, restart Xcode, verify Swift 5.9+. Generated JSON includes prose alongside the JSON object — common with low-quality prompts. Add “Reply with only the JSON object” to the user message, lower temperature, and filter.text content fragments before decoding.
Model produces empty or trivial JSON — verify each @Guide description gives the model a concrete sense of what to fill in. Generic descriptions (“a string”) leave the model guessing.