Dynamic Types - TypeBuilder
Sometimes you have output schemas that change at runtime — for example if you have a list of Categories that you need to classify that come from a database, or your schema is user-provided.
TypeBuilder
is used to create or modify dynamic types at runtime to achieve this.
Dynamic BAML Enums
Imagine we want to make a categorizer prompt, but the list of categories to output come from a database.
- Add
@@dynamic
to the class or enum definition to mark it as dynamic in BAML.
- Import the
TypeBuilder
from baml_client in your runtime code and modifyCategory
. All dynamic types you define in BAML will be available as properties ofTypeBuilder
. Think of the typebuilder as a registry of modified runtime types that the baml function will read from when building the output schema in the prompt.
Python
TypeScript
Ruby
OpenAPI
Dynamic BAML Classes
Now we’ll add some properties to a User
class at runtime using @@dynamic.
We can then modify the User
schema at runtime. Since we marked User
with @@dynamic
, it’ll be available as a property of TypeBuilder
.
Creating new dynamic classes or enums not in BAML
The previous examples showed how to modify existing types. Here we create a new Hobbies
enum, and a new class called Address
without having them defined in BAML.
Note that you must attach the new types to the existing Return Type of your BAML function(in this case it’s User
).
TypeBuilder provides methods for building different kinds of types:
Adding descriptions to dynamic types
Creating dynamic classes and enums at runtime with BAML
The TypeBuilder
has a higher level API for creating dynamic types at runtime.
Here’s an example:
Building dynamic types from JSON schema
We have a working implementation of this, but are waiting for a concrete use case to merge it. Please chime in on the GitHub issue if this is something you’d like to use.
Testing dynamic types in BAML
When testing dynamic types there are two different cases:
- Injecting properties into dynamic types returned by the tested function.
- Injecting values into dynamic types received as arguments by the tested function.
The first case requires using the type_builder
and dynamic
blocks in the
test, whereas the second case only requires specifying the values in the args
block.
Testing return types
Dynamic classes
Suppose we have a dynamic class Resume
and we want to add a property that
stores the user’s work experience when we testing a specific function. We can
do that by specifying the types and properties that we need in the
type_builder
block.
The rendered prompt for ExtractResume
will now include the experience
field
defined in the dynamic
block and the LLM will correctly extract the experience
in the input text.
Dynamic enums
Dynamic enums can be included in the type_builder
block just like classes. The
only difference is that we inject new variants in the dynamic
block instead of
properties.
The Feedback
variant will be rendered in the prompt for ClassifyMessage
during the test execution.
Testing parameter types
When a dynamic type is used as an input parameter of a function, we can simply
pass any value in the args
block of the test and the value will be rendered in
the prompt.
Dynamic classes
Dynamic enums
Enums work the same way, any variant defined in the args
block will be
rendered normally.
For more information about dynamic types, see Type Builder.