Skip to content

Commit b27c980

Browse files
authored
Document jinja in checks and asserts (#1826)
<!-- ELLIPSIS_HIDDEN --> > [!IMPORTANT] > Adds documentation for using Jinja syntax in BAML's `@check` and `@assert` attributes, including examples and navigation updates. > > - **Documentation**: > - Adds `jinja-checks-and-asserts.mdx` to document Jinja syntax usage in `@check` and `@assert` attributes. > - Provides examples of Jinja expressions, filters, and common patterns in `jinja-checks-and-asserts.mdx`. > - Updates `checks-and-asserts.mdx`, `assert.mdx`, and `check.mdx` to reference the new Jinja documentation. > - **Navigation**: > - Adds "Jinja in Attributes" to `docs.yml` under the "Attributes" section. > > <sup>This description was created by </sup>[<img alt="Ellipsis" src="https://img.shields.io/badge/Ellipsis-blue?color=175173">](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral)<sup> for b6db554. You can [customize](https://app.ellipsis.dev/BoundaryML/settings/summaries) this summary. It will automatically update as commits are pushed.</sup> <!-- ELLIPSIS_HIDDEN -->
1 parent c8378bc commit b27c980

File tree

6 files changed

+160
-0
lines changed

6 files changed

+160
-0
lines changed

fern/01-guide/05-baml-advanced/checks-and-asserts.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ function NextInt8(a: int) -> int @assert(ok_int8, {{ this >= -128 and this < 127
3636
}
3737
```
3838

39+
See [Jinja in Attributes](/ref/attributes/jinja-in-attributes) for a longer description of the Jinja syntax
40+
available in asserts.
41+
3942
Asserts may be applied to a whole class via `@@assert`.
4043

4144
```baml BAML

fern/03-reference/baml/attributes/assert.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,3 +49,6 @@ class Foo {
4949
@@assert(baz_length_limit, {{ this.baz|length < this.bar }})
5050
}
5151
```
52+
53+
See [Jinja in Attributes](/ref/attributes/jinja-in-attributes) for a longer description of the Jinja syntax
54+
available in asserts.

fern/03-reference/baml/attributes/check.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ class Bar {
2020
}
2121
```
2222

23+
See [Jinja in Attributes](/ref/attributes/jinja-in-attributes) for a longer description of the Jinja syntax
24+
available in checks.
25+
2326
## Benefits
2427

2528
- **Non-Intrusive Validation**: Allows for validation checks without interrupting the flow of data processing.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
`@check` and `@assert` use [Jinja](/ref/prompt-syntax/what-is-jinja) syntax to specify the invariants
2+
(properties that should always hold true) of a type.
3+
4+
### Checks and Asserts
5+
6+
This example demonstrates [@assert](/ref/attributes/assert) and [@check](/ref/attributes/check) on both class fields
7+
and the class block itself, and it shows a few examples of Jinja syntax.
8+
9+
```baml BAML
10+
class Student {
11+
first_name string @assert( {{ this|length > 0 }})
12+
last_name string @assert( {{ this|length > 0 }})
13+
age int @check(old_enough, {{ this > 5 }}) @check(u8, {{ this|abs < 255 }})
14+
concentration string @assert( {{ this.regex_match("[Math|Science]")}})
15+
@@check(age_threshold, {{ this.concentration != "calculus" or this.age > 12 }})
16+
}
17+
```
18+
19+
### `this` keyword
20+
21+
Inside a Jinja expression, `this` refers to the value of a class field, if the
22+
`@assert` or `@check` is applied to a class field, and it applies to the whole
23+
object if it is applied to the whole type with `@@assert()` or `@@check()`.
24+
25+
### Filters
26+
27+
In Jinja, functions are called "filters", and they are applied to arguments
28+
by writing `some_argument|some_filter`. Filters can be applied one after the
29+
other by chaining them with additional `|`s.
30+
31+
- `abs`: Absolote value.
32+
- `capitalize`: Make the first letter uppercase
33+
- `escape`: Replace special HTML characters with their escaped counterparts
34+
- `first`: First item of a list
35+
- `last`: Last item of a list
36+
- `default(x)`: Returns `x` when applied to something undefined.
37+
- `float`: Convert to a float, or 0.0 if conversion fails
38+
- `int`: Convert to an int, or 0 if conversion fails
39+
- `join`: Concatenate a list of strings
40+
- `length`: List length
41+
- `lower`: Make the string lowercase
42+
- `upper`: Make the string uppercase
43+
- `map(filter)`: Apply a filter to each item in a list
44+
- `max`: Maximum of a list of numbers or Booleans
45+
- `min`: Minimum of a list of numbers or Booleans
46+
- `regex_match("regex")`: Return true if argument matches the regex
47+
- `reject("test")`: Filter out items that fail the test
48+
- `reverse`: Reverse a list or string
49+
- `round`: Round a float to the nearest int
50+
- `select("test_name")`: Retain the values of a list passing `test_name`
51+
- `sum`: Sum of a list of numbers
52+
- `title`: Convert a string to "Title Case"
53+
- `trim`: Remove leading and trailing whitespace from a string
54+
- `unique`: Remove duplicate entries in a list
55+
56+
### Common Patterns
57+
58+
#### Test that a substring appears inside some string
59+
60+
```baml BAML
61+
function GenerateStory(subject: string) -> string {
62+
client GPT4
63+
prompt #"Write a story about {{ subject }}"#
64+
}
65+
66+
test HorseStory {
67+
functions [GenerateStory]
68+
args {
69+
subject "Equestrian team coming-of-age story"
70+
}
71+
@@assert( {{ this|lower|regex_match("horse") }} )
72+
}
73+
```
74+
75+
We use the `lower` filter to make the whole story lowercase, and pass
76+
the result to `regex_match()` to search for an occurrance of "horse".
77+
78+
79+
#### Test that a string is an exact match
80+
81+
```baml BAML
82+
class Person {
83+
first_name string
84+
last_name string
85+
}
86+
87+
function ExtractPerson(description: string) -> Person {
88+
client GPT4
89+
prompt #"
90+
Extract a Person from the description {{ description }}.
91+
{{ ctx.output_format }}
92+
"#
93+
}
94+
95+
test ExtractJohnDoe {
96+
functions [ExtractPerson]
97+
args {
98+
description "John Doe is a 5'6\" man riding a stolen horse."
99+
}
100+
@@assert( {{ this.first_name|regex_match("^John$") }} )
101+
@@assert( {{ this.last_name == "Doe" }} )
102+
}
103+
```
104+
105+
We can use `regex_match` with special control characters indicating
106+
the beginning and end of a string, as in the first `@@assert`, or
107+
simply check equality with a literal string as in the second `@@assert`.
108+
109+
#### Test that item prices add up to a total
110+
111+
```baml BAML
112+
class Receipt {
113+
establishment string
114+
items Item[]
115+
tax_cents int
116+
total_cents int
117+
}
118+
119+
class Item {
120+
name string
121+
price_cents int
122+
}
123+
124+
function ExtractReceipt(text_receipt: string) -> Receipt {
125+
client GPT4
126+
prompt #"
127+
Extract the details of this receipt: {{ text_receipt }}
128+
{{ ctx.output_format }}
129+
"#
130+
}
131+
132+
test SmallReceipt {
133+
functions [ExtractReceipt]
134+
args {
135+
text_receipt "Nutty Squirrel. Affogato: $8.50. Kids cone: $6.50. Tax: $1. Total: $16.00"
136+
}
137+
138+
@@assert( {{ this.items|map(attribute="price_cents")|sum + this.tax_cents == this.total_cents }} )
139+
}
140+
```
141+
142+
To check that the numbers in our `Receipt` add up, we first
143+
`map` over the items to get the price of each item, then sum
144+
the list of prices, and check the sum of the items and the sales
145+
tax against the receipt total.
146+

fern/03-reference/baml/prompt-syntax/output-format.mdx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ BAML's default prefix varies based on the function's return type.
8484
<ParamField path="always_hoist_enums" type="boolean" >
8585
Whether to inline the enum definitions in the schema, or print them above. **Default: false**
8686

87+
Note that setting this to `false` means BAML will use heuristics internally to determine
88+
whether or not to hoist. `false` does not mean "never hoist".
89+
8790

8891
**Inlined**
8992
```

fern/docs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,8 @@ navigation:
476476
path: 03-reference/baml/attributes/assert.mdx
477477
- page: "@check"
478478
path: 03-reference/baml/attributes/check.mdx
479+
- page: "Jinja in Attributes"
480+
path: 03-reference/baml/attributes/jinja-checks-and-asserts.mdx
479481
- page: "@@dynamic"
480482
path: 03-reference/baml/attributes/dynamic.mdx
481483
- section: LLM Client Providers

0 commit comments

Comments
 (0)