diff --git a/docs/docs.yml b/docs/docs.yml index d7c8d75c8..9d13adf8f 100644 --- a/docs/docs.yml +++ b/docs/docs.yml @@ -131,12 +131,14 @@ navigation: path: docs/snippets/template-string.mdx - page: Test Cases path: docs/snippets/test-cases.mdx - - section: Advanced BAML Snippets + - section: Advanced BAML Features contents: - page: Dynamic Types path: docs/calling-baml/dynamic-types.mdx - page: Client Registry path: docs/calling-baml/client-registry.mdx + - page: Custom Type Validations + path: docs/calling-baml/assertions.mdx - section: BAML with Python/TS/Ruby contents: - page: Generate the BAML Client @@ -149,7 +151,7 @@ navigation: path: docs/calling-baml/streaming.mdx - page: Concurrent function calls path: docs/calling-baml/concurrent-calls.mdx - - page: Multimodal + - page: Multimodal Input path: docs/calling-baml/multi-modal.mdx - section: Observability [Paid] contents: diff --git a/docs/docs/calling-baml/assertions.mdx b/docs/docs/calling-baml/assertions.mdx new file mode 100644 index 000000000..72a5b383e --- /dev/null +++ b/docs/docs/calling-baml/assertions.mdx @@ -0,0 +1,454 @@ +--- +slug: docs/calling-baml/assertions +--- +BAML raises `BAMLValidationError` exceptions when it can't parse the response based on your type definitions. With custom type validations, you can set specific rules to ensure a field's value falls within an acceptable range. + +Validations **do not** modify the prompt or response data. They are only used to change the post hoc **validation logic** of the BAML parser. + +BAML provides two types of validations: +- `@assert` for strict, exception-raising validations +- `@check` for non-exception-raising validations, which allow you to access the data even when validation fails along with the validation results of which checks pass and fail. + +This guide covers how to write different types of `@assert` validations, but the same principles and syntax apply to `@check` validations. +See [Non-exception Raising Checks](#non-exception-raising-checks) for more information. + + +## Field-level Assertions +Field-level assertions are used to validate individual fields in a response. These assertions can be written directly as inline attributes next to the field definition or on the line following the field definition. + +### Using `@assert` +BAML will raise an exception if `Foo.bar` is not between 0 and 10. +```baml BAML +class Foo { + bar int @assert(this > 0 and this < 10) //this = Foo.bar value +} +``` + + +### Using `@assert` with `Union` Types +Note that when using [`Unions`](../snippets/supported-types.mdx#union-), it is crucial to specify where the `@assert` attribute is applied within the union type, as it is not known until runtime which type the value will be. +```baml BAML +class Foo { + bar (int @assert(this > 0 and this < 10) + | string @assert(this|length > 0 and this|contains("foobar"))) +} +``` + +In the above example, the `@assert` attribute is applied specifically to the `int` and `string` instances of the `Union`, rather than to the `Foo.bar` field as a whole. + +Likewise, the keyword `this` refers to the value of the type instance it is directly associated with (e.g., `int` or `string`). + +### Referencing other fields with `block` +The `block` syntax can be used to reference other fields within the same class, whereas `this` is used to access the current field's value. + +This is useful when defining an assertion for a field that is dependent on the validated value of another field. +```baml BAML +class User { + user_age int @assert( + this|length > 0, "user_age_invalid" + ) + + parent_age string @assert( + this > 0 and this > block.user_age, "parent_age_invalid" + ) +} +``` + + +## Block-level Assertions +To validate an entire object by considering multiple fields together after their individual validations, use a block-level assertion with `@@assert`. + +```baml BAML +class Foo { + password string @assert(this|length > 10) + confirm_password string + + @@assert(this.confirm_password == this.password) +} +``` +In this example, the `password` field must be longer than 10 characters, and the `Foo` class includes a block-level assertion to ensure `password` and `confirm_password` match. + +{/* For block-level assertions, you don't need to use the `block` keyword because `this` refers to the entire block. */} + + +## Chaining Assertions +You can have multiple assertions on a single field by using the `and` operator or by chaining multiple `@assert` attributes. + +In this example, the asserts on `bar` and `baz` are equivalent. +```baml BAML +class Foo { + bar int @assert(this > 0 and this < 10) + baz int @assert(this > 0) @assert(this < 10) +} +``` + +Chained asserts are evaluated in order from left to right. If the first assert fails, the second assert will not be evaluated. + +## Reference Assertion Parameters +Sometimes, you may need to validate a field differently for different instances of a class or based on the input to the function returning the class. + +### Function Input +Use constructor inputs for your class to define dynamic assertions. In this example, the `quote` field must be present in the `text` input string. +```baml BAML +class Citation(text: string) { + quote string @assert(this in block.text, "exact_citation_not_found") + idx int +} +``` + +Pass the `full_text` string to the `Citation` constructor to validate the `quote` field. The `block` keyword allows access to `full_text` for validation from the scope of the function. +```baml BAML +function GetCitations(full_text: string) -> Citation(text=block.full_text) { + client GPT4 + prompt #" + Generate a citation of the text below in MLA format: + {{full_text}} + + {{ctx.output_format}} + + "# +} +``` +### Parent Class Input +You may also use input assertions when composing a class from a parent class. In this example, the `quote` field must be present in the `contents` field of the `Book` class, which is passed as an input to the `Citation` class. +```baml BAML +class Citation(text: string) { + quote string @assert(this in block.text, "exact_citation_not_found") + idx int +} + +class Book(contents: string) { + citation Citation(text=block.contents) + author string + publisher string +} + +function GetBookDetails(book_contents: string) -> Book(contents=block.book_contents) { + client GPT4 + prompt #" + Gather the details of the book with the following contents: + {{book_contents}} + + {{ctx.output_format}} + "# +} +``` + + +## Writing Assertions +Assertions are represented as Jinja expressions and can be used to validate various types of data. Possible constraints include checking the length of a string, comparing two values, or verifying the presence of a substring with regular expressions. + +In the future, we plan to support shorthand syntax for common assertions to make writing them easier. + +For now, see our [Jinja cookbook / guide](../snippets/prompt-syntax/what-is-jinja.mdx) or the [Minijinja filters docs](https://docs.rs/minijinja/latest/minijinja/filters/index.html#functions) for more information on writing expressions. + + +{/* ### Operators +| Assertion | Types | +|------------------|------------------------| +| length | array, map, string | +| regex match | string | +| eq, ne | all | +| gt, ge, lt, le | int, float, string | +| xor | int, float, bool | +| and, or | int, float, bool | +| contains | string, array, map | +| index [] | array, map, string | +| min, max | int, float | */} +{/* +| custom function | all | +| unique | array | every item is unique (consider using set type?) | +| default | all | default value to fill if not found | +| reference | all | when a value references another value | */} + +{/* Operators are called using the `|` symbol, followed by the operator name. +```baml BAML +class Foo { + bar int @assert(this|gt 0) +} +``` */} + + +### Expression keywords +- `this` refers to the value of the current field being validated. +- `block` refers to the entire object being validated. It can be used to reference other fields within the same class. + + +`.field` is used to refer to a specific field within the context of `this` or `block`. +Access nested fields of a data type by chaining the field names together with a `.` as shown below. +```baml BAML +class Resume { + name string + experience string[] + +} + +class Person { + resume Resume @assert(this.experience|length > 0) + person_name name @assert(this == block.resume.name) //nested field access +} +``` + + + + + + +## Assertion Errors +### Custom Error Messages +When validations fail, your BAML function will raise a `BAMLValidationError` exception, same as when parsing fails. You can catch this exception and handle it as you see fit. + +You can define custom error messages for each assertion, which will be included in the exception for that failure case. If you don't define a custom message, BAML will use a default message. + +In this example, if the `quote` field is empty, BAML raises a `BAMLValidationError` with the message **exact_citation_not_found**. If the `website_link` field does not contain **"https://",** it raises a `BAMLValidationError` with the message **invalid_link**. +```baml BAML +class Citation { + //@assert(, ) + quote string @assert( + this|length > 0, "exact_citation_not_found" + ) + + website_link string @assert( + this|contains("https://"), "invalid_link" + ) +} +``` + +`BAMLValidationError` will propagate up to the top-level function, where you can catch it and handle it as needed. + + +```python Python +from baml_client import b +from baml_client.types import Citation + +def main(): + try: + citation: Citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...") + + # Access the value of the quote field + quote = citation.quote + website_link = citation.website_link + print(f"Quote: {quote} from {website_link}") + + except BAMLValidationError as e: + print(f"Validation error: {e.error_message}") + except Exception as e: + print(f"An unexpected error occurred: {e}") + +``` + +```typescript Typescript +import { b, BAMLValidationError } from './baml_client'; +import { Citation } from './baml_client/types'; + +const main = () => { + try { + const citation: Citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider..."); + + const quote = citation.quote.value; + console.log(`Quote: ${quote}`); + + const checks = citation.quote.checks; + for (const [check_name, result] of Object.entries(checks)) { + console.log(`Check ${check_name}: ${result ? 'passed' : 'failed'}`); + } + + const author = citation.author; + console.log(`Author: ${author}`); + } catch (e) { + if (e instanceof BAMLValidationError) { + console.log(`Validation error: ${e.error_message}`); + } else { + console.error(e); + } + } +}; +``` + + + +### Validation Order + +When validating a class with multiple assertions, BAML raises a `BAMLValidationError` for the first failed assertion it finds, validating sequentially from top to bottom. + + BAML validates assertions with dependencies after validating their dependencies, so `parent_age` would be validated after `user_age`. +```baml BAML +class User { + parent_age string @assert( + this > 0 and this > block.user_age, "parent_age_invalid" + ) + + user_age int @assert( + this|length > 0, "user_age_invalid" + ) +} +``` + + +## Non-exception Raising Checks + +Use `@check` to access data even if an assertion fails. It provides both the raw data and the assertion error without raising an exception, unlike `@assert`. This is useful when you need the data despite validation failures. Besides this, `@check` works the same as `@assert`. + + +To return both the data and the possible warning, BAML will return a `BamlCheckedValue` object, which contains the parsed data and the validation results for each check. + +To access the value, use the `value` attribute of the `BamlCheckedValue` object, and use the `checks` attribute to access a map of the checks used and their results during validation. + +```rust BamlCheckedValue +interface BamlCheckedValue { + value T + checks {} // map of error message to true (passed) or false (failed) +} +``` + +```baml BAML +class Citation { + //@check(, ) + quote string @check( + this|length > 0, "exact_citation_not_found" + ) + line_number string @assert( + this|length >= 0, "no_line_number" + ) +} + +function GetCitation(full_text: string) -> Citation { + client GPT4 + prompt #" + Generate a citation of the text below in MLA format: + {{full_text}} + + {{ctx.output_format}} + "# +} + +``` + +Note that the `line_number` field uses `@assert` instead of `@check`. This means that while `quote` will return wrapped in a `BamlCheckedValue` object, `line_number` will raise an exception if the assertion fails and return as a regular field if it passes. + +```python Python +from baml_client import b +from baml_client.types import Citation + +def main(): + citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...") + + # Access the value of the quote field + quote = citation.quote.value + print(f"Quote: {quote}") + + # Access the error messages for each check and its status + checks = citation.quote.checks + for check_name, result in checks.items(): + print(f"Check {check_name}: {'passed' if result else 'failed'}") + + # Access the author field directly, as it uses @assert + author = citation.author + print(f"Author: {author}") + +``` + +```typescript Typescript +import { b } from './baml_client' +import { Citation } from './baml_client/types' + +const main = () => { + const citation = b.GetCitation("SpaceX, is an American spacecraft manufacturer, launch service provider...") + + // Access the value of the quote field + const quote = citation.quote.value + console.log(`Quote: ${quote}`) + + // Access the error messages for each check and its status + const checks = citation.quote.checks + for (const [check_name, result] of Object.entries(checks)) { + console.log(`Check ${check_name}: ${result ? 'passed' : 'failed'}`) + } + + // Access the author field directly, as it uses @assert + const author = citation.author + console.log(`Author: ${author}`) +} +``` + + + + +You can also chain multiple `@check` and `@assert` attributes on a single field. +```baml BAML +class Foo { + bar string @check(this|length > 0, "bar_empty") + @assert(this|contains("foo"), "bar_no_foo") + @check(this|contains("fizzle"), "bar_no_fizzle") + @assert(this|contains("baz"), "bar_no_baz") +} +``` +In this example, the `@assert` statements are checked during parsing of types, and if they fail, a `BAMLValidationError` is raised. The `@check` statements are checked after parsing, and the data is returned as a `BamlCheckedValue` object with the validation results. + + When using `@check`, all checks on the response data are evaluated even if one fails. In contrast, with `@assert`, a failure will stop the parsing process and immediately raise an exception. + + +## Advanced Examples +While the following examples show more complex minijinja expressions, see the [Minijinja filters docs](https://docs.rs/minijinja/latest/minijinja/filters/index.html#functions) for more information on available operators to use in your assertions. + + +-------- +The `Address` class below demonstrates how to validate a postal code based on the country field. The postal code must be 5 digits for the USA, 6 digits for Canada, and match a specific pattern for the UK. +```baml BAML +class Address { + street string @assert(this|length > 0) + city string @assert(this|length > 0) + country string @assert(this in ["USA", "Canada", "UK"]) + postal_code string @assert( + (this|length == 5 and block.country == "USA") or + (this|length == 6 and block.country == "Canada") or + (this|matches("^[A-Z]{1,2}[0-9][A-Z0-9]? [0-9][ABD-HJLNP-UW-Z]{2}$") and block.country == "UK"), + "Invalid postal code for the specified country" + ) +} +``` +-------- + +The `Person` class below demonstrates how to individually validate a person's name, age, and email address. Additionally, it includes a block-level assertion to ensure that a person must be 18 or older to have a USA address. +```baml BAML +class Person { + name string @assert(this|length >= 2) + age int @assert(this >= 0) + email string @assert(this|matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$")) + address Address + + @@assert( + this.age >= 18 or this.address.country != "USA", + "Person must be 18 or older to have a USA address" + ) +} +``` +-------- + +The `Book` and `Library` classes below demonstrate how to validate a book's title, author, ISBN, publication year, genres, and a library's name and books. The block-level assertion in the `Library` class ensures that all books have unique ISBNs. +```baml BAML +class Book { + title string @assert(this|length > 0) + author string @assert(this|length > 0) + isbn string @assert( + this|matches("^(97(8|9))?\\d{9}(\\d|X)$"), + "Invalid ISBN format" + ) + publication_year int @assert(1000 <= this <= 2100) + genres string[] @assert(1 <= this|length <= 10) +} + +class Library { + name string + books Book[] @assert(this|length > 0) + total_books int @assert(this == block.books|length) + + @@assert( + this.books|map(attribute='isbn')|unique()|length == this.books|length, + "All books must have unique ISBNs" + ) +} +``` + + + diff --git a/docs/docs/calling-baml/dynamic-types.mdx b/docs/docs/calling-baml/dynamic-types.mdx index 0a48b4f4f..ff68b4b51 100644 --- a/docs/docs/calling-baml/dynamic-types.mdx +++ b/docs/docs/calling-baml/dynamic-types.mdx @@ -12,7 +12,7 @@ Sometimes you have a **output schemas that change at runtime** -- for example if Here are the steps to make this work: 1. Add `@@dynamic` to the class or enum definition to mark it as dynamic -```rust baml +```rust BAML enum Category { VALUE1 // normal static enum values that don't change VALUE2 diff --git a/docs/docs/calling-baml/multi-modal.mdx b/docs/docs/calling-baml/multi-modal.mdx index 90af56e51..67883a4bf 100644 --- a/docs/docs/calling-baml/multi-modal.mdx +++ b/docs/docs/calling-baml/multi-modal.mdx @@ -3,8 +3,6 @@ slug: docs/calling-baml/multi-modal --- -## Multi-modal input - ### Images Calling a BAML function with an `image` input argument type (see [image types](../snippets/supported-types.mdx)). diff --git a/docs/docs/snippets/class.mdx b/docs/docs/snippets/class.mdx index ac97b00e0..20ce5ee17 100644 --- a/docs/docs/snippets/class.mdx +++ b/docs/docs/snippets/class.mdx @@ -12,12 +12,13 @@ In the context of LLMs, classes describe the type of the variables you can injec -```baml Baml +```baml BAML class Foo { property1 string property2 int? property3 Bar[] property4 MyEnum + property5 int | string } ``` @@ -31,6 +32,8 @@ class Foo(BaseModel): property2: Optional[int]= None property3: List[Bar] property4: MyEnum + property5: Union[int, str] + ``` ```typescript Typescript Equivalent @@ -43,6 +46,7 @@ const FooZod = z.object({ property2: z.number().int().nullable().optional(), property3: z.array(BarZod), property4: MyEnumZod, + property5: z.union([z.number().int(), z.string()]) }); type Foo = z.infer; @@ -51,27 +55,71 @@ type Foo = z.infer; ## Class Attributes +### Contextual Attributes +Contextual attributes modify the prompt and serve to provide additional context to the LLM. + If set, will allow you to add fields to the class dynamically at runtime (in your python/ts/etc code). See [dynamic classes](../calling-baml/dynamic-types.mdx) for more information. + +```baml BAML +class MyClass { + property1 string + property2 int? + + @@dynamic // allows me to later property3 float[] at runtime +} +``` +### Validation Attributes +Validation attributes are used to enforce constraints on the fields of a class. They do not modify the prompt, but rather the post hoc validation logic of the BAML parser. + +Add class-level assertions using Jinja templates to ensure certain properties. If an assertion fails, a `BAMLValidationError` is raised. See [custom type assertions](../calling-baml/assertions.mdx) for details. + ```baml BAML class MyClass { property1 string property2 int? - @@dynamic // allows me to later propert3 float[] at runtime + @@assert(block.property2 > property1|length) // property2 must be greater than the length of property1 } ``` + + + +Use `@@check` to access data even if an assertion fails. This is useful in scenarios where you want to be informed of a validation failure but still need the data. It returns a `BamlCheckedValue` object with the parsed data and validation results. Access the value via the `value` attribute and the validation results via the `checks_results` attribute. See [non-exception raising type checks](../calling-baml/assertions.mdx#non-exception-checks) for details. + + +```baml BAML +class MyClass { + property1 string + property2 int? + + @@check(block.property2 > property1|length, "compare_prop1_length_with_prop2") // property2 must be greater than the length of property1 +} +``` + + + + + + + ## Field Attributes -When prompt engineering, you can also alias values and add descriptions. +When prompt engineering, you can also inline attributes to the fields of a class to provide additional context or constraints. Multiple attributes can be appended to a field. +### Contextual Attributes +Contextual attributes modify the prompt and serve to provide additional context to the LLM. This adds some additional context to the field in the prompt. - - ```baml BAML class MyClass { @@ -96,6 +148,49 @@ class MyClass { } ``` + + + +### Validation Attributes +Validation attributes are used to enforce constraints on the fields of a class. They do not modify the prompt, but rather the post hoc validation logic of the BAML parser. + + + +Add field assertions using Jinja templates to ensure specific properties. If the assertion fails, the prompt will fail. Because assertions are evaluated at runtime, `Union` cases must have type-instance-specific assertions. See [custom type assertions](../calling-baml/assertions.mdx) for more information. + +```baml BAML +class MyClass { + property1 string @alias("name") @assert(this|length > 0, "name_not_empty") + age int? @assert(this > 0, "age_positive") +} +``` + + + +The `@check` attribute allows you to access data even if an assertion fails. This is useful in scenarios where you want to be informed of a validation failure but still need the data. + +When using `@check`, the field returns a `BamlCheckedValue` object, which includes both the parsed data and the validation results. You can access the actual value through the `value` attribute and the validation results through the `checks_results` attribute. For more details, see [non-exception raising type checks](../calling-baml/assertions.mdx#non-exception-checks). + +```baml BAML +class MyClass { + property1 string @alias("name") @check(this|length > 0, "name_not_empty") + age int? @check(this > 0, "age_positive") + hometown string @check(this == "New York", "hometown_new_york") +} +``` + + + + + + + ## Constraints Classes may have any number of properties. diff --git a/docs/docs/snippets/prompt-syntax/what-is-jinja.mdx b/docs/docs/snippets/prompt-syntax/what-is-jinja.mdx index 0607d1cbe..cc997c8de 100644 --- a/docs/docs/snippets/prompt-syntax/what-is-jinja.mdx +++ b/docs/docs/snippets/prompt-syntax/what-is-jinja.mdx @@ -4,7 +4,7 @@ slug: docs/snippets/prompt-syntax/what-is-jinja --- -BAML Prompt strings are essentially [Jinja](https://jinja.palletsprojects.com/en/3.1.x/templates/) templates, which offer the ability to express logic and data manipulation within strings. Jinja is a very popular and mature templating language amongst Python developers, so Github Copilot or another LLM can already help you write most of the logic you want. +BAML Prompt strings are essentially [Minijinja](https://docs.rs/minijinja/latest/minijinja/filters/index.html#functions) templates, which offer the ability to express logic and data manipulation within strings. Jinja is a very popular and mature templating language amongst Python developers, so Github Copilot or another LLM can already help you write most of the logic you want. ## Jinja Cookbook @@ -20,7 +20,7 @@ When in doubt -- use the BAML VSCode Playground preview. It will show you the fu Here's how you can iterate over a list of items, accessing each item's attributes: -```jinja +```jinja Jinja function MyFunc(messages: Message[]) -> string { prompt #" {% for message in messages %} @@ -34,7 +34,7 @@ function MyFunc(messages: Message[]) -> string { Use conditional statements to control the flow and output of your templates based on conditions: -```jinja +```jinja Jinja function MyFunc(user: User) -> string { prompt #" {% if user.is_active %} @@ -81,4 +81,4 @@ function MyFunc(arg1: string, user: User) -> string { ``` ### Built-in filters -See [jinja docs](https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters) \ No newline at end of file +See [Jinja docs](https://jinja.palletsprojects.com/en/3.1.x/templates/#list-of-builtin-filters) \ No newline at end of file diff --git a/engine/.turbo/daemon/d1f419c7a2c5692a-turbo.log.2024-07-23 b/engine/.turbo/daemon/d1f419c7a2c5692a-turbo.log.2024-07-23 new file mode 100644 index 000000000..e69de29bb diff --git a/engine/Cargo.lock b/engine/Cargo.lock index 656399753..19504fffd 100644 --- a/engine/Cargo.lock +++ b/engine/Cargo.lock @@ -2409,6 +2409,7 @@ dependencies = [ "pest_derive", "serde", "serde_json", + "test-log", ] [[package]] diff --git a/engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs b/engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs index 22909521d..993936972 100644 --- a/engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs +++ b/engine/baml-lib/baml-core/src/ir/ir_helpers/mod.rs @@ -7,7 +7,7 @@ use crate::{ error_not_found, error_unsupported, ir::{ repr::{IntermediateRepr, Walker}, - Class, Client, Enum, EnumValue, Field, Function, RetryPolicy, TemplateString, TestCase, + Class, Client, Enum, EnumValue, Field, FunctionNode, RetryPolicy, TemplateString, TestCase, }, }; use anyhow::Result; @@ -15,14 +15,14 @@ use baml_types::{BamlMap, BamlValue}; use super::repr; -pub type FunctionWalker<'a> = Walker<'a, &'a Function>; +pub type FunctionWalker<'a> = Walker<'a, &'a FunctionNode>; pub type EnumWalker<'a> = Walker<'a, &'a Enum>; pub type EnumValueWalker<'a> = Walker<'a, &'a EnumValue>; pub type ClassWalker<'a> = Walker<'a, &'a Class>; pub type TemplateStringWalker<'a> = Walker<'a, &'a TemplateString>; pub type ClientWalker<'a> = Walker<'a, &'a Client>; pub type RetryPolicyWalker<'a> = Walker<'a, &'a RetryPolicy>; -pub type TestCaseWalker<'a> = Walker<'a, (&'a Function, &'a TestCase)>; +pub type TestCaseWalker<'a> = Walker<'a, (&'a FunctionNode, &'a TestCase)>; pub type ClassFieldWalker<'a> = Walker<'a, &'a Field>; pub trait IRHelper { @@ -89,22 +89,11 @@ impl IRHelper for IntermediateRepr { fn find_function<'a>(&'a self, function_name: &str) -> Result> { match self.walk_functions().find(|f| f.name() == function_name) { Some(f) => match f.item.elem { - repr::Function::V1(_) => { - error_unsupported!( - "function", - function_name, - "legacy functions cannot use the runtime" - ) - } - repr::Function::V2(_) => Ok(f), + repr::Function { .. } => Ok(f), }, None => { // Get best match. - let functions = self - .walk_functions() - .filter(|f| f.is_v2()) - .map(|f| f.name()) - .collect::>(); + let functions = self.walk_functions().map(|f| f.name()).collect::>(); error_not_found!("function", function_name, &functions) } } @@ -166,17 +155,7 @@ impl IRHelper for IntermediateRepr { params: &BamlMap, allow_implicit_cast_to_string: bool, ) -> Result { - let function_params = match function.inputs() { - either::Either::Left(_) => { - // legacy functions are not supported - error_unsupported!( - "function", - function.name(), - "legacy functions cannot use the runtime" - ) - } - either::Either::Right(defs) => defs, - }; + let function_params = function.inputs(); // Now check that all required parameters are present. let mut scope = ScopeStack::new(); diff --git a/engine/baml-lib/baml-core/src/ir/json_schema.rs b/engine/baml-lib/baml-core/src/ir/json_schema.rs index 152df8516..b63311946 100644 --- a/engine/baml-lib/baml-core/src/ir/json_schema.rs +++ b/engine/baml-lib/baml-core/src/ir/json_schema.rs @@ -5,7 +5,7 @@ use serde_json::json; use super::{ repr::{self}, - Class, Enum, FieldType, Function, FunctionArgs, IntermediateRepr, Walker, + Class, Enum, FieldType, FunctionArgs, FunctionNode, IntermediateRepr, Walker, }; pub trait WithJsonSchema { @@ -43,20 +43,14 @@ impl WithJsonSchema for IntermediateRepr { } } -impl WithJsonSchema for (&Function, bool) { +impl WithJsonSchema for (&FunctionNode, bool) { fn json_schema(&self) -> serde_json::Value { let (f, is_input) = self; let mut res = if *is_input { - match &f.elem { - repr::Function::V1(f) => f.inputs.json_schema(), - repr::Function::V2(f) => f.inputs.json_schema(), - } + f.elem.inputs.json_schema() } else { - match &f.elem { - repr::Function::V1(f) => f.output.elem.json_schema(), - repr::Function::V2(f) => f.output.elem.json_schema(), - } + f.elem.output.json_schema() }; // Add a title field to the schema diff --git a/engine/baml-lib/baml-core/src/ir/mod.rs b/engine/baml-lib/baml-core/src/ir/mod.rs index 120559de3..c3c61639b 100644 --- a/engine/baml-lib/baml-core/src/ir/mod.rs +++ b/engine/baml-lib/baml-core/src/ir/mod.rs @@ -19,11 +19,9 @@ pub type FieldType = baml_types::FieldType; pub type Expression = repr::Expression; pub type Identifier = repr::Identifier; pub type TypeValue = baml_types::TypeValue; -pub type Function = repr::Node; +pub type FunctionNode = repr::Node; #[allow(dead_code)] -pub(super) type FunctionV1 = repr::FunctionV1; -#[allow(dead_code)] -pub(super) type FunctionV2 = repr::FunctionV2; +pub(super) type Function = repr::Function; pub(super) type FunctionArgs = repr::FunctionArgs; pub(super) type Impl = repr::Node; pub type Client = repr::Node; diff --git a/engine/baml-lib/baml-core/src/ir/repr.rs b/engine/baml-lib/baml-core/src/ir/repr.rs index 262a69457..7e7672db1 100644 --- a/engine/baml-lib/baml-core/src/ir/repr.rs +++ b/engine/baml-lib/baml-core/src/ir/repr.rs @@ -1,17 +1,20 @@ -use std::collections::HashSet; +use std::{collections::HashSet, default}; use anyhow::{anyhow, bail, Context, Result}; use baml_types::FieldType; use either::Either; - use indexmap::IndexMap; + +use internal_baml_diagnostics::DatamodelError; + use internal_baml_parser_database::{ walkers::{ ClassWalker, ClientWalker, ConfigurationWalker, EnumValueWalker, EnumWalker, FieldWalker, - FunctionWalker, TemplateStringWalker, VariantWalker, + FunctionWalker, TemplateStringWalker, }, - ParserDatabase, PromptAst, RetryPolicyStrategy, ToStringAttributes, WithStaticRenames, + ParserDatabase, PromptAst, RetryPolicyStrategy, ToStringAttributes, }; +use internal_baml_schema_ast::ast::SubType; use internal_baml_schema_ast::ast::{self, FieldArity, WithName, WithSpan}; use serde::Serialize; @@ -139,8 +142,7 @@ impl IntermediateRepr { .map(|e| e.node(db)) .collect::>>()?, functions: db - .walk_old_functions() - .chain(db.walk_new_functions()) + .walk_functions() .map(|e| e.node(db)) .collect::>>()?, clients: db @@ -199,13 +201,6 @@ pub struct NodeAttributes { #[serde(with = "indexmap::map::serde_seq")] meta: IndexMap, - /// Overrides for the specified AST node in a given implementation (which is keyed by FunctionId - /// and ImplementationId). In .baml files these are represented in the implementation, but in the - /// IR AST we attach them to the AST node so that all metadata associated with an IRnode can be - /// accessed from that node, rather than through a different IR node. - #[serde(with = "indexmap::map::serde_seq")] - overrides: IndexMap<(FunctionId, ImplementationId), IndexMap>, - // Spans #[serde(skip)] pub span: Option, @@ -267,7 +262,6 @@ pub trait WithRepr { fn attributes(&self, _: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: IndexMap::new(), - overrides: IndexMap::new(), span: None, } } @@ -292,19 +286,24 @@ fn type_with_arity(t: FieldType, arity: &FieldArity) -> FieldType { impl WithRepr for ast::FieldType { fn repr(&self, db: &ParserDatabase) -> Result { Ok(match self { - ast::FieldType::Identifier(arity, idn) => type_with_arity( - match idn { - ast::Identifier::Primitive(t, ..) => FieldType::Primitive(*t), - ast::Identifier::Local(name, _) => match db.find_type(idn) { - Some(Either::Left(_class_walker)) => Ok(FieldType::Class(name.clone())), - Some(Either::Right(_enum_walker)) => Ok(FieldType::Enum(name.clone())), - None => Err(anyhow!("Field type uses unresolvable local identifier")), - }?, - _ => bail!("Field type uses unsupported identifier type"), + ast::FieldType::Primitive(_, typeval, ..) => { + let repr = FieldType::Primitive(typeval.clone()); + + repr + } + ast::FieldType::Symbol(arity, idn, ..) => type_with_arity( + match db.find_type_by_str(idn) { + Some(Either::Left(class_walker)) => { + FieldType::Class(class_walker.name().to_string()) + } + Some(Either::Right(enum_walker)) => { + FieldType::Enum(enum_walker.name().to_string()) + } + None => return Err(anyhow!("Field type uses unresolvable local identifier")), }, arity, ), - ast::FieldType::List(ft, dims, _) => { + ast::FieldType::List(ft, dims, ..) => { // NB: potential bug: this hands back a 1D list when dims == 0 let mut repr = FieldType::List(Box::new(ft.repr(db)?)); @@ -314,11 +313,11 @@ impl WithRepr for ast::FieldType { repr } - ast::FieldType::Map(kv, _) => { + ast::FieldType::Map(kv, ..) => { // NB: we can't just unpack (*kv) into k, v because that would require a move/copy FieldType::Map(Box::new((*kv).0.repr(db)?), Box::new((*kv).1.repr(db)?)) } - ast::FieldType::Union(arity, t, _) => { + ast::FieldType::Union(arity, t, ..) => { // NB: preempt union flattening by mixing arity into union types let mut types = t.iter().map(|ft| ft.repr(db)).collect::>>()?; @@ -328,7 +327,7 @@ impl WithRepr for ast::FieldType { FieldType::Union(types) } - ast::FieldType::Tuple(arity, t, _) => type_with_arity( + ast::FieldType::Tuple(arity, t, ..) => type_with_arity( FieldType::Tuple(t.iter().map(|ft| ft.repr(db)).collect::>>()?), arity, ), @@ -414,9 +413,7 @@ impl WithRepr for ast::Expression { // because that's modelled as Identifier::ENV, not Identifier::Ref Ok(Expression::String(r.full_name.clone())) } - ast::Identifier::Primitive(p, _) => { - Ok(Expression::Identifier(Identifier::Primitive(*p))) - } + ast::Identifier::Invalid(_, _) => { Err(anyhow!("Cannot represent an invalid parser-AST identifier")) } @@ -447,7 +444,7 @@ impl WithRepr for TemplateStringWalker<'_> { fn attributes(&self, _: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: Default::default(), - overrides: Default::default(), + span: Some(self.span().clone()), } } @@ -456,8 +453,7 @@ impl WithRepr for TemplateStringWalker<'_> { Ok(TemplateString { name: self.name().to_string(), params: self.ast_node().input().map_or(vec![], |e| match e { - ast::FunctionArgs::Named(arg_list) => arg_list - .args + ast::BlockArgs { args, .. } => args .iter() .filter_map(|(id, arg)| { arg.field_type @@ -469,15 +465,12 @@ impl WithRepr for TemplateStringWalker<'_> { .ok() }) .collect::>(), - ast::FunctionArgs::Unnamed(_) => { - vec![] - } + _ => vec![], }), content: self.template_string().to_string(), }) } } - type EnumId = String; #[derive(serde::Serialize, Debug)] @@ -493,23 +486,9 @@ impl WithRepr for EnumValueWalker<'_> { fn attributes(&self, db: &ParserDatabase) -> NodeAttributes { let mut attributes = NodeAttributes { meta: to_ir_attributes(db, self.get_default_attributes()), - overrides: IndexMap::new(), span: Some(self.span().clone()), }; - for r#fn in db.walk_old_functions() { - for r#impl in r#fn.walk_variants() { - let node_attributes = to_ir_attributes(db, self.get_override(&r#impl)); - - if !node_attributes.is_empty() { - attributes.overrides.insert( - (r#fn.name().to_string(), r#impl.name().to_string()), - node_attributes, - ); - } - } - } - attributes } @@ -520,26 +499,11 @@ impl WithRepr for EnumValueWalker<'_> { impl WithRepr for EnumWalker<'_> { fn attributes(&self, db: &ParserDatabase) -> NodeAttributes { - let mut attributes = NodeAttributes { - meta: to_ir_attributes(db, self.get_default_attributes()), - overrides: IndexMap::new(), + let attributes = NodeAttributes { + meta: to_ir_attributes(db, self.get_default_attributes(SubType::Enum)), span: Some(self.span().clone()), }; - - attributes.meta = to_ir_attributes(db, self.get_default_attributes()); - - for r#fn in db.walk_old_functions() { - for r#impl in r#fn.walk_variants() { - let node_attributes = - to_ir_attributes(db, r#impl.find_serializer_attributes(self.name())); - if !node_attributes.is_empty() { - attributes.overrides.insert( - (r#fn.name().to_string(), r#impl.name().to_string()), - node_attributes, - ); - } - } - } + println!("Enum Attributes: {:?}", attributes); attributes } @@ -563,31 +527,26 @@ pub struct Field { impl WithRepr for FieldWalker<'_> { fn attributes(&self, db: &ParserDatabase) -> NodeAttributes { - let mut attributes = NodeAttributes { + let attributes = NodeAttributes { meta: to_ir_attributes(db, self.get_default_attributes()), - overrides: IndexMap::new(), span: Some(self.span().clone()), }; - for r#fn in db.walk_old_functions() { - for r#impl in r#fn.walk_variants() { - let node_attributes = to_ir_attributes(db, self.get_override(&r#impl)); - if !node_attributes.is_empty() { - attributes.overrides.insert( - (r#fn.name().to_string(), r#impl.name().to_string()), - node_attributes, - ); - } - } - } - attributes } fn repr(&self, db: &ParserDatabase) -> Result { Ok(Field { name: self.name().to_string(), - r#type: self.ast_field().field_type.node(db)?, + r#type: Node { + elem: self + .ast_field() + .expr + .clone() + .ok_or(anyhow!("Field type is None"))? + .repr(db)?, + attributes: self.attributes(db), + }, }) } } @@ -603,27 +562,14 @@ pub struct Class { impl WithRepr for ClassWalker<'_> { fn attributes(&self, db: &ParserDatabase) -> NodeAttributes { - let mut attributes = NodeAttributes { - meta: to_ir_attributes(db, self.get_default_attributes()), - overrides: IndexMap::new(), + let default_attributes = self.get_default_attributes(SubType::Class); + println!("Default Attributes: {:?}", default_attributes); + let attributes = NodeAttributes { + meta: to_ir_attributes(db, default_attributes), span: Some(self.span().clone()), }; - attributes.meta = to_ir_attributes(db, self.get_default_attributes()); - - for r#fn in db.walk_old_functions() { - for r#impl in r#fn.walk_variants() { - let node_attributes = - to_ir_attributes(db, r#impl.find_serializer_attributes(self.name())); - if !node_attributes.is_empty() { - attributes.overrides.insert( - (r#fn.name().to_string(), r#impl.name().to_string()), - node_attributes, - ); - } - } - } - + println!("Class Attributes: {:?}", attributes); attributes } @@ -697,65 +643,33 @@ pub enum FunctionArgs { type FunctionId = String; -#[derive(serde::Serialize, Debug)] -#[serde(tag = "version")] -pub enum Function { - V1(FunctionV1), - V2(FunctionV2), -} - impl Function { pub fn name(&self) -> &str { - match self { - Function::V1(f) => &f.name, - Function::V2(f) => &f.name, - } + &self.name } pub fn output(&self) -> &FieldType { - match &self { - Function::V1(f) => &f.output.elem, - Function::V2(f) => &f.output.elem, - } + &self.output } - pub fn inputs(&self) -> either::Either<&FunctionArgs, &Vec<(String, FieldType)>> { - match &self { - Function::V1(f) => either::Either::Left(&f.inputs), - Function::V2(f) => either::Either::Right(&f.inputs), - } + pub fn inputs(&self) -> &Vec<(String, FieldType)> { + &self.inputs } pub fn tests(&self) -> &Vec> { - match &self { - Function::V1(f) => &f.tests, - Function::V2(f) => &f.tests, - } + &self.tests } pub fn configs(&self) -> Option<&Vec> { - match &self { - Function::V1(_) => None, - Function::V2(f) => Some(&f.configs), - } + Some(&self.configs) } } #[derive(serde::Serialize, Debug)] -pub struct FunctionV1 { - pub name: FunctionId, - pub inputs: FunctionArgs, - pub output: Node, - pub impls: Vec>, - pub tests: Vec>, - pub default_impl: Option, -} - -#[derive(serde::Serialize, Debug)] -pub struct FunctionV2 { +pub struct Function { pub name: FunctionId, pub inputs: Vec<(String, FieldType)>, - pub output: Node, + pub output: FieldType, pub tests: Vec>, pub configs: Vec, pub default_config: String, @@ -770,114 +684,6 @@ pub struct FunctionConfig { pub client: ClientId, } -impl WithRepr for VariantWalker<'_> { - fn attributes(&self, _db: &ParserDatabase) -> NodeAttributes { - NodeAttributes { - meta: IndexMap::new(), - overrides: IndexMap::new(), - span: Some(self.span().clone()), - } - } - - fn repr(&self, db: &ParserDatabase) -> Result { - let function_name = self.ast_variant().function_name().name(); - let impl_name = self.name(); - // Convert the IndexMap to a Vec of tuples - let mut replacers_vec: Vec<(_, _)> = self - .properties() - .replacers - // NB: .0 should really be .input - .0 - .iter() - .map(|r| (r.0.key(), r.1.clone())) - .collect(); - // Sort the Vec by the keys - replacers_vec.sort_by(|a, b| a.0.cmp(&b.0)); - // Convert the sorted Vec back to an IndexMap - let sorted_replacers: IndexMap = replacers_vec - .into_iter() - .map(|(k, v)| (k.clone(), v.clone())) - .collect(); - - Ok(Implementation { - r#type: OracleType::LLM, - name: self.name().to_string(), - function_name: function_name.to_string(), - prompt: self.properties().to_prompt().repr(db)?, - input_replacers: sorted_replacers, - output_replacers: self - .properties() - .replacers - // NB: .1 should really be .output - .1 - .iter() - .map(|r| (r.0.key(), r.1.clone())) - .collect(), - client: self.properties().client.value.clone(), - overrides: self - .ast_variant() - .iter_serializers() - .filter_map(|(_k, v)| { - let matches = match self.db.find_type_by_str(v.name()) { - Some(either) => match either { - Either::Left(left_value) => { - let cls_res = left_value.repr(db); - match cls_res { - Ok(cls) => cls - .static_fields - .iter() - .flat_map(|f| { - process_field( - &f.attributes.overrides, - &f.elem.name, - function_name, - impl_name, - ) - }) - .collect::>(), - - _ => vec![], - } - } - Either::Right(right_value) => { - let enm_res = right_value.repr(db); - match enm_res { - Ok(enm) => enm - .values - .iter() - .flat_map(|f| { - process_field( - &f.attributes.overrides, - &f.elem.0, - function_name, - impl_name, - ) - }) - .collect::>(), - - _ => vec![], - } - } - }, - None => { - vec![] - } - }; - - if matches.is_empty() { - None - } else { - Some(AliasOverride { - name: v.name().to_string(), - aliased_keys: matches, - }) - } - }) - .collect::>(), - }) - } -} - fn process_field( overrides: &IndexMap<(String, String), IndexMap>, // Adjust the type according to your actual field type original_name: &str, @@ -926,79 +732,30 @@ impl WithRepr for FunctionWalker<'_> { fn attributes(&self, _: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: Default::default(), - overrides: Default::default(), span: Some(self.span().clone()), } } fn repr(&self, db: &ParserDatabase) -> Result { - if self.is_old_function() { - Ok(Function::V1(self.repr(db)?)) - } else { - Ok(Function::V2(self.repr(db)?)) - } - } -} - -impl WithRepr for FunctionWalker<'_> { - fn repr(&self, db: &ParserDatabase) -> Result { - if !self.is_old_function() { - bail!("Cannot represent a new function as a FunctionV1") - } - Ok(FunctionV1 { + Ok(Function { name: self.name().to_string(), - inputs: match self.ast_function().input() { - ast::FunctionArgs::Named(arg_list) => FunctionArgs::NamedArgList( - arg_list - .args - .iter() - .map(|(id, arg)| Ok((id.name().to_string(), arg.field_type.repr(db)?))) - .collect::>>()?, - ), - ast::FunctionArgs::Unnamed(arg) => { - FunctionArgs::UnnamedArg(arg.field_type.node(db)?.elem) - } - }, - output: match self.ast_function().output() { - ast::FunctionArgs::Named(_) => bail!("Functions may not return named args"), - ast::FunctionArgs::Unnamed(arg) => arg.field_type.node(db), - }?, - default_impl: self.metadata().default_impl.as_ref().map(|f| f.0.clone()), - impls: { - let mut impls = self - .walk_variants() - .map(|e| e.node(db)) - .collect::>>()?; - impls.sort_by(|a, b| a.elem.name.cmp(&&b.elem.name)); - impls - }, - tests: self - .walk_tests() - .map(|e| e.node(db)) + inputs: self + .ast_function() + .input() + .expect("msg") + .args + .iter() + .map(|arg| { + let field_type = arg.1.field_type.repr(db)?; + Ok((arg.0.to_string(), field_type)) + }) .collect::>>()?, - }) - } -} - -impl WithRepr for FunctionWalker<'_> { - fn repr(&self, db: &ParserDatabase) -> Result { - if self.is_old_function() { - bail!("Cannot represent a new function as a FunctionV1") - } - Ok(FunctionV2 { - name: self.name().to_string(), - inputs: match self.ast_function().input() { - ast::FunctionArgs::Named(arg_list) => arg_list - .args - .iter() - .map(|(id, arg)| Ok((id.name().to_string(), arg.field_type.repr(db)?))) - .collect::>>()?, - ast::FunctionArgs::Unnamed(_) => bail!("Unnamed args not supported"), - }, - output: match self.ast_function().output() { - ast::FunctionArgs::Named(_) => bail!("Functions may not return named args"), - ast::FunctionArgs::Unnamed(arg) => arg.field_type.node(db), - }?, + output: self + .ast_function() + .output() + .expect("need block arg") + .field_type + .repr(db)?, configs: vec![FunctionConfig { name: "default_config".to_string(), prompt_template: self.jinja_prompt().to_string(), @@ -1032,7 +789,6 @@ impl WithRepr for ClientWalker<'_> { fn attributes(&self, _: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: IndexMap::new(), - overrides: IndexMap::new(), span: Some(self.span().clone()), } } @@ -1073,7 +829,6 @@ impl WithRepr for ConfigurationWalker<'_> { fn attributes(&self, _db: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: IndexMap::new(), - overrides: IndexMap::new(), span: Some(self.span().clone()), } } @@ -1104,7 +859,6 @@ impl WithRepr for ConfigurationWalker<'_> { fn attributes(&self, _db: &ParserDatabase) -> NodeAttributes { NodeAttributes { meta: IndexMap::new(), - overrides: IndexMap::new(), span: Some(self.span().clone()), } } diff --git a/engine/baml-lib/baml-core/src/ir/walker.rs b/engine/baml-lib/baml-core/src/ir/walker.rs index 3b0bd80a9..4751eb703 100644 --- a/engine/baml-lib/baml-core/src/ir/walker.rs +++ b/engine/baml-lib/baml-core/src/ir/walker.rs @@ -8,59 +8,41 @@ use std::collections::HashMap; use super::{ repr::{self, FunctionConfig}, - Class, Client, Enum, EnumValue, Expression, Field, Function, FunctionV2, Identifier, Impl, + Class, Client, Enum, EnumValue, Expression, Field, Function, FunctionNode, Identifier, Impl, RetryPolicy, TemplateString, TestCase, Walker, }; -impl<'a> Walker<'a, &'a Function> { +impl<'a> Walker<'a, &'a FunctionNode> { pub fn name(&self) -> &'a str { self.elem().name() } pub fn is_v1(&self) -> bool { - matches!(self.item.elem, repr::Function::V1(_)) + false } pub fn is_v2(&self) -> bool { - matches!(self.item.elem, repr::Function::V2(_)) - } - - pub fn as_v2(&self) -> Option<&'a FunctionV2> { - match &self.item.elem { - repr::Function::V1(_) => None, - repr::Function::V2(f) => Some(f), - } + true } pub fn client_name(&self) -> Option<&'a str> { - if let Some(v2) = self.as_v2() { - if let Some(c) = v2.configs.first() { - return Some(c.client.as_str()); - } + if let Some(c) = self.elem().configs.first() { + return Some(c.client.as_str()); } None } - pub fn walk_impls( &'a self, - ) -> either::Either< - impl Iterator>, - impl Iterator>, - > { - match &self.item.elem { - repr::Function::V1(f) => either::Either::Left(f.impls.iter().map(|i| Walker { - db: self.db, - item: (self.item, i), - })), - repr::Function::V2(f) => either::Either::Right(f.configs.iter().map(|c| Walker { - db: self.db, - item: (self.item, c), - })), - } + ) -> impl Iterator> { + self.elem().configs.iter().map(|c| Walker { + db: self.db, + item: (self.elem(), c), + }) } - - pub fn walk_tests(&'a self) -> impl Iterator> { + pub fn walk_tests( + &'a self, + ) -> impl Iterator> { self.elem().tests().iter().map(|i| Walker { db: self.db, item: (self.item, i), @@ -70,7 +52,7 @@ impl<'a> Walker<'a, &'a Function> { pub fn find_test( &'a self, test_name: &str, - ) -> Option> { + ) -> Option> { self.walk_tests().find(|t| t.item.1.elem.name == test_name) } @@ -79,16 +61,11 @@ impl<'a> Walker<'a, &'a Function> { } pub fn output(&self) -> &'a baml_types::FieldType { - match &self.item.elem { - repr::Function::V1(f) => &f.output.elem, - repr::Function::V2(f) => &f.output.elem, - } + self.elem().output() } - pub fn inputs( - &self, - ) -> either::Either<&'a repr::FunctionArgs, &'a Vec<(String, baml_types::FieldType)>> { - self.item.elem.inputs() + pub fn inputs(&self) -> &'a Vec<(String, baml_types::FieldType)> { + self.elem().inputs() } pub fn span(&self) -> Option<&crate::Span> { @@ -234,9 +211,9 @@ impl Expression { } } -impl<'a> Walker<'a, (&'a Function, &'a Impl)> { +impl<'a> Walker<'a, (&'a FunctionNode, &'a Impl)> { #[allow(dead_code)] - pub fn function(&'a self) -> Walker<'a, &'a Function> { + pub fn function(&'a self) -> Walker<'a, &'a FunctionNode> { Walker { db: self.db, item: self.item.0, @@ -248,7 +225,7 @@ impl<'a> Walker<'a, (&'a Function, &'a Impl)> { } } -impl<'a> Walker<'a, (&'a Function, &'a TestCase)> { +impl<'a> Walker<'a, (&'a FunctionNode, &'a TestCase)> { pub fn matches(&self, function_name: &str, test_name: &str) -> bool { self.item.0.elem.name() == function_name && self.item.1.elem.name == test_name } @@ -279,7 +256,7 @@ impl<'a> Walker<'a, (&'a Function, &'a TestCase)> { .collect() } - pub fn function(&'a self) -> Walker<'a, &'a Function> { + pub fn function(&'a self) -> Walker<'a, &'a FunctionNode> { Walker { db: self.db, item: self.item.0, diff --git a/engine/baml-lib/baml-core/src/validate/generator_loader/mod.rs b/engine/baml-lib/baml-core/src/validate/generator_loader/mod.rs index a32c80b6b..9234ac921 100644 --- a/engine/baml-lib/baml-core/src/validate/generator_loader/mod.rs +++ b/engine/baml-lib/baml-core/src/validate/generator_loader/mod.rs @@ -23,7 +23,7 @@ pub(crate) fn load_generators_from_ast<'i>( } fn parse_generator( - ast_generator: &ast::GeneratorConfig, + ast_generator: &ast::ValueExprBlock, diagnostics: &mut Diagnostics, ) -> Option { let errors = match v2::parse_generator(ast_generator, &diagnostics.root_path) { diff --git a/engine/baml-lib/baml-core/src/validate/generator_loader/v0.rs b/engine/baml-lib/baml-core/src/validate/generator_loader/v0.rs index 6663a155b..e825bed19 100644 --- a/engine/baml-lib/baml-core/src/validate/generator_loader/v0.rs +++ b/engine/baml-lib/baml-core/src/validate/generator_loader/v0.rs @@ -64,7 +64,7 @@ fn parse_optional_key<'a>( } pub(crate) fn parse_generator( - ast_generator: &ast::GeneratorConfig, + ast_generator: &ast::ValueExprBlock, baml_src: &PathBuf, ) -> Result> { let generator_name = ast_generator.name(); @@ -79,14 +79,14 @@ pub(crate) fn parse_generator( let args = ast_generator .fields() .iter() - .map(|arg| match &arg.value { + .map(|arg| match &arg.expr { Some(expr) => { if FIRST_CLASS_PROPERTIES.iter().any(|k| *k == arg.name()) { Ok((arg.name(), expr)) } else { Err(DatamodelError::new_property_not_known_error( arg.name(), - arg.span.clone(), + arg.span().clone(), FIRST_CLASS_PROPERTIES.to_vec(), )) } diff --git a/engine/baml-lib/baml-core/src/validate/generator_loader/v1.rs b/engine/baml-lib/baml-core/src/validate/generator_loader/v1.rs index 922d43ad7..37e8b2f65 100644 --- a/engine/baml-lib/baml-core/src/validate/generator_loader/v1.rs +++ b/engine/baml-lib/baml-core/src/validate/generator_loader/v1.rs @@ -58,7 +58,7 @@ fn parse_optional_key<'a>( } pub(crate) fn parse_generator( - ast_generator: &ast::GeneratorConfig, + ast_generator: &ast::ValueExprBlock, baml_src: &PathBuf, ) -> Result> { let generator_name = ast_generator.name(); @@ -73,14 +73,14 @@ pub(crate) fn parse_generator( let args = ast_generator .fields() .iter() - .map(|arg| match &arg.value { + .map(|arg| match &arg.expr { Some(expr) => { if FIRST_CLASS_PROPERTIES.iter().any(|k| *k == arg.name()) { Ok((arg.name(), expr)) } else { Err(DatamodelError::new_property_not_known_error( arg.name(), - arg.span.clone(), + arg.span().clone(), FIRST_CLASS_PROPERTIES.to_vec(), )) } diff --git a/engine/baml-lib/baml-core/src/validate/generator_loader/v2.rs b/engine/baml-lib/baml-core/src/validate/generator_loader/v2.rs index 13ac2b434..94a5a0824 100644 --- a/engine/baml-lib/baml-core/src/validate/generator_loader/v2.rs +++ b/engine/baml-lib/baml-core/src/validate/generator_loader/v2.rs @@ -61,7 +61,7 @@ fn parse_optional_key<'a>( } pub(crate) fn parse_generator( - ast_generator: &ast::GeneratorConfig, + ast_generator: &ast::ValueExprBlock, baml_src: &PathBuf, ) -> Result> { let generator_name = ast_generator.name(); @@ -77,14 +77,14 @@ pub(crate) fn parse_generator( let args = ast_generator .fields() .iter() - .map(|arg| match &arg.value { + .map(|arg| match &arg.expr { Some(expr) => { if FIRST_CLASS_PROPERTIES.iter().any(|k| *k == arg.name()) { Ok((arg.name(), expr)) } else { Err(DatamodelError::new_property_not_known_error( arg.name(), - arg.span.clone(), + arg.span().clone(), FIRST_CLASS_PROPERTIES.to_vec(), )) } diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations.rs index df3a3da89..72c9f11e3 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations.rs @@ -5,14 +5,12 @@ mod cycle; mod enums; mod functions; mod types; -mod variants; use super::context::Context; pub(super) fn validate(ctx: &mut Context<'_>) { enums::validate(ctx); classes::validate(ctx); - variants::validate(ctx); functions::validate(ctx); clients::validate(ctx); configurations::validate(ctx); diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/classes.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/classes.rs index 946963d63..a0b2a6036 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/classes.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/classes.rs @@ -8,11 +8,15 @@ pub(super) fn validate(ctx: &mut Context<'_>) { for c in cls.static_fields() { let field = c.ast_field(); - validate_type(ctx, &field.field_type); + if let Some(ft) = &field.expr { + validate_type(ctx, &ft); + } } for c in cls.dynamic_fields() { let field = c.ast_field(); - validate_type(ctx, &field.field_type); + if let Some(ft) = &field.expr { + validate_type(ctx, &ft); + } } } } diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/configurations.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/configurations.rs index 45899fd20..9876e138f 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/configurations.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/configurations.rs @@ -6,9 +6,7 @@ pub(super) fn validate(ctx: &mut Context<'_>) { for _config in ctx.db.walk_retry_policies() { // Nothing to validate. } - for _config in ctx.db.walk_printers() { - // Nothing to validate. - } + for config in ctx.db.walk_test_cases() { // Ensure that the test case name is valid. let case = config.test_case(); diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/cycle.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/cycle.rs index b07fb1b2e..62dbe0785 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/cycle.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/cycle.rs @@ -1,7 +1,7 @@ use std::collections::HashSet; use internal_baml_diagnostics::DatamodelError; -use internal_baml_schema_ast::ast::{ClassId, WithIdentifier, WithName, WithSpan}; +use internal_baml_schema_ast::ast::{TypeExpId, WithIdentifier, WithName, WithSpan}; use crate::validate::validation_pipeline::context::Context; @@ -27,7 +27,7 @@ pub(super) fn validate(ctx: &mut Context<'_>) { .collect::>(); // Now we can check for cycles using topological sort. - let mut stack: Vec<(ClassId, Vec)> = Vec::new(); // This stack now also keeps track of the path + let mut stack: Vec<(TypeExpId, Vec)> = Vec::new(); // This stack now also keeps track of the path let mut visited = HashSet::new(); let mut in_stack = HashSet::new(); diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/functions.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/functions.rs index 649b6d60f..ea8cd79f9 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/functions.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/functions.rs @@ -1,51 +1,12 @@ +use crate::validate::validation_pipeline::context::Context; + use internal_baml_diagnostics::{DatamodelError, DatamodelWarning, Span}; -use internal_baml_schema_ast::ast::{WithIdentifier, WithName, WithSpan}; -use crate::validate::validation_pipeline::context::Context; +use internal_baml_schema_ast::ast::{WithIdentifier, WithName, WithSpan}; use super::types::validate_type; pub(super) fn validate(ctx: &mut Context<'_>) { - for func in ctx.db.walk_old_functions() { - for args in func.walk_input_args().chain(func.walk_output_args()) { - let arg = args.ast_arg(); - validate_type(ctx, &arg.1.field_type) - } - - // Check if the function has multiple impls, if it does, - // we require an impl. - match &func.metadata().default_impl { - Some((default_impl, span)) => { - if !func - .walk_variants() - .find(|v| v.name() == default_impl) - .is_some() - { - ctx.push_error(DatamodelError::new_impl_not_found_error( - &default_impl, - func.walk_variants() - .map(|v| v.name().to_string()) - .collect::>(), - span.clone(), - )) - } - } - None => { - let num_impls = func.walk_variants().len(); - if num_impls >= 2 { - ctx.push_error(DatamodelError::new_validation_error( - &format!( - "{} has multiple impls({}). Add a `default_impl your_impl` field to the function", - func.name(), - num_impls - ), - func.identifier().span().clone(), - )) - } - } - } - } - let clients = ctx .db .walk_clients() @@ -74,9 +35,7 @@ pub(super) fn validate(ctx: &mut Context<'_>) { }; defined_types.start_scope(); - if let Some(internal_baml_schema_ast::ast::FunctionArgs::Named(p)) = - template.ast_node().input() - { + if let Some(p) = template.ast_node().input() { p.args.iter().for_each(|(name, t)| { defined_types.add_variable(name.name(), ctx.db.to_jinja_type(&t.field_type)) }); @@ -111,7 +70,7 @@ pub(super) fn validate(ctx: &mut Context<'_>) { defined_types.errors_mut().clear(); } - for func in ctx.db.walk_new_functions() { + for func in ctx.db.walk_functions() { for args in func.walk_input_args().chain(func.walk_output_args()) { let arg = args.ast_arg(); validate_type(ctx, &arg.1.field_type) @@ -130,13 +89,37 @@ pub(super) fn validate(ctx: &mut Context<'_>) { )) } } + // for arg in func.walk_output_args() { + // let arg_ast = arg.ast_arg(); + // let type_name = arg_ast.1.name().to_string(); // Store the name in a variable + // match arg_ast.1.field_type { + // FieldType::Symbol(..) if ctx.db.find_type_by_str(type_name.as_str()).is_none() => { + // ctx.push_error(DatamodelError::not_found_error( + // &format!( + // "Output argument cannot be resolved. Did you mean something else?" + // ), + // &arg_ast.1.name(), + // arg_ast.1.span().clone(), + // ctx.db + // .walk_classes() + // .chain(ctx.db.walk_enums()) + // .map(|c| c.name().to_string()) + // .collect(), + // )); + // } + // _ => {} + // } + // } let prompt = func.metadata().prompt.as_ref().unwrap(); defined_types.start_scope(); + func.walk_input_args().for_each(|arg| { - let name = arg.name(); - let field_type = ctx.db.to_jinja_type(arg.field_type()); - defined_types.add_variable(name, field_type); + let name = arg.ast_arg().0.unwrap().name().to_string(); + + let field_type = ctx.db.to_jinja_type(&arg.ast_arg().1.field_type); + + defined_types.add_variable(&name, field_type); }); match internal_baml_jinja::validate_template( func.name(), @@ -146,10 +129,10 @@ pub(super) fn validate(ctx: &mut Context<'_>) { Ok(_) => {} Err(e) => { let pspan = prompt.span(); - if let Some(_e) = e.parsing_errors { + if let Some(e) = e.parsing_errors { // ctx.push_error(DatamodelError::new_validation_error( // &format!("Error parsing jinja template: {}", e), - // e.line(), + // // e., // )) } else { e.errors.iter().for_each(|t| { diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/types.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/types.rs index 42754a94b..dd69ab134 100644 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/types.rs +++ b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/types.rs @@ -30,21 +30,15 @@ fn validate_type_exists(ctx: &mut Context<'_>, field_type: &FieldType) { .iter() .for_each(|f| match ctx.db.find_type(f) { Some(_) => {} - None => match f { - Identifier::Primitive(..) => {} - _ => errors_with_names(ctx, f), - }, + None => errors_with_names(ctx, f), }); } fn validate_type_allowed(ctx: &mut Context<'_>, field_type: &FieldType) { match field_type { - FieldType::Map(kv_types, _) => { + FieldType::Map(kv_types, ..) => { match &kv_types.0 { - FieldType::Identifier( - FieldArity::Required, - Identifier::Primitive(TypeValue::String, _), - ) => {} + FieldType::Primitive(FieldArity::Required, _, ..) => {} key_type => { ctx.push_error(DatamodelError::new_validation_error( "Maps may only have strings as keys", @@ -55,9 +49,34 @@ fn validate_type_allowed(ctx: &mut Context<'_>, field_type: &FieldType) { validate_type_allowed(ctx, &kv_types.1); // TODO:assert key_type is string or int or null } - FieldType::Identifier(_, _) => {} - FieldType::List(field_type, _, _) => validate_type_allowed(ctx, field_type), - FieldType::Tuple(_, field_types, _) | FieldType::Union(_, field_types, _) => { + + FieldType::Primitive(_, type_value, span, _) => { + let primitives = vec!["int", "float", "bool", "string", "image", "audio"]; + if !primitives.contains(&type_value.to_string().as_str()) { + ctx.push_error(DatamodelError::not_found_error( + "Primitive type", + &type_value.to_string(), + span.clone(), + primitives.iter().map(|&s| s.to_string()).collect(), + )); + } + } + FieldType::Symbol(_, name, span, _) => { + if ctx.db.find_type_by_str(name).is_none() { + ctx.push_error(DatamodelError::not_found_error( + "Type", + name, + span.clone(), + ctx.db + .walk_classes() + .chain(ctx.db.walk_enums()) + .map(|c| c.name().to_string()) + .collect(), + )); + } + } + FieldType::List(field_type, ..) => validate_type_allowed(ctx, field_type), + FieldType::Tuple(_, field_types, ..) | FieldType::Union(_, field_types, ..) => { for field_type in field_types { validate_type_allowed(ctx, field_type); } diff --git a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/variants.rs b/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/variants.rs deleted file mode 100644 index 2b942a7d3..000000000 --- a/engine/baml-lib/baml-core/src/validate/validation_pipeline/validations/variants.rs +++ /dev/null @@ -1,116 +0,0 @@ -use internal_baml_diagnostics::DatamodelError; - -use internal_baml_parser_database::{PrinterType, PromptVariable}; -use internal_baml_schema_ast::ast::{Identifier, WithIdentifier, WithName, WithSpan}; - -use crate::validate::validation_pipeline::context::Context; - -pub(super) fn validate(ctx: &mut Context<'_>) { - for variant in ctx.db.walk_variants() { - let client = &variant.properties().client; - - if variant.client().is_none() { - ctx.push_error(DatamodelError::new_validation_error( - &format!("Unknown client `{}`", client.value), - client.span.clone(), - )); - } - - if let Some(_function) = variant.walk_function() { - // Ensure that every serializer is valid. - variant.ast_variant().iter_serializers().for_each(|(_, f)| { - match ctx.db.find_type(f.identifier()) { - Some(_) => {} - None => { - ctx.push_error(DatamodelError::new_validation_error( - &format!("Unknown override `{}`", f.identifier().name()), - f.identifier().span().clone(), - )); - } - } - }); - - if let Some((idx, _)) = variant.properties().output_adapter { - // Ensure that all input types exist. - let adapter = &variant.ast_variant()[idx]; - - adapter - .from - .flat_idns() - .iter() - .filter(|f| match f { - // Primitive types don't need to found. - Identifier::Primitive(..) => false, - _ => true, - }) - .for_each(|f| match ctx.db.find_type(f) { - Some(_) => {} - None => { - ctx.push_error(DatamodelError::new_type_not_found_error( - f.name(), - ctx.db.valid_type_names(), - f.span().clone(), - )); - } - }); - } - - // Ensure that all blocks are valid. - variant - .properties() - .prompt_replacements - .iter() - .filter_map(|p| match p { - PromptVariable::Enum(e) => e.printer.as_ref().map(|f| (f, "enum")), - PromptVariable::Type(t) => t.printer.as_ref().map(|f| (f, "type")), - PromptVariable::Input(_) => None, - PromptVariable::Chat(_) => None, - }) - .for_each(|(printer, t)| { - match ctx.db.find_printer(&printer.0) { - Some(w) => { - match w.printer() { - PrinterType::Enum(_) => { - if t == "enum" { - // All good. - } else { - ctx.push_error(DatamodelError::new_validation_error( - &format!( - "Expected a printer, found printer {}", - printer.0 - ), - printer.1.clone(), - )); - } - } - PrinterType::Type(_) => { - if t == "type" { - // All good. - } else { - ctx.push_error(DatamodelError::new_validation_error( - &format!( - "Expected a printer, found printer {}", - printer.0 - ), - printer.1.clone(), - )); - } - } - } - } - None => ctx.push_error(DatamodelError::new_type_not_found_error( - &printer.0, - ctx.db.valid_printer_names(), - printer.1.clone(), - )), - } - }); - } else { - ctx.push_error(DatamodelError::new_type_not_found_error( - variant.function_identifier().name(), - ctx.db.valid_function_names(), - variant.function_identifier().span().clone(), - )); - } - } -} diff --git a/engine/baml-lib/baml-types/src/field_type/mod.rs b/engine/baml-lib/baml-types/src/field_type/mod.rs index c495e34fa..a4dabd61b 100644 --- a/engine/baml-lib/baml-types/src/field_type/mod.rs +++ b/engine/baml-lib/baml-types/src/field_type/mod.rs @@ -11,7 +11,20 @@ pub enum TypeValue { Image, Audio, } - +impl TypeValue { + pub fn from_str(s: &str) -> Option { + match s { + "string" => Some(TypeValue::String), + "int" => Some(TypeValue::Int), + "float" => Some(TypeValue::Float), + "bool" => Some(TypeValue::Bool), + "null" => Some(TypeValue::Null), + "image" => Some(TypeValue::Image), + "audio" => Some(TypeValue::Audio), + _ => None, + } + } +} impl std::fmt::Display for TypeValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/engine/baml-lib/baml/tests/validation_files/class/attributes.baml b/engine/baml-lib/baml/tests/validation_files/class/attributes.baml new file mode 100644 index 000000000..de778e110 --- /dev/null +++ b/engine/baml-lib/baml/tests/validation_files/class/attributes.baml @@ -0,0 +1,10 @@ +class TestClassAlias { + key string @alias("key-dash") + @description(#" + This is a description for key + af asdf + "#) + key2 string @alias("key21") + key3 string @alias("key with space") + key4 string @alias("key.with.punctuation/123") +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/class/dependency_cycle.baml b/engine/baml-lib/baml/tests/validation_files/class/dependency_cycle.baml index 74e17dc4b..571a8e966 100644 --- a/engine/baml-lib/baml/tests/validation_files/class/dependency_cycle.baml +++ b/engine/baml-lib/baml/tests/validation_files/class/dependency_cycle.baml @@ -8,24 +8,4 @@ class InterfaceOne { class InterfaceThree { interface InterfaceThree -} - - -// error: Error validating: These classes form a dependency cycle: InterfaceTwo -// --> class/dependency_cycle.baml:1 -// | -// | -// 1 | class InterfaceTwo { -// | -// error: Error validating: These classes form a dependency cycle: InterfaceOne -// --> class/dependency_cycle.baml:5 -// | -// 4 | -// 5 | class InterfaceOne { -// | -// error: Error validating: These classes form a dependency cycle: InterfaceThree -// --> class/dependency_cycle.baml:9 -// | -// 8 | -// 9 | class InterfaceThree { -// | +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/class/map_types.baml b/engine/baml-lib/baml/tests/validation_files/class/map_types.baml index 7843d8409..b87d3de6c 100644 --- a/engine/baml-lib/baml/tests/validation_files/class/map_types.baml +++ b/engine/baml-lib/baml/tests/validation_files/class/map_types.baml @@ -31,18 +31,6 @@ function InputAndOutput(i1: map, i2: map) -> m "# } -// error: Error validating: Maps may only have strings as keys -// --> class/map_types.baml:16 -// | -// 15 | -// 16 | b1 map -// | -// error: Error validating: Maps may only have strings as keys -// --> class/map_types.baml:17 -// | -// 16 | b1 map -// 17 | b2 map -// | // error: Error validating: Maps may only have strings as keys // --> class/map_types.baml:18 // | @@ -62,12 +50,6 @@ function InputAndOutput(i1: map, i2: map) -> m // 20 | b5 map // | // error: Error validating: Maps may only have strings as keys -// --> class/map_types.baml:23 -// | -// 22 | c1 string | map -// 23 | c2 string | map -// | -// error: Error validating: Maps may only have strings as keys // --> class/map_types.baml:24 // | // 23 | c2 string | map diff --git a/engine/baml-lib/baml/tests/validation_files/class/secure_types.baml b/engine/baml-lib/baml/tests/validation_files/class/secure_types.baml index 548c3d36c..bb008b4d5 100644 --- a/engine/baml-lib/baml/tests/validation_files/class/secure_types.baml +++ b/engine/baml-lib/baml/tests/validation_files/class/secure_types.baml @@ -17,163 +17,25 @@ class ComplexTypes { o (((int | string) | bool[]), (float, double) | long_long_identifier_123) } -// error: Type `apple_pie` does not exist. Did you mean one of these: `ComplexTypes`, `float`, `bool`, `string`, `int`? -// --> class/secure_types.baml:3 -// | -// 2 | class ComplexTypes { -// 3 | a map -// | // error: Error validating: Maps may only have strings as keys // --> class/secure_types.baml:3 // | // 2 | class ComplexTypes { // 3 | a map // | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:4 -// | -// 3 | a map -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// | -// error: Type `long_word_123.foobar` does not exist. Did you mean one of these: `float`, `bool`, `ComplexTypes`, `string`, `int`? -// --> class/secure_types.baml:4 -// | -// 3 | a map -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// | // error: Error validating: Maps may only have strings as keys -// --> class/secure_types.baml:4 -// | -// 3 | a map -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// | -// error: Type `apple123_456_pie` does not exist. Did you mean one of these: `ComplexTypes`, `float`, `bool`, `string`, `int`? -// --> class/secure_types.baml:5 -// | -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// 5 | c apple123_456_pie | (stringer, bool[], (int | char))[] -// | -// error: Type `stringer` does not exist. Did you mean one of these: `string`, `int`, `float`, `bool`, `ComplexTypes`? -// --> class/secure_types.baml:5 -// | -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// 5 | c apple123_456_pie | (stringer, bool[], (int | char))[] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:5 -// | -// 4 | b (int, map, (char | float)[][] | long_word_123.foobar[]) -// 5 | c apple123_456_pie | (stringer, bool[], (int | char))[] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? // --> class/secure_types.baml:6 // | // 5 | c apple123_456_pie | (stringer, bool[], (int | char))[] // 6 | d map // | // error: Error validating: Maps may only have strings as keys -// --> class/secure_types.baml:6 -// | -// 5 | c apple123_456_pie | (stringer, bool[], (int | char))[] -// 6 | d map -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:7 -// | -// 6 | d map -// 7 | e ((int, string | char) | ((float, double) | long[], bool)[][][]) -// | -// error: Type `double` does not exist. Did you mean one of these: `bool`, `string`, `int`, `float`, `ComplexTypes`? -// --> class/secure_types.baml:7 -// | -// 6 | d map -// 7 | e ((int, string | char) | ((float, double) | long[], bool)[][][]) -// | -// error: Type `long` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:7 -// | -// 6 | d map -// 7 | e ((int, string | char) | ((float, double) | long[], bool)[][][]) -// | -// error: Type `VeryLongWord_With_123_Numbers` does not exist. -// --> class/secure_types.baml:8 -// | -// 7 | e ((int, string | char) | ((float, double) | long[], bool)[][][]) -// 8 | f VeryLongWord_With_123_Numbers[][][][] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:9 -// | -// 8 | f VeryLongWord_With_123_Numbers[][][][] -// 9 | g (int, (float, char, bool), string[]) | tuple_inside_tuple[] -// | -// error: Type `tuple_inside_tuple` does not exist. Did you mean one of these: `ComplexTypes`, `int`, `string`, `float`, `bool`? -// --> class/secure_types.baml:9 -// | -// 8 | f VeryLongWord_With_123_Numbers[][][][] -// 9 | g (int, (float, char, bool), string[]) | tuple_inside_tuple[] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? // --> class/secure_types.baml:10 // | // 9 | g (int, (float, char, bool), string[]) | tuple_inside_tuple[] // 10 | h (((int | string)[]) | map) // | // error: Error validating: Maps may only have strings as keys -// --> class/secure_types.baml:10 -// | -// 9 | g (int, (float, char, bool), string[]) | tuple_inside_tuple[] -// 10 | h (((int | string)[]) | map) -// | -// error: Type `apple` does not exist. Did you mean one of these: `bool`, `int`, `float`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:11 -// | -// 10 | h (((int | string)[]) | map) -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// | -// error: Type `banana` does not exist. Did you mean one of these: `string`, `int`, `float`, `bool`, `ComplexTypes`? -// --> class/secure_types.baml:11 -// | -// 10 | h (((int | string)[]) | map) -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// | -// error: Type `cherry` does not exist. Did you mean one of these: `string`, `int`, `float`, `bool`, `ComplexTypes`? -// --> class/secure_types.baml:11 -// | -// 10 | h (((int | string)[]) | map) -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// | -// error: Type `date_fruit` does not exist. Did you mean one of these: `string`, `float`, `int`, `bool`, `ComplexTypes`? -// --> class/secure_types.baml:11 -// | -// 10 | h (((int | string)[]) | map) -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// | -// error: Type `eggplant_vegetable` does not exist. Did you mean one of these: `ComplexTypes`, `string`, `int`, `float`, `bool`? -// --> class/secure_types.baml:11 -// | -// 10 | h (((int | string)[]) | map) -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:12 -// | -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// 12 | j ((char, int[][], (bool | string[][])) | double[][][][], (float, int)[]) -// | -// error: Type `double` does not exist. Did you mean one of these: `bool`, `string`, `int`, `float`, `ComplexTypes`? -// --> class/secure_types.baml:12 -// | -// 11 | i (apple, banana | cherry | date_fruit | eggplant_vegetable)[] -// 12 | j ((char, int[][], (bool | string[][])) | double[][][][], (float, int)[]) -// | -// error: Type `long` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:13 -// | -// 12 | j ((char, int[][], (bool | string[][])) | double[][][][], (float, int)[]) -// 13 | k map | map -// | -// error: Type `double` does not exist. Did you mean one of these: `bool`, `string`, `int`, `float`, `ComplexTypes`? // --> class/secure_types.baml:13 // | // 12 | j ((char, int[][], (bool | string[][])) | double[][][][], (float, int)[]) @@ -186,66 +48,6 @@ class ComplexTypes { // 13 | k map | map // | // error: Error validating: Maps may only have strings as keys -// --> class/secure_types.baml:13 -// | -// 12 | j ((char, int[][], (bool | string[][])) | double[][][][], (float, int)[]) -// 13 | k map | map -// | -// error: Type `AlphaNumeric_123_456_789` does not exist. -// --> class/secure_types.baml:14 -// | -// 13 | k map | map -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// | -// error: Type `char` does not exist. Did you mean one of these: `int`, `float`, `bool`, `string`, `ComplexTypes`? -// --> class/secure_types.baml:14 -// | -// 13 | k map | map -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// | -// error: Type `tuple_1` does not exist. Did you mean one of these: `float`, `bool`, `string`, `int`, `ComplexTypes`? -// --> class/secure_types.baml:15 -// | -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// | -// error: Type `tuple_2` does not exist. Did you mean one of these: `float`, `bool`, `string`, `int`, `ComplexTypes`? -// --> class/secure_types.baml:15 -// | -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// | -// error: Type `tuple_3` does not exist. Did you mean one of these: `float`, `bool`, `string`, `int`, `ComplexTypes`? -// --> class/secure_types.baml:15 -// | -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// | -// error: Type `tuple_4` does not exist. Did you mean one of these: `float`, `bool`, `string`, `int`, `ComplexTypes`? -// --> class/secure_types.baml:15 -// | -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// | -// error: Type `tuple_5` does not exist. Did you mean one of these: `float`, `bool`, `string`, `int`, `ComplexTypes`? -// --> class/secure_types.baml:15 -// | -// 14 | l AlphaNumeric_123_456_789 | (int, bool?) | char[] -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// | -// error: Type `another_key` does not exist. Did you mean one of these: `string`, `int`, `ComplexTypes`, `float`, `bool`? -// --> class/secure_types.baml:16 -// | -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// 16 | n map> -// | -// error: Type `complex_key_type` does not exist. Did you mean one of these: `ComplexTypes`, `float`, `bool`, `int`, `string`? -// --> class/secure_types.baml:16 -// | -// 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] -// 16 | n map> -// | -// error: Error validating: Maps may only have strings as keys // --> class/secure_types.baml:16 // | // 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] @@ -257,15 +59,3 @@ class ComplexTypes { // 15 | m (tuple_1, tuple_2 | tuple_3, (tuple_4, tuple_5))[] // 16 | n map> // | -// error: Type `double` does not exist. Did you mean one of these: `bool`, `string`, `int`, `float`, `ComplexTypes`? -// --> class/secure_types.baml:17 -// | -// 16 | n map> -// 17 | o (((int | string) | bool[]), (float, double) | long_long_identifier_123) -// | -// error: Type `long_long_identifier_123` does not exist. Did you mean `ComplexTypes`? -// --> class/secure_types.baml:17 -// | -// 16 | n map> -// 17 | o (((int | string) | bool[]), (float, double) | long_long_identifier_123) -// | diff --git a/engine/baml-lib/baml/tests/validation_files/class/spelling_error.baml b/engine/baml-lib/baml/tests/validation_files/class/spelling_error.baml index edb2ccd78..940c62e38 100644 --- a/engine/baml-lib/baml/tests/validation_files/class/spelling_error.baml +++ b/engine/baml-lib/baml/tests/validation_files/class/spelling_error.baml @@ -4,22 +4,4 @@ class InterfaceTwo { class InterfaceOne { uses InterfaceT -} - - - - - - -// error: Type `strin` does not exist. Did you mean one of these: `string`, `int`, `float`, `bool`, `InterfaceOne`, `InterfaceTwo`? -// --> class/spelling_error.baml:2 -// | -// 1 | class InterfaceTwo { -// 2 | interface strin -// | -// error: Type `InterfaceT` does not exist. Did you mean one of these: `InterfaceTwo`, `InterfaceOne`, `int`, `string`, `float`, `bool`? -// --> class/spelling_error.baml:6 -// | -// 5 | class InterfaceOne { -// 6 | uses InterfaceT -// | +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/class/unknown_type.baml b/engine/baml-lib/baml/tests/validation_files/class/unknown_type.baml index c5554052e..2bc485811 100644 --- a/engine/baml-lib/baml/tests/validation_files/class/unknown_type.baml +++ b/engine/baml-lib/baml/tests/validation_files/class/unknown_type.baml @@ -1,16 +1,4 @@ class InterfaceTwo { interface string prop2 Bar -} - - - - - - -// error: Type `Bar` does not exist. Did you mean one of these: `int`, `bool`, `float`, `string`, `InterfaceTwo`? -// --> class/unknown_type.baml:3 -// | -// 2 | interface string -// 3 | prop2 Bar -// | +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/client/bad_template_args.baml b/engine/baml-lib/baml/tests/validation_files/client/bad_template_args.baml index a753fba49..e0c5f02fc 100644 --- a/engine/baml-lib/baml/tests/validation_files/client/bad_template_args.baml +++ b/engine/baml-lib/baml/tests/validation_files/client/bad_template_args.baml @@ -2,15 +2,24 @@ client MyClient2 { provider baml-openai-chat } - - - - - - -// error: Error validating: Only LLM clients are supported. Use: client +// error: Error validating: This line is invalid. It does not start with any known Baml schema keyword. // --> client/bad_template_args.baml:1 // | // | // 1 | client MyClient2 { +// 2 | provider baml-openai-chat +// | +// error: Error validating: This line is invalid. It does not start with any known Baml schema keyword. +// --> client/bad_template_args.baml:2 +// | +// 1 | client MyClient2 { +// 2 | provider baml-openai-chat +// 3 | } +// | +// error: Error validating: This line is invalid. It does not start with any known Baml schema keyword. +// --> client/bad_template_args.baml:3 +// | +// 2 | provider baml-openai-chat +// 3 | } +// 4 | // | diff --git a/engine/baml-lib/baml/tests/validation_files/client/missing_template_args.baml b/engine/baml-lib/baml/tests/validation_files/client/missing_template_args.baml index b20366e4d..fe0a640f8 100644 --- a/engine/baml-lib/baml/tests/validation_files/client/missing_template_args.baml +++ b/engine/baml-lib/baml/tests/validation_files/client/missing_template_args.baml @@ -1,12 +1,3 @@ client MyClient { provider baml-openai-chat -} - -// error: Error validating: Missing template for client. (did you forget ) -// --> client/missing_template_args.baml:1 -// | -// | -// 1 | client MyClient { -// 2 | provider baml-openai-chat -// 3 | } -// | +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/client/period_in_model_type.baml b/engine/baml-lib/baml/tests/validation_files/client/period_in_model_type.baml index 5f93d8811..59adb740c 100644 --- a/engine/baml-lib/baml/tests/validation_files/client/period_in_model_type.baml +++ b/engine/baml-lib/baml/tests/validation_files/client/period_in_model_type.baml @@ -4,6 +4,4 @@ client MyClient { model gpt-3.5-turbo max_tokens 100 } -} - - +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/client/unknown_prop.baml b/engine/baml-lib/baml/tests/validation_files/client/unknown_prop.baml index c8325d1fd..0db5d1238 100644 --- a/engine/baml-lib/baml/tests/validation_files/client/unknown_prop.baml +++ b/engine/baml-lib/baml/tests/validation_files/client/unknown_prop.baml @@ -6,7 +6,6 @@ client MyClient { } } - // error: Error validating: Unknown field `myExtraProp` in client // --> client/unknown_prop.baml:3 // | diff --git a/engine/baml-lib/baml/tests/validation_files/dictionary/valid_dictionary.baml b/engine/baml-lib/baml/tests/validation_files/dictionary/valid_dictionary.baml index eae426153..45547bac4 100644 --- a/engine/baml-lib/baml/tests/validation_files/dictionary/valid_dictionary.baml +++ b/engine/baml-lib/baml/tests/validation_files/dictionary/valid_dictionary.baml @@ -37,6 +37,4 @@ client MyClient { #{//a comment in a prompt} "# } -} - - +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/enum/invalid_commas.baml b/engine/baml-lib/baml/tests/validation_files/enum/invalid_commas.baml index e55dd3ec6..de9fef648 100644 --- a/engine/baml-lib/baml/tests/validation_files/enum/invalid_commas.baml +++ b/engine/baml-lib/baml/tests/validation_files/enum/invalid_commas.baml @@ -4,21 +4,21 @@ enum Test { C, } -// error: Error validating: This line is not an enum value definition. BAML enums don't have commas, and all values must be all caps +// error: Error validating: This line is not a valid field or attribute definition. A valid class property looks like: 'myProperty string[] @description("This is a description")' // --> enum/invalid_commas.baml:2 // | // 1 | enum Test { // 2 | A, // 3 | B, // | -// error: Error validating: This line is not an enum value definition. BAML enums don't have commas, and all values must be all caps +// error: Error validating: This line is not a valid field or attribute definition. A valid class property looks like: 'myProperty string[] @description("This is a description")' // --> enum/invalid_commas.baml:3 // | // 2 | A, // 3 | B, // 4 | C, // | -// error: Error validating: This line is not an enum value definition. BAML enums don't have commas, and all values must be all caps +// error: Error validating: This line is not a valid field or attribute definition. A valid class property looks like: 'myProperty string[] @description("This is a description")' // --> enum/invalid_commas.baml:4 // | // 3 | B, diff --git a/engine/baml-lib/baml/tests/validation_files/functions/missing_input_output_value.baml b/engine/baml-lib/baml/tests/validation_files/functions/missing_input_output_value.baml deleted file mode 100644 index 345bffda0..000000000 --- a/engine/baml-lib/baml/tests/validation_files/functions/missing_input_output_value.baml +++ /dev/null @@ -1,40 +0,0 @@ -function A { - input -} - -function B { - input string - output -} - -// error: Error validating: Missing function field type -// --> functions/missing_input_output_value.baml:2 -// | -// 1 | function A { -// 2 | input -// 3 | } -// | -// error: Error validating function "A": This function declaration is invalid. It is missing an input or output field. -// --> functions/missing_input_output_value.baml:1 -// | -// | -// 1 | function A { -// 2 | input -// 3 | } -// | -// error: Error validating: Missing function field type -// --> functions/missing_input_output_value.baml:7 -// | -// 6 | input string -// 7 | output -// 8 | } -// | -// error: Error validating function "B": This function declaration is invalid. It is missing an input or output field. -// --> functions/missing_input_output_value.baml:5 -// | -// 4 | -// 5 | function B { -// 6 | input string -// 7 | output -// 8 | } -// | diff --git a/engine/baml-lib/baml/tests/validation_files/functions/nonexistent_input_output_types.baml b/engine/baml-lib/baml/tests/validation_files/functions/nonexistent_input_output_types.baml deleted file mode 100644 index 8d3a4f21e..000000000 --- a/engine/baml-lib/baml/tests/validation_files/functions/nonexistent_input_output_types.baml +++ /dev/null @@ -1,22 +0,0 @@ -// test comment -function Foo { - input Bar - output Baz -} - - - - - -// error: Type `Bar` does not exist. Did you mean one of these: `int`, `bool`, `float`, `string`? -// --> functions/nonexistent_input_output_types.baml:3 -// | -// 2 | function Foo { -// 3 | input Bar -// | -// error: Type `Baz` does not exist. Did you mean one of these: `int`, `bool`, `float`, `string`? -// --> functions/nonexistent_input_output_types.baml:4 -// | -// 3 | input Bar -// 4 | output Baz -// | diff --git a/engine/baml-lib/baml/tests/validation_files/functions/valid_functions.baml b/engine/baml-lib/baml/tests/validation_files/functions/valid_functions.baml deleted file mode 100644 index 39a8415e8..000000000 --- a/engine/baml-lib/baml/tests/validation_files/functions/valid_functions.baml +++ /dev/null @@ -1,23 +0,0 @@ -function One { - input string - output string -} - -class Hello { - world string -} - -class Hello2 { - /// Comment about this - world string // Comment about this - /// This works - // This works - relevant_phrase_from_user_document string // This breaks - // test - @alias(foo) -} - -function Two { - input Hello - output Hello2 -} diff --git a/engine/baml-lib/baml/tests/validation_files/functions/valid_multiple_arg.baml b/engine/baml-lib/baml/tests/validation_files/functions/valid_multiple_arg.baml deleted file mode 100644 index 664e3b60f..000000000 --- a/engine/baml-lib/baml/tests/validation_files/functions/valid_multiple_arg.baml +++ /dev/null @@ -1,20 +0,0 @@ -class Bar { - hello string -} - -function Foo { - input (arg_name: Bar, arg_2: Bar) - output string -} - -function ExtractAllergies { - input (hello: string, world: string) - output Allergies[] -} - -// error: Type `Allergies` does not exist. Did you mean one of these: `string`, `Bar`, `int`, `float`, `bool`? -// --> functions/valid_multiple_arg.baml:12 -// | -// 11 | input (hello: string, world: string) -// 12 | output Allergies[] -// | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/duplicate_names.baml b/engine/baml-lib/baml/tests/validation_files/functions_v2/duplicate_names.baml index ef6e2d3ac..06ad56c8e 100644 --- a/engine/baml-lib/baml/tests/validation_files/functions_v2/duplicate_names.baml +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/duplicate_names.baml @@ -8,7 +8,7 @@ function Bar(a: string, b: int | bool) -> int { prompt #"fa"# } -// error: The function "Bar" cannot be defined because a function[deprecated signature] with that name already exists. +// error: The function "Bar" cannot be defined because a function with that name already exists. // --> functions_v2/duplicate_names.baml:6 // | // 5 | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid.baml b/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid.baml index a7fcfb9d1..a14705a95 100644 --- a/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid.baml +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid.baml @@ -7,22 +7,6 @@ function FooBar(arg) -> bar { } - -// error: Error validating function "Foo": No return type specified. Valid function syntax is -// ``` -// function Foo(param1: String, param2: String) -> ReturnType { -// client SomeClient -// prompt #"..."# -// } -// ``` -// --> functions_v2/invalid.baml:1 -// | -// | -// 1 | function Foo() -> { -// 2 | client Bar -// 3 | prompt #"fa"# -// 4 | } -// | // error: Error validating: No type specified for argument: arg. Expected: `arg: type` // --> functions_v2/invalid.baml:6 // | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid2.baml b/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid2.baml index 95ad32ca8..8ebfc292f 100644 --- a/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid2.baml +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/invalid2.baml @@ -29,64 +29,21 @@ function Foo6(arg: int) -> float { prompt } -// error: Error validating: Missing `prompt` field in function. Add to the block: -// ``` -// prompt #"..."# -// ``` -// --> functions_v2/invalid2.baml:1 +// error: Error validating Function "Foo4": expr as val!! This field declaration is invalid. It is either missing a name or a type. +// --> functions_v2/invalid2.baml:17 // | +// 16 | client bar +// 17 | prompt // | -// 1 | function Foo1(arg: int) -> float { +// error: Error validating Function "Foo5": expr as val!! This field declaration is invalid. It is either missing a name or a type. +// --> functions_v2/invalid2.baml:22 // | -// error: Error validating: Missing `client` field in function. Add to the block: -// ``` -// client GPT4 -// ``` -// --> functions_v2/invalid2.baml:5 -// | -// 4 | -// 5 | function Foo2(arg: int) -> float { -// | -// error: Expected a template_string value, but received string value `"..."`. -// --> functions_v2/invalid2.baml:11 -// | -// 10 | client bar -// 11 | prompt "..." -// | -// error: Error validating: Missing `prompt` field in function. Add to the block: -// ``` -// prompt #"..."# -// ``` -// --> functions_v2/invalid2.baml:9 -// | -// 8 | -// 9 | function Foo3(arg: int) -> float { -// | -// error: Error validating: Missing `prompt` field in function. Add to the block: -// ``` -// prompt #"..."# -// ``` -// --> functions_v2/invalid2.baml:15 -// | -// 14 | -// 15 | function Foo4(arg: int) -> float { -// | -// error: Error validating: Missing `client` field in function. Add to the block: -// ``` -// client GPT4 -// ``` -// --> functions_v2/invalid2.baml:21 -// | -// 20 | // 21 | function Foo5(arg: int) -> float { +// 22 | client // | -// error: Error validating: Missing `prompt` and `client` fields in function. Add to the block: -// ``` -// client GPT4 -// prompt #"..."# -// ``` -// --> functions_v2/invalid2.baml:27 +// error: Error validating Function "Foo6": expr as val!! This field declaration is invalid. It is either missing a name or a type. +// --> functions_v2/invalid2.baml:28 // | -// 26 | // 27 | function Foo6(arg: int) -> float { +// 28 | client // | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/parameters b/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/parameters new file mode 100644 index 000000000..27d343d5a --- /dev/null +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/parameters @@ -0,0 +1,14 @@ +function TestFnNamedArgsSingleBool(myBool: bool) -> string{ + client Vertex + prompt #" + Return this value back to me: {{myBool}} + "# +} + +// error: Error validating: A BAML file must have the file extension `.baml` +// --> functions_v2/tests/parameters:1 +// | +// | +// 1 | function TestFnNamedArgsSingleBool(myBool: bool) -> string{ +// | ^ Unexpected token. +// | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/valid_tests.baml b/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/valid_tests.baml index 746a452e5..100886cd1 100644 --- a/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/valid_tests.baml +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/tests/valid_tests.baml @@ -72,4 +72,11 @@ test Foo { functions [InputEnum] args { } -} \ No newline at end of file +} + +// warning: 'email' is a string, expected class +// --> functions_v2/tests/valid_tests.baml:22 +// | +// 21 | client Bar +// 22 | prompt #" subject line {{ email.subject }} "# +// | diff --git a/engine/baml-lib/baml/tests/validation_files/functions_v2/valid.baml b/engine/baml-lib/baml/tests/validation_files/functions_v2/valid.baml index 5167c9e4f..0e792b6e8 100644 --- a/engine/baml-lib/baml/tests/validation_files/functions_v2/valid.baml +++ b/engine/baml-lib/baml/tests/validation_files/functions_v2/valid.baml @@ -60,4 +60,11 @@ string function InputImage(image: image) -> string { client Bar prompt #" image {{ image }} "# -} \ No newline at end of file +} + +// warning: 'email' is a string, expected class +// --> functions_v2/valid.baml:22 +// | +// 21 | client Bar +// 22 | prompt #" subject line {{ email.subject }} "# +// | diff --git a/engine/baml-lib/baml/tests/validation_files/generators/v1.baml b/engine/baml-lib/baml/tests/validation_files/generators/v1.baml index a4b47bdac..58d2142ba 100644 --- a/engine/baml-lib/baml/tests/validation_files/generators/v1.baml +++ b/engine/baml-lib/baml/tests/validation_files/generators/v1.baml @@ -38,4 +38,4 @@ generator lang_ruby_2 { output_type typescript default_client_mode "sync" output_dir "../" -} +} \ No newline at end of file diff --git a/engine/baml-lib/baml/tests/validation_files/strings/unquoted_strings.baml b/engine/baml-lib/baml/tests/validation_files/strings/unquoted_strings.baml index 41997accc..c1614dda4 100644 --- a/engine/baml-lib/baml/tests/validation_files/strings/unquoted_strings.baml +++ b/engine/baml-lib/baml/tests/validation_files/strings/unquoted_strings.baml @@ -1,5 +1,5 @@ client Hello { - provider baml-openai-chat + provider openai options { thing hello'world banned @helloworld @@ -8,33 +8,11 @@ client Hello { } } -// error: Error validating: This line is not a valid field or attribute definition. A valid property may look like: 'myProperty "some value"' for example, with no colons. +// error: Error validating Client "Hello": expr as val!! This field declaration is invalid. It is either missing a name or a type. // --> strings/unquoted_strings.baml:3 // | -// 2 | provider baml-openai-chat +// 2 | provider openai // 3 | options { -// 4 | thing hello'world -// | -// error: Error validating: This line is not a valid field or attribute definition. A valid property may look like: 'myProperty "some value"' for example, with no colons. -// --> strings/unquoted_strings.baml:4 -// | -// 3 | options { -// 4 | thing hello'world -// 5 | banned @helloworld -// | -// error: Error validating: This line is not a valid field or attribute definition. A valid property may look like: 'myProperty "some value"' for example, with no colons. -// --> strings/unquoted_strings.baml:6 -// | -// 5 | banned @helloworld -// 6 | banned2 #helloworld -// 7 | banned3 hello(world) -// | -// error: Error validating: This line is not a valid field or attribute definition. A valid property may look like: 'myProperty "some value"' for example, with no colons. -// --> strings/unquoted_strings.baml:7 -// | -// 6 | banned2 #helloworld -// 7 | banned3 hello(world) -// 8 | } // | // error: Error validating: This line is invalid. It does not start with any known Baml schema keyword. // --> strings/unquoted_strings.baml:9 diff --git a/engine/baml-lib/baml/tests/validation_files/template_string/duplicate_names.baml b/engine/baml-lib/baml/tests/validation_files/template_string/duplicate_names.baml index 5a4540ef9..27ac7eece 100644 --- a/engine/baml-lib/baml/tests/validation_files/template_string/duplicate_names.baml +++ b/engine/baml-lib/baml/tests/validation_files/template_string/duplicate_names.baml @@ -11,17 +11,13 @@ function SomeString { output string } - - - - // error: The template_string "SomeString" cannot be defined because a template_string with that name already exists. // --> template_string/duplicate_names.baml:5 // | // 4 | // 5 | template_string SomeString(a: int) #" // | -// error: The function[deprecated signature] "SomeString" cannot be defined because a template_string with that name already exists. +// error: The function "SomeString" cannot be defined because a template_string with that name already exists. // --> template_string/duplicate_names.baml:9 // | // 8 | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/bad_client_def.baml b/engine/baml-lib/baml/tests/validation_files/variants/bad_client_def.baml deleted file mode 100644 index b0470542d..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/bad_client_def.baml +++ /dev/null @@ -1,29 +0,0 @@ -// The error here is bad. -function Foo { - input string - output string -} - -client MyClient { - provider baml-openai-chat -} - -impl V1 { - client MyClient - prompt "Hello there" -} - - - -// warning: To use comments and {#vars} use a block string. #"..."# instead. -// --> variants/bad_client_def.baml:13 -// | -// 12 | client MyClient -// 13 | prompt "Hello there" -// | -// error: Error validating: Did you mean `client` instead of `client<...>`? -// --> variants/bad_client_def.baml:12 -// | -// 11 | impl V1 { -// 12 | client MyClient -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/client_unknown.baml b/engine/baml-lib/baml/tests/validation_files/variants/client_unknown.baml deleted file mode 100644 index aed0d869e..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/client_unknown.baml +++ /dev/null @@ -1,22 +0,0 @@ -function Foo { - input string - output string -} - -impl FooImpl { - client MadeUpClient - prompt #" - hello world {#input} - {#print_type(output)} - "# -} - - - - -// error: Error validating: Unknown client `MadeUpClient` -// --> variants/client_unknown.baml:7 -// | -// 6 | impl FooImpl { -// 7 | client MadeUpClient -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/missing_template_args.baml b/engine/baml-lib/baml/tests/validation_files/variants/missing_template_args.baml deleted file mode 100644 index f08bf4e63..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/missing_template_args.baml +++ /dev/null @@ -1,33 +0,0 @@ -function Foo { - input string - output string -} - -client MyClient { - provider baml-openai-chat -} - -impl Impl1 { - prompt "hello" - client MyClient -} - -impl Impl2 { - prompt "hello" - client MyClient -} - - - -// error: Error validating: impl requires 2 template args. (did you forget ) -// --> variants/missing_template_args.baml:10 -// | -// 9 | -// 10 | impl Impl1 { -// | -// error: Error validating: Missing template for impl. (did you forget ) -// --> variants/missing_template_args.baml:15 -// | -// 14 | -// 15 | impl Impl2 { -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/adapters.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/adapters.baml deleted file mode 100644 index 1c016d621..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/adapters.baml +++ /dev/null @@ -1,110 +0,0 @@ -function Foo { - input InputType - output OutputType - - default_impl FooImpl -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl { - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# - - adapter python#" - return OutputType(x=Sentiment.HAPPY, y=False) - "# -} - -impl BarImpl { - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# - - adapter python#" - return OutputType(x=Sentiment.HAPPY, y=False) - "# -} - -impl Bar2Impl { - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# - - adapter python#" - return OutputType(x=Sentiment.HAPPY, y=False) - "# -} diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/invalid_chat.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/invalid_chat.baml deleted file mode 100644 index d26830245..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/invalid_chat.baml +++ /dev/null @@ -1,68 +0,0 @@ -function Foo { - input InputType - output OutputType -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl{ - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - {#chat()} - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#chat} - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# -} - - - -// error: Unexpected token. Expected one of: Expected exactly one argument for role. e.g. {#chat(user)} or {#chat(system)} -// --> variants/prompt/invalid_chat.baml:41 -// | -// 40 | {#input.a.c} -// 41 | {#chat()} -// | -// error: Unexpected token. Expected one of: Expected exactly one argument for role. e.g. {#chat(user)} or {#chat(system)} -// --> variants/prompt/invalid_chat.baml:47 -// | -// 46 | morespaces here -// 47 | {#chat} -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/overrides.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/overrides.baml deleted file mode 100644 index 6591cebc2..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/overrides.baml +++ /dev/null @@ -1,63 +0,0 @@ -function Foo { - input InputType - output OutputType -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl{ - client MyClient - - override Sentiment { - HAPPY @alias("happy") - // Then - @description(#" - foo - "#) - } - - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# -} - - diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/spaces_in_prompts.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/spaces_in_prompts.baml deleted file mode 100644 index 27958e1e0..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/spaces_in_prompts.baml +++ /dev/null @@ -1,52 +0,0 @@ -function Foo { - input InputType - output OutputType -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl{ - client MyClient - prompt #" - A {# input.a }!! {// A - multiline - comment //} - - - {# input.a.c } - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {# input.a } {# input.a } hi there - JSON: - {#print_enum( Sentiment) } - {#print_type(output )} - "# -} diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_var_multi_arg.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_var_multi_arg.baml deleted file mode 100644 index 1482b9fd5..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_var_multi_arg.baml +++ /dev/null @@ -1,37 +0,0 @@ -class Bar { - hello string -} - -// TODO: finish this validation test.. -function Foo { - input (arg_name: Bar, arg_2: Bar) - output string -} - - -client MyClient { - provider baml-openai-chat -} - -impl FooImpl{ - client MyClient - prompt #" - A {#input.e} - {#InputType.e} - - the rest of the prompt - tabbed-in - JSON: - {#print_enum(enumarg)} - {#print_type(typearg)} - "# -} - - - -// error: Error validating: Must start with `input` -// --> variants/prompt/unknown_prompt_var_multi_arg.baml:20 -// | -// 19 | A {#input.e} -// 20 | {#InputType.e} -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_variables.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_variables.baml deleted file mode 100644 index 06ba258d3..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/unknown_prompt_variables.baml +++ /dev/null @@ -1,79 +0,0 @@ -function Foo { - input InputType - output OutputType -} - -class InputType { - a string - b bool -} - -class OutputType { - x string - y bool -} - -client MyClient { - provider baml-openai-chat -} - -impl FooImpl{ - client MyClient - prompt #" - A {#input.e} - {#input.e} - {#input.e.y} - - the rest of the prompt - tabbed-in - JSON: - {#print_enum(enumarg)} - {#print_type(typearg)} - "# -} - -enum Enumarg { - A - B - C -} - - - - - - - - - - -// error: Error validating: Unknown field `e` in class `InputType` -// --> variants/prompt/unknown_prompt_variables.baml:23 -// | -// 22 | prompt #" -// 23 | A {#input.e} -// | -// error: Error validating: Unknown field `e` in class `InputType` -// --> variants/prompt/unknown_prompt_variables.baml:24 -// | -// 23 | A {#input.e} -// 24 | {#input.e} -// | -// error: Error validating: Unknown field `e` in class `InputType` -// --> variants/prompt/unknown_prompt_variables.baml:25 -// | -// 24 | {#input.e} -// 25 | {#input.e.y} -// | -// error: Enum `enumarg` does not exist. No Enums are used in the output of this function. -// --> variants/prompt/unknown_prompt_variables.baml:30 -// | -// 29 | JSON: -// 30 | {#print_enum(enumarg)} -// | -// error: Type `typearg` does not exist. Did you mean one of these: `output`, `OutputType`? -// --> variants/prompt/unknown_prompt_variables.baml:31 -// | -// 30 | {#print_enum(enumarg)} -// 31 | {#print_type(typearg)} -// | diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_chat_prompts.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_chat_prompts.baml deleted file mode 100644 index d7b5f2a82..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_chat_prompts.baml +++ /dev/null @@ -1,55 +0,0 @@ -function Foo { - input InputType - output OutputType -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl{ - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - {#chat(user)} - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#chat(system)} - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# -} - - diff --git a/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_prompt.baml b/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_prompt.baml deleted file mode 100644 index 28592882d..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/prompt/valid_prompt.baml +++ /dev/null @@ -1,81 +0,0 @@ -function Foo { - input InputType - output OutputType - default_impl FooImpl -} - -class InputType { - a InputType2 - b bool -} - -class OtherInput { - d string -} - -class InputType2 { - c string -} - -class OutputType { - x Sentiment - y bool -} - -client MyClient { - provider baml-openai-chat -} - -enum Sentiment { - HAPPY -} - -impl FooImpl{ - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# -} - - - -impl FooImpl3 { - // Include a trailing space - client MyClient - prompt #" - A {#input.a}!! {// A - multiline - comment //} - - - {#input.a.c} - - the rest of the prompt - no-tab - tab1 - tab2 - morespaces here - {#input.a} {#input.a} hi there - JSON: - {#print_enum(Sentiment)} - {#print_type(output)} - "# -} - - - diff --git a/engine/baml-lib/baml/tests/validation_files/variants/require_client_field.baml b/engine/baml-lib/baml/tests/validation_files/variants/require_client_field.baml deleted file mode 100644 index 8bb2031df..000000000 --- a/engine/baml-lib/baml/tests/validation_files/variants/require_client_field.baml +++ /dev/null @@ -1,24 +0,0 @@ -function Foo { - input string - output string -} - -impl FooImpl{ - prompt "hello world" -} - - - - -// warning: To use comments and {#vars} use a block string. #"..."# instead. -// --> variants/require_client_field.baml:7 -// | -// 6 | impl FooImpl{ -// 7 | prompt "hello world" -// | -// error: Error validating: Missing `client` field in impl -// --> variants/require_client_field.baml:6 -// | -// 5 | -// 6 | impl FooImpl{ -// | diff --git a/engine/baml-lib/diagnostics/src/error.rs b/engine/baml-lib/diagnostics/src/error.rs index 05bdc20a8..fc63f1972 100644 --- a/engine/baml-lib/diagnostics/src/error.rs +++ b/engine/baml-lib/diagnostics/src/error.rs @@ -400,8 +400,19 @@ impl DatamodelError { type_name: &str, name: &str, span: Span, - names: Vec, + mut names: Vec, ) -> DatamodelError { + // Include a list of primitives in the names + let primitives = vec![ + "int".to_string(), + "float".to_string(), + "bool".to_string(), + "string".to_string(), + "image".to_string(), + "audio".to_string(), + ]; + names.extend(primitives); + let close_names = sort_by_match(name, &names, Some(3)); let suggestions = if names.is_empty() { "".to_string() @@ -419,7 +430,10 @@ impl DatamodelError { ) }; - Self::new(format!("{type_name} {name} not found.{suggestions}"), span) + Self::new( + format!("{type_name} {name} not found.{suggestions} (from error.rs l.422)"), + span, + ) } pub fn type_not_used_in_prompt_error( @@ -470,7 +484,7 @@ impl DatamodelError { ) }; - Self::new(format!("{}{}", prefix, suggestions), span) + Self::new(format!("{}{} (l.476 error.rs)", prefix, suggestions), span) } pub fn new_type_not_found_error( @@ -493,7 +507,7 @@ impl DatamodelError { // If there are multiple close names, suggest them all let suggestions = close_names.join("`, `"); format!( - "Type `{}` does not exist. Did you mean one of these: `{}`?", + "Type `{}` does not exist. Did you mean one of these: `{}`? (error.rs l.499)", type_name, suggestions ) }; @@ -501,34 +515,6 @@ impl DatamodelError { Self::new(msg, span) } - pub fn new_impl_not_found_error( - impl_name: &str, - names: Vec, - span: Span, - ) -> DatamodelError { - let close_names = sort_by_match(impl_name, &names, Some(10)); - - let msg = if close_names.is_empty() { - // If no names are close enough, suggest nothing or provide a generic message - format!("impl `{}` does not exist.", impl_name) - } else if close_names.len() == 1 { - // If there's only one close name, suggest it - format!( - "impl `{}` does not exist. Did you mean `{}`?", - impl_name, close_names[0] - ) - } else { - // If there are multiple close names, suggest them all - let suggestions = close_names.join("`, `"); - format!( - "impl `{}` does not exist. Did you mean one of these: `{}`?", - impl_name, suggestions - ) - }; - - Self::new(msg, span) - } - pub fn new_attribute_not_known_error(attribute_name: &str, span: Span) -> DatamodelError { Self::new(format!("Attribute not known: \"@{attribute_name}\"."), span) } diff --git a/engine/baml-lib/diagnostics/src/warning.rs b/engine/baml-lib/diagnostics/src/warning.rs index 03fcc4bb5..0990de839 100644 --- a/engine/baml-lib/diagnostics/src/warning.rs +++ b/engine/baml-lib/diagnostics/src/warning.rs @@ -55,7 +55,7 @@ impl DatamodelWarning { // If there are multiple close names, suggest them all let suggestions = close_names.join("`, `"); format!( - "Type `{}` does not exist. Did you mean one of these: `{}`?", + "Type `{}` does not exist. Did you mean one of these: `{}`? ", type_name, suggestions ) }; diff --git a/engine/baml-lib/parser-database/src/attributes/mod.rs b/engine/baml-lib/parser-database/src/attributes/mod.rs index b36dd9a47..c710bdd59 100644 --- a/engine/baml-lib/parser-database/src/attributes/mod.rs +++ b/engine/baml-lib/parser-database/src/attributes/mod.rs @@ -1,122 +1,71 @@ -use internal_baml_diagnostics::DatamodelError; -use internal_baml_schema_ast::ast::{ - Class, ClassId, Enum, EnumId, Top, TopId, Variant, VariantConfigId, WithSpan, -}; +use internal_baml_schema_ast::ast::{Top, TopId, TypeExpId, TypeExpressionBlock}; mod alias; mod description; mod get; mod meta; mod to_string_attribute; - -use crate::{ - context::Context, - types::{ClassAttributes, EnumAttributes, SerializerAttributes, VariantAttributes}, -}; +use crate::{context::Context, types::ClassAttributes, types::EnumAttributes}; +use internal_baml_schema_ast::ast::SubType; pub(super) fn resolve_attributes(ctx: &mut Context<'_>) { for top in ctx.ast.iter_tops() { match top { (TopId::Class(class_id), Top::Class(ast_class)) => { - resolve_class_attributes(class_id, ast_class, ctx) + resolve_type_exp_block_attributes(class_id, ast_class, ctx, SubType::Class) } (TopId::Enum(enum_id), Top::Enum(ast_enum)) => { - resolve_enum_attributes(enum_id, ast_enum, ctx) - } - (TopId::Variant(ctid), Top::Variant(ast_variant)) if ast_variant.is_llm() => { - resolve_llm_variant_attributes(ctid, ast_variant, ctx) + resolve_type_exp_block_attributes(enum_id, ast_enum, ctx, SubType::Enum) } _ => (), } } } -fn resolve_enum_attributes<'db>(enum_id: EnumId, ast_enum: &'db Enum, ctx: &mut Context<'db>) { - let mut enum_attributes = EnumAttributes::default(); - - for (value_idx, _value) in ast_enum.iter_values() { - ctx.visit_attributes((enum_id, value_idx).into()); - if let Some(attrs) = to_string_attribute::visit(ctx, false) { - enum_attributes.value_serilizers.insert(value_idx, attrs); - } - ctx.validate_visited_attributes(); - } - - // Now validate the enum attributes. - ctx.visit_attributes(enum_id.into()); - enum_attributes.serilizer = to_string_attribute::visit(ctx, true); - ctx.validate_visited_attributes(); - - ctx.types.enum_attributes.insert(enum_id, enum_attributes); -} - -fn resolve_class_attributes<'db>(class_id: ClassId, ast_class: &'db Class, ctx: &mut Context<'db>) { - let mut class_attributes = ClassAttributes::default(); - - for (field_id, _) in ast_class.iter_fields() { - ctx.visit_attributes((class_id, field_id).into()); - if let Some(attrs) = to_string_attribute::visit(ctx, false) { - class_attributes.field_serilizers.insert(field_id, attrs); - } - ctx.validate_visited_attributes(); - } - - // Now validate the class attributes. - ctx.visit_attributes(class_id.into()); - class_attributes.serilizer = to_string_attribute::visit(ctx, true); - ctx.validate_visited_attributes(); - - ctx.types - .class_attributes - .insert(class_id, class_attributes); -} - -fn resolve_llm_variant_attributes<'db>( - variant_id: VariantConfigId, - ast_variant: &'db Variant, +fn resolve_type_exp_block_attributes<'db>( + type_id: TypeExpId, + ast_typexpr: &'db TypeExpressionBlock, ctx: &mut Context<'db>, + sub_type: SubType, ) { - let mut variant_attributes = VariantAttributes::default(); - - for (field_id, _) in ast_variant.iter_fields() { - ctx.visit_attributes((variant_id, field_id).into()); - // Variant fields can have no attributes (for now). - // TODO: Support expressions to have attributes. - ctx.validate_visited_attributes(); - } - - for (serializer_idx, serializer) in ast_variant.iter_serializers() { - let mut serializer_attr = SerializerAttributes::default(); - for (field_id, _value_idx) in serializer.iter_fields() { - ctx.visit_attributes((variant_id, serializer_idx, field_id).into()); - if let Some(attrs) = to_string_attribute::visit(ctx, false) { - serializer_attr.field_serilizers.insert(field_id, attrs); + match sub_type { + SubType::Enum => { + let mut enum_attributes = EnumAttributes::default(); + + for (value_idx, _value) in ast_typexpr.iter_fields() { + ctx.visit_attributes((type_id, value_idx).into()); + if let Some(attrs) = to_string_attribute::visit(ctx, false) { + enum_attributes.value_serilizers.insert(value_idx, attrs); + } + ctx.validate_visited_attributes(); } + + // Now validate the enum attributes. + ctx.visit_attributes(type_id.into()); + enum_attributes.serilizer = to_string_attribute::visit(ctx, true); ctx.validate_visited_attributes(); + + ctx.types.enum_attributes.insert(type_id, enum_attributes); } + SubType::Class => { + let mut class_attributes = ClassAttributes::default(); + + for (field_idx, _field) in ast_typexpr.iter_fields() { + ctx.visit_attributes((type_id, field_idx).into()); + if let Some(attrs) = to_string_attribute::visit(ctx, false) { + class_attributes.field_serilizers.insert(field_idx, attrs); + } + ctx.validate_visited_attributes(); + } - // Now validate the class attributes. - ctx.visit_attributes((variant_id, serializer_idx).into()); - serializer_attr.serilizer = to_string_attribute::visit(ctx, true); - ctx.validate_visited_attributes(); + // Now validate the class attributes. + ctx.visit_attributes(type_id.into()); + class_attributes.serilizer = to_string_attribute::visit(ctx, true); + ctx.validate_visited_attributes(); - if variant_attributes - .serializers - .insert(serializer_idx, serializer_attr) - .is_some() - { - ctx.push_error(DatamodelError::new_validation_error( - "Duplicate serializer name.", - serializer.name.span().clone(), - )); + ctx.types.class_attributes.insert(type_id, class_attributes); } - } - - // Now validate the class attributes. - ctx.visit_attributes(variant_id.into()); - ctx.validate_visited_attributes(); - ctx.types - .variant_attributes - .insert(variant_id, variant_attributes); + _ => (), + } } diff --git a/engine/baml-lib/parser-database/src/attributes/to_string_attribute.rs b/engine/baml-lib/parser-database/src/attributes/to_string_attribute.rs index 63173bb3f..baae5d767 100644 --- a/engine/baml-lib/parser-database/src/attributes/to_string_attribute.rs +++ b/engine/baml-lib/parser-database/src/attributes/to_string_attribute.rs @@ -23,6 +23,12 @@ pub(super) fn visit(ctx: &mut Context<'_>, as_block: bool) -> Option, as_block: bool) -> Option>(); - - default_impl.iter().for_each(|((_, fid), impl_name, span)| { - self.types.function.get_mut(fid).unwrap().default_impl = - Some((impl_name.clone(), span.clone())) - }); } fn finalize_dependencies(&mut self, diag: &mut Diagnostics) { @@ -276,108 +254,6 @@ impl ParserDatabase { } } - fn finalize_prompt_validation(&mut self, diag: &mut Diagnostics) { - let mut vars: HashMap<_, _> = Default::default(); - - self.walk_variants().for_each(|variant| { - let mut input_replacers = HashMap::new(); - let mut output_replacers = HashMap::new(); - let mut chat_replacers = vec![]; - if let Some(fn_walker) = variant.walk_function() { - // Now lets validate the prompt is what we expect. - let prompt_variables = &variant.properties().prompt_replacements; - - let num_errors = prompt_variables.iter().fold(0, |count, f| match f { - PromptVariable::Input(variable) => { - // Ensure the prompt has an input path that works. - match types::post_prompt::process_input(self, fn_walker, variable) { - Ok(replacer) => { - input_replacers.insert(variable.to_owned(), replacer); - count - } - Err(e) => { - diag.push_error(e); - count + 1 - } - } - } - PromptVariable::Enum(blk) => { - // Ensure the prompt has an enum path that works. - match types::post_prompt::process_print_enum( - self, variant, fn_walker, blk, diag, - ) { - Ok(result) => { - output_replacers.insert(blk.to_owned(), result); - count - } - Err(e) => { - diag.push_error(e); - count + 1 - } - } - } - PromptVariable::Type(blk) => { - // Ensure the prompt has an enum path that works. - match types::post_prompt::process_print_type(self, variant, fn_walker, blk) - { - Ok(result) => { - output_replacers.insert(blk.to_owned(), result); - count - } - Err(e) => { - diag.push_error(e); - count + 1 - } - } - } - PromptVariable::Chat(c) => { - chat_replacers.push(c.clone()); - count - } - }); - - if num_errors == 0 { - // Some simple error checking. - let span = &variant.properties().prompt.key_span; - // Validation already done that the prompt is valid. - // We should just ensure that atleast one of the input or output replacers is used. - if input_replacers.is_empty() { - diag.push_warning(DatamodelWarning::prompt_variable_unused( - "Expected prompt to use {#input}", - span.clone(), - )); - } - - // TODO: We should ensure every enum the class uses is used here. - if output_replacers.is_empty() { - diag.push_warning(DatamodelWarning::prompt_variable_unused( - "Expected prompt to use {#print_type(..)} or {#print_enum(..)} but none was found", - span.clone(), - )); - } - - // Only in this case update the prompt. - vars.insert( - variant.id, - (input_replacers, output_replacers, chat_replacers), - ); - } - } else { - diag.push_error(DatamodelError::new_type_not_found_error( - variant.function_identifier().name(), - self.valid_function_names(), - variant.function_identifier().span().clone(), - )); - } - }); - - if !diag.has_errors() { - vars.into_iter().for_each(|(k, v)| { - self.types.variant_properties.get_mut(&k).unwrap().replacers = v; - }); - } - } - /// The parsed AST. pub fn ast(&self) -> &ast::SchemaAst { &self.ast diff --git a/engine/baml-lib/parser-database/src/names/mod.rs b/engine/baml-lib/parser-database/src/names/mod.rs index 29ad773ce..0d211fa21 100644 --- a/engine/baml-lib/parser-database/src/names/mod.rs +++ b/engine/baml-lib/parser-database/src/names/mod.rs @@ -5,7 +5,8 @@ use crate::{ coerce, coerce_array, Context, DatamodelError, StaticType, StringId, }; -use internal_baml_schema_ast::ast::{ConfigBlockProperty, WithIdentifier}; +use baml_types::FieldType; +use internal_baml_schema_ast::ast::{ConfigBlockProperty, Expression, Field, WithIdentifier}; use rustc_hash::{FxHashMap as HashMap, FxHashSet as HashSet}; use validate_reserved_names::*; @@ -21,7 +22,7 @@ pub(super) struct Names { pub(super) generators: HashMap, /// Tests have their own namespace. pub(super) tests: HashMap>, - pub(super) model_fields: HashMap<(ast::ClassId, StringId), ast::FieldId>, + pub(super) model_fields: HashMap<(ast::TypeExpId, StringId), ast::FieldId>, // pub(super) composite_type_fields: HashMap<(ast::CompositeTypeId, StringId), ast::FieldId>, } @@ -31,7 +32,6 @@ pub(super) struct Names { /// - Model, enum and type alias names /// - Generators /// - Model fields for each model -/// - Enum variants for each enum pub(super) fn resolve_names(ctx: &mut Context<'_>) { let mut tmp_names: HashSet<&str> = HashSet::default(); // throwaway container for duplicate checking let mut names = Names::default(); @@ -45,27 +45,29 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) { validate_enum_name(ast_enum, ctx.diagnostics); validate_attribute_identifiers(ast_enum, ctx); - for value in &ast_enum.values { + for value in &ast_enum.fields { validate_enum_value_name(value, ctx.diagnostics); + validate_attribute_identifiers(value, ctx); - if !tmp_names.insert(value.name.name()) { + if !tmp_names.insert(value.name()) { ctx.push_error(DatamodelError::new_duplicate_enum_value_error( ast_enum.name.name(), - value.name.name(), - value.span.clone(), + value.name(), + value.span().clone(), )) } } Some(either::Left(&mut names.tops)) } + (ast::TopId::Class(model_id), ast::Top::Class(ast_class)) => { validate_class_name(ast_class, ctx.diagnostics); validate_attribute_identifiers(ast_class, ctx); for (field_id, field) in ast_class.iter_fields() { - validate_class_fiel_name(field, ctx.diagnostics); + validate_class_field_name(field, ctx.diagnostics); validate_attribute_identifiers(field, ctx); let field_name_id = ctx.interner.intern(field.name()); @@ -97,68 +99,73 @@ pub(super) fn resolve_names(ctx: &mut Context<'_>) { (_, ast::Top::TemplateString(_)) => { unreachable!("Encountered impossible template_string declaration during parsing") } - (ast::TopId::Function(_function_id), ast::Top::FunctionOld(ast_function)) => { + + (ast::TopId::Function(_function_id), ast::Top::Function(ast_function)) => { validate_function_name(ast_function, ctx.diagnostics); validate_attribute_identifiers(ast_function, ctx); Some(either::Left(&mut names.tops)) } - (_, ast::Top::FunctionOld(_)) => { + (_, ast::Top::Function(_)) => { unreachable!("Encountered impossible function declaration during parsing") } - (ast::TopId::Function(_function_id), ast::Top::Function(ast_function)) => { - validate_function_name(ast_function, ctx.diagnostics); - validate_attribute_identifiers(ast_function, ctx); + + (ast::TopId::Client(_), ast::Top::Client(ast_client)) => { + validate_client_name(ast_client, ctx.diagnostics); + validate_attribute_identifiers(ast_client, ctx); + + ctx.interner.intern(ast_client.identifier().name()); Some(either::Left(&mut names.tops)) } - (_, ast::Top::Function(_)) => { - unreachable!("Encountered impossible function declaration during parsing") + (_, ast::Top::Client(_)) => { + unreachable!("Encountered impossible client declaration during parsing") + } + + (ast::TopId::RetryPolicy(_), ast::Top::RetryPolicy(ast_retry_policy)) => { + validate_retry(ast_retry_policy, ctx.diagnostics); + validate_attribute_identifiers(ast_retry_policy, ctx); + + ctx.interner.intern(ast_retry_policy.identifier().name()); + + Some(either::Left(&mut names.tops)) + } + (_, ast::Top::RetryPolicy(_)) => { + unreachable!("Encountered impossible retry_policy declaration during parsing") } + (_, ast::Top::Generator(generator)) => { validate_generator_name(generator, ctx.diagnostics); check_for_duplicate_properties(top, generator.fields(), &mut tmp_names, ctx); Some(either::Left(&mut names.generators)) } - (_, ast::Top::Variant(variant)) => { - validate_variant_name(variant, ctx.diagnostics); - check_for_duplicate_properties(top, &variant.fields, &mut tmp_names, ctx); - Some(either::Left(&mut names.tops)) - } - (_, ast::Top::Client(client)) => { - validate_client_name(client, ctx.diagnostics); - check_for_duplicate_properties(top, client.fields(), &mut tmp_names, ctx); - Some(either::Left(&mut names.tops)) - } - (_, ast::Top::Config(config)) => { - validate_config_name(config, ctx.diagnostics); - check_for_duplicate_properties(top, config.fields(), &mut tmp_names, ctx); - match config { - ast::Configuration::TestCase(t) => { - // TODO: I think we should do this later after all parsing, as duplication - // would work best as a validation error with walkers. - let function_ids = t - .iter_fields() - .find(|f| f.1.name() == "functions") - .and_then(|f| match f.1.value { - Some(ref v) => coerce_array(v, &coerce::string, ctx.diagnostics), - None => None, - }); - - match function_ids { - Some(f) => Some(either::Right(f)), - None => { - ctx.push_error(DatamodelError::new_validation_error( - "Test case must have a functions field", - t.identifier().span().clone(), - )); - None - } - } + + (ast::TopId::TestCase(testcase_id), ast::Top::TestCase(testcase)) => { + validate_test(testcase, ctx.diagnostics); + check_for_duplicate_properties(top, testcase.fields(), &mut tmp_names, ctx); + + // TODO: I think we should do this later after all parsing, as duplication + // would work best as a validation error with walkers. + let function_ids = testcase + .iter_fields() + .find(|f| f.1.name() == "functions") + .and_then(|f| match f.1.expr { + Some(ref v) => coerce_array(v, &coerce::string, ctx.diagnostics), + None => None, + }); + + match function_ids { + Some(f) => Some(either::Right(f)), + None => { + ctx.push_error(DatamodelError::new_validation_error( + "Test case must have a functions field", + testcase.identifier().span().clone(), + )); + None } - _ => Some(either::Left(&mut names.tops)), } } + _ => None, }; match namespace { @@ -195,22 +202,6 @@ fn insert_name( let name = ctx.interner.intern(top.name()); if let Some(existing) = namespace.insert(name, top_id) { - // For variants, we do extra checks. - if let (Some(existing_variant), Some(current_variant)) = - (ctx.ast[existing].as_variant(), top.as_variant()) - { - let existing_function_name = existing_variant.function_name().name(); - let current_function_name = current_variant.function_name().name(); - - let existing_type = ctx.ast[existing].get_type(); - let current_type = top.get_type(); - - if existing_type == current_type && existing_function_name == current_function_name { - ctx.push_error(duplicate_top_error(&ctx.ast[existing], top)); - return; - } - } - let current_type = top.get_type(); if current_type != "impl" && current_type != "impl" { ctx.push_error(duplicate_top_error(&ctx.ast[existing], top)); @@ -238,17 +229,17 @@ fn assert_is_not_a_reserved_scalar_type(ident: &ast::Identifier, ctx: &mut Conte fn check_for_duplicate_properties<'a>( top: &ast::Top, - props: &'a [ConfigBlockProperty], + props: &'a [Field], tmp_names: &mut HashSet<&'a str>, ctx: &mut Context<'_>, ) { tmp_names.clear(); for arg in props { - if !tmp_names.insert(arg.name.name()) { + if !tmp_names.insert(arg.name()) { ctx.push_error(DatamodelError::new_duplicate_config_key_error( &format!("{} \"{}\"", top.get_type(), top.name()), - arg.name.name(), - arg.name.span().clone(), + arg.name(), + arg.span().clone(), )); } } diff --git a/engine/baml-lib/parser-database/src/names/validate_reserved_names.rs b/engine/baml-lib/parser-database/src/names/validate_reserved_names.rs index 6a5cfdd1b..781a838fc 100644 --- a/engine/baml-lib/parser-database/src/names/validate_reserved_names.rs +++ b/engine/baml-lib/parser-database/src/names/validate_reserved_names.rs @@ -1,3 +1,5 @@ +use internal_baml_schema_ast::ast::{FieldType, ValueExprBlockType}; + use crate::{ ast::{self, WithIdentifier, WithName}, DatamodelError, Diagnostics, @@ -8,46 +10,42 @@ pub(crate) fn validate_attribute_name(ast_attr: &ast::Attribute, diagnostics: &m } pub(crate) fn validate_generator_name( - ast_gen: &ast::GeneratorConfig, + ast_gen: &ast::ValueExprBlock, diagnostics: &mut Diagnostics, ) { validate_name("generator", ast_gen.identifier(), diagnostics, false); } -pub(crate) fn validate_client_name(ast_client: &ast::Client, diagnostics: &mut Diagnostics) { +pub(crate) fn validate_client_name( + ast_client: &ast::ValueExprBlock, + diagnostics: &mut Diagnostics, +) { validate_name("client", ast_client.identifier(), diagnostics, true); } -pub(crate) fn validate_config_name(ast_config: &ast::Configuration, diagnostics: &mut Diagnostics) { - match ast_config { - ast::Configuration::TestCase(_) => { - validate_name( - ast_config.get_type(), - ast_config.identifier(), - diagnostics, - false, - ); - } - _ => validate_name( - ast_config.get_type(), - ast_config.identifier(), - diagnostics, - // Test cases don't need to be upper case. - true, - ), - } +pub(crate) fn validate_test(ast_config: &ast::ValueExprBlock, diagnostics: &mut Diagnostics) { + validate_name("test", ast_config.identifier(), diagnostics, false); } -pub(crate) fn validate_variant_name(ast_variant: &ast::Variant, diagnostics: &mut Diagnostics) { - validate_name("impl", ast_variant.identifier(), diagnostics, false); +pub(crate) fn validate_retry(ast_config: &ast::ValueExprBlock, diagnostics: &mut Diagnostics) { + validate_name( + "retry", + ast_config.identifier(), + diagnostics, + // Test cases don't need to be upper case. + true, + ) } -pub(crate) fn validate_class_name(ast_class: &ast::Class, diagnostics: &mut Diagnostics) { +pub(crate) fn validate_class_name( + ast_class: &ast::TypeExpressionBlock, + diagnostics: &mut Diagnostics, +) { validate_name("class", ast_class.identifier(), diagnostics, true); } -pub(crate) fn validate_class_fiel_name( - ast_class_field: &ast::Field, +pub(crate) fn validate_class_field_name( + ast_class_field: &ast::Field, diagnostics: &mut Diagnostics, ) { validate_name( @@ -70,19 +68,25 @@ pub(crate) fn validate_template_string_name( ); } -pub(crate) fn validate_function_name(ast_func: &ast::Function, diagnostics: &mut Diagnostics) { +pub(crate) fn validate_function_name( + ast_func: &ast::ValueExprBlock, + diagnostics: &mut Diagnostics, +) { validate_name("function", ast_func.identifier(), diagnostics, true); } -pub(crate) fn validate_enum_name(ast_enum: &ast::Enum, diagnostics: &mut Diagnostics) { +pub(crate) fn validate_enum_name( + ast_enum: &ast::TypeExpressionBlock, + diagnostics: &mut Diagnostics, +) { validate_name("enum", ast_enum.identifier(), diagnostics, true); - ast_enum.iter_values().for_each(|(_, val)| { + ast_enum.iter_fields().for_each(|(_, val)| { validate_name("enum value", val.identifier(), diagnostics, true); }) } pub(crate) fn validate_enum_value_name( - ast_enum_value: &ast::EnumValue, + ast_enum_value: &ast::Field, diagnostics: &mut Diagnostics, ) { validate_name("enum value", ast_enum_value.identifier(), diagnostics, true); @@ -105,11 +109,7 @@ fn validate_name( "Namespace imports (using '.') are not yet supported.", span.clone(), )), - ast::Identifier::Primitive(_t, span) => Err(DatamodelError::new_name_error( - _type, - &format!("{} is a primitive type.", idn.name()), - span.clone(), - )), + ast::Identifier::Invalid(_, span) | ast::Identifier::String(_, span) => { Err(DatamodelError::new_name_error( _type, diff --git a/engine/baml-lib/parser-database/src/printer/mod.rs b/engine/baml-lib/parser-database/src/printer/mod.rs index 1492dd5b3..a92caa8f4 100644 --- a/engine/baml-lib/parser-database/src/printer/mod.rs +++ b/engine/baml-lib/parser-database/src/printer/mod.rs @@ -1,123 +1,17 @@ -use std::collections::HashMap; - use internal_baml_diagnostics::DatamodelError; -use internal_baml_prompt_parser::ast::PrinterBlock; -use internal_baml_schema_ast::ast::WithName; mod print_enum_default; mod print_type_default; -use crate::{ - interner::StringId, - types::{StaticStringAttributes, ToStringAttributes}, - walkers::VariantWalker, - ParserDatabase, -}; +use crate::ParserDatabase; /// Trait pub trait WithSerializeableContent { /// Trait to render an object. - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value; + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value; } /// Trait -pub trait WithStaticRenames<'db>: WithName { - /// Overrides for local names. - fn get_override(&self, variant: &VariantWalker<'db>) -> Option<&'_ ToStringAttributes>; - /// Overrides for local names. - fn get_default_attributes(&self) -> Option<&'db ToStringAttributes>; - - /// Overrides for local names. - fn alias(&'db self, variant: Option<&VariantWalker<'db>>, db: &'db ParserDatabase) -> String { - let (overrides, defaults) = self.get_attributes(variant); - - let override_alias = overrides.and_then(|o| *o.alias()); - let base_alias = defaults.and_then(|a| *a.alias()); - - match (override_alias, base_alias) { - (Some(id), _) => db[id].to_string(), - (None, Some(id)) => db[id].to_string(), - (None, None) => self.name().to_string(), - } - } - - /// Overrides for local names. - fn maybe_alias(&'db self, db: &'db ParserDatabase) -> Option { - let defaults = match self.get_default_attributes() { - Some(ToStringAttributes::Static(refs)) => Some(refs), - _ => None, - }; - let base_alias = defaults.and_then(|a| *a.alias()); - base_alias.map(|id| db[id].to_string()) - } - - /// Overrides for local names. - fn meta( - &'db self, - variant: Option<&VariantWalker<'db>>, - db: &'db ParserDatabase, - ) -> HashMap { - let (overrides, defaults) = self.get_attributes(variant); - - let mut meta: HashMap = Default::default(); - match defaults { - Some(a) => { - meta.extend(a.meta()); - } - None => {} - }; - - if let Some(o) = overrides { - meta.extend(o.meta()); - } - - meta.iter() - .map(|(&k, &v)| (db[k].to_string(), db[v].to_string())) - .collect::>() - } - - /// Overrides for skip. - fn skip(&'db self, variant: Option<&VariantWalker<'db>>) -> bool { - let (overrides, defaults) = self.get_attributes(variant); - - let override_alias = overrides.and_then(|o| *o.skip()); - let base_alias = defaults.and_then(|a| *a.skip()); - match (override_alias, base_alias) { - (Some(id), _) => id, - (None, Some(id)) => id, - (None, None) => false, - } - } - - /// Overrides for local names. - fn get_attributes( - &'db self, - variant: Option<&VariantWalker<'db>>, - ) -> ( - Option<&'db StaticStringAttributes>, - Option<&'db StaticStringAttributes>, - ) { - let defaults = match self.get_default_attributes() { - Some(ToStringAttributes::Static(refs)) => Some(refs), - _ => None, - }; - match variant { - Some(variant) => { - let overrides = match self.get_override(variant) { - Some(ToStringAttributes::Static(refs)) => Some(refs), - _ => None, - }; - - (overrides, defaults) - } - None => (None, defaults), - } - } -} /// Trait pub trait WithSerialize: WithSerializeableContent { @@ -125,8 +19,6 @@ pub trait WithSerialize: WithSerializeableContent { fn serialize( &self, db: &'_ ParserDatabase, - variant: Option<&VariantWalker<'_>>, - block: Option<&PrinterBlock>, span: &internal_baml_diagnostics::Span, ) -> Result; @@ -139,14 +31,7 @@ pub trait WithSerialize: WithSerializeableContent { } /// print_type, print_enum implementation -pub fn serialize_with_printer( - is_enum: bool, - template: Option, - json: serde_json::Value, -) -> Result { - if template.is_some() { - return Err("printer keyword is not yet supported".to_string()); - } +pub fn serialize_with_printer(is_enum: bool, json: serde_json::Value) -> Result { if is_enum { Ok(print_enum_default::print_enum(json)) } else { diff --git a/engine/baml-lib/parser-database/src/types/configurations.rs b/engine/baml-lib/parser-database/src/types/configurations.rs index 0d8ababde..f145220a2 100644 --- a/engine/baml-lib/parser-database/src/types/configurations.rs +++ b/engine/baml-lib/parser-database/src/types/configurations.rs @@ -1,7 +1,5 @@ use internal_baml_diagnostics::{DatamodelError, DatamodelWarning, Span}; -use internal_baml_schema_ast::ast::{ - ConfigurationId, PrinterConfig, RetryPolicyConfig, WithIdentifier, WithName, WithSpan, -}; +use internal_baml_schema_ast::ast::{ValExpId, ValueExprBlock, WithIdentifier, WithName, WithSpan}; use regex::Regex; use crate::{coerce, coerce_array, coerce_expression::coerce_map, context::Context}; @@ -33,71 +31,9 @@ fn dedent(s: &str) -> String { .to_string() } -pub(crate) fn visit_printer<'db>( - idx: ConfigurationId, - config: &'db PrinterConfig, - ctx: &mut Context<'db>, -) { - let mut template = None; - - config - .iter_fields() - .for_each(|(_idx, f)| match (f.name(), &f.value) { - (name, None) => { - ctx.push_error(DatamodelError::new_config_property_missing_value_error( - name, - config.name(), - "printer", - f.identifier().span().clone(), - )) - } - ("template", Some(val)) => match coerce::string_with_span(val, ctx.diagnostics) { - Some((t, span)) => template = Some((dedent(t), span.clone())), - None => {} - }, - (name, Some(_)) => ctx.push_error(DatamodelError::new_property_not_known_error( - name, - f.identifier().span().clone(), - ["template"].to_vec(), - )), - }); - - match ( - template, - coerce::string_with_span(&config.printer_type, ctx.diagnostics), - ) { - (None, _) => ctx.push_error(DatamodelError::new_validation_error( - "Missing `template` property", - config.identifier().span().clone(), - )), - (Some(template), Some(("enum", _))) => { - ctx.types - .printers - .insert(idx, PrinterType::Enum(Printer { template })); - } - (Some(template), Some(("type", _))) => { - ctx.types - .printers - .insert(idx, PrinterType::Type(Printer { template })); - } - (Some(_), Some((name, span))) => { - ctx.push_error(DatamodelError::new_validation_error( - &format!( - "Unknown printer type: {}. Options are `type` or `enum`", - name - ), - span.clone(), - )); - } - (Some(_), None) => { - // errors are handled by coerce::string_with_span - } - } -} - pub(crate) fn visit_retry_policy<'db>( - idx: ConfigurationId, - config: &'db RetryPolicyConfig, + idx: ValExpId, + config: &'db ValueExprBlock, ctx: &mut Context<'db>, ) { let mut max_reties = None; @@ -109,7 +45,7 @@ pub(crate) fn visit_retry_policy<'db>( config .iter_fields() - .for_each(|(_idx, f)| match (f.name(), &f.value) { + .for_each(|(_idx, f)| match (f.name(), &f.expr) { (name, None) => { ctx.push_error(DatamodelError::new_config_property_missing_value_error( name, @@ -261,8 +197,8 @@ fn visit_strategy( } pub(crate) fn visit_test_case<'db>( - idx: ConfigurationId, - config: &'db RetryPolicyConfig, + idx: ValExpId, + config: &'db ValueExprBlock, ctx: &mut Context<'db>, ) { let mut functions = None; @@ -270,7 +206,7 @@ pub(crate) fn visit_test_case<'db>( config .iter_fields() - .for_each(|(_idx, f)| match (f.name(), &f.value) { + .for_each(|(_idx, f)| match (f.name(), &f.expr) { (name, None) => { ctx.push_error(DatamodelError::new_config_property_missing_value_error( name, diff --git a/engine/baml-lib/parser-database/src/types/mod.rs b/engine/baml-lib/parser-database/src/types/mod.rs index e4936cd12..efb2cb39d 100644 --- a/engine/baml-lib/parser-database/src/types/mod.rs +++ b/engine/baml-lib/parser-database/src/types/mod.rs @@ -2,14 +2,14 @@ use std::collections::{HashMap, HashSet}; use std::hash::Hash; use crate::coerce; +use crate::types::configurations::visit_test_case; use crate::{context::Context, DatamodelError}; use indexmap::IndexMap; use internal_baml_diagnostics::{DatamodelWarning, Span}; use internal_baml_prompt_parser::ast::{ChatBlock, PrinterBlock, Variable}; use internal_baml_schema_ast::ast::{ - self, AdapterId, ClassId, ClientId, ConfigurationId, EnumId, EnumValueId, Expression, FieldId, - FieldType, FunctionId, RawString, SerializerFieldId, VariantConfigId, VariantSerializerId, + self, Expression, FieldId, FieldType, RawString, TypeExpId, ValExpId, ValueExprBlockType, WithIdentifier, WithName, WithSpan, }; @@ -28,41 +28,43 @@ pub use to_string_attributes::{ pub(crate) use types::EnumAttributes; pub(crate) use types::*; +use self::configurations::visit_retry_policy; + pub(super) fn resolve_types(ctx: &mut Context<'_>) { for (top_id, top) in ctx.ast.iter_tops() { match (top_id, top) { - (_, ast::Top::Enum(enm)) => visit_enum(enm, ctx), + (ast::TopId::Enum(idx), ast::Top::Enum(model)) => visit_enum(model, ctx), + (_, ast::Top::Enum(enm)) => unreachable!("Enum misconfigured"), + (ast::TopId::Class(idx), ast::Top::Class(model)) => visit_class(idx, model, ctx), (_, ast::Top::Class(_)) => unreachable!("Class misconfigured"), (ast::TopId::TemplateString(idx), ast::Top::TemplateString(template_string)) => { visit_template_string(idx, template_string, ctx) } (_, ast::Top::TemplateString(_)) => unreachable!("TemplateString misconfigured"), - (ast::TopId::Function(idx), ast::Top::FunctionOld(function)) => { - visit_old_function(idx, function, ctx) - } - (_, ast::Top::FunctionOld(_)) => unreachable!("Function misconfigured"), + (ast::TopId::Function(idx), ast::Top::Function(function)) => { visit_function(idx, function, ctx) } (_, ast::Top::Function(_)) => unreachable!("Function misconfigured"), - (ast::TopId::Variant(idx), ast::Top::Variant(variant)) => { - visit_variant(idx, variant, ctx) - } - (_, ast::Top::Variant(_)) => unreachable!("Variant misconfigured"), (ast::TopId::Client(idx), ast::Top::Client(client)) => { visit_client(idx, client, ctx); } + (_, ast::Top::Client(_)) => unreachable!("Client misconfigured"), - (_, ast::Top::Generator(_generator)) => {} - (ast::TopId::Config((idx, _)), ast::Top::Config(cfg)) => { - visit_config(idx, cfg, ctx); + (ast::TopId::RetryPolicy(idx), ast::Top::RetryPolicy(config)) => { + visit_retry_policy(idx, config, ctx); + } + (_, ast::Top::RetryPolicy(_)) => unreachable!("RetryPolicy misconfigured"), + (ast::TopId::TestCase(idx), ast::Top::TestCase(config)) => { + visit_test_case(idx, config, ctx); } - (_, ast::Top::Config(_)) => unreachable!("Config misconfigured"), + (_, ast::Top::TestCase(_)) => unreachable!("TestCase misconfigured"), + + _ => {} } } } - #[derive(Debug, Clone)] /// Variables used inside of raw strings. pub enum PromptVariable { @@ -118,19 +120,6 @@ pub struct StringValue { pub key_span: Span, } -#[derive(Debug)] -pub struct VariantProperties { - pub client: StringValue, - pub prompt: StringValue, - pub prompt_replacements: Vec, - pub replacers: ( - HashMap, - HashMap, - Vec, - ), - pub output_adapter: Option<(AdapterId, Vec)>, -} - /// The representation of a prompt. pub enum PromptAst<'a> { /// For single string prompts @@ -142,93 +131,6 @@ pub enum PromptAst<'a> { Chat(Vec<(Option<&'a ChatBlock>, String)>, Vec<(String, String)>), } -impl VariantProperties { - pub fn output_adapter_for_language(&self, language: &str) -> Option<&str> { - self.output_adapter.as_ref().and_then(|f| { - f.1.iter() - .find(|r| r.language.as_ref().map(|(l, _)| l.as_str()) == Some(language)) - .map(|r| r.value()) - }) - } - - pub fn to_prompt(&self) -> PromptAst<'_> { - let (input, output, chats) = &self.replacers; - - // Replace all the inputs with the input replacers - let mut used_inputs = vec![]; - let prompt = input - .iter() - .fold(self.prompt.value.clone(), |prompt, (k, val)| { - // Only add the input if it's used in the prompt - let key = k.key(); - if prompt.contains(&key) { - used_inputs.push((key.clone(), val.clone())); - prompt - } else { - prompt - } - }); - // Replace all the outputs with the output replacers - let prompt = output.iter().fold(prompt, |prompt, (k, val)| { - prompt.replace(&k.key(), &val.to_string()) - }); - - used_inputs.sort(); - - if chats.is_empty() { - PromptAst::String(prompt, used_inputs) - } else { - // Split the prompt into parts based on the chat blocks. - let mut last_idx = 0; - let mut parts = vec![]; - for chat in chats { - let splitter = chat.key(); - let idx = prompt[last_idx..].find(&splitter); - if let Some(idx) = idx { - parts.push(( - Some(chat), - (idx + last_idx, idx + last_idx + splitter.len()), - )); - last_idx += idx + splitter.len(); - } - } - - match parts.first() { - // If the first chat block is not at the start of the prompt, add the first part. - Some(&(Some(_), (start, _))) if start > 0 => { - parts.insert(0, (None, (0, 0))); - } - Some(_) => {} - _ => unreachable!("At least one chat block should exist"), - } - - // Each chat block owns a part of the prompt. until the next chat block. - PromptAst::Chat( - parts - .iter() - .enumerate() - .filter_map(|(idx, &(chat, (_, start)))| { - let end = if idx + 1 < parts.len() { - parts[idx + 1].1 .0 - } else { - prompt.len() - }; - - let p = prompt[start..end].trim(); - if p.is_empty() { - info!("Skipping empty prompt part: {} {} {}", idx, start, end); - None - } else { - Some((chat, p.to_string())) - } - }) - .collect(), - used_inputs, - ) - } - } -} - #[derive(Debug, Clone)] pub struct ClientProperties { pub provider: (String, Span), @@ -325,24 +227,22 @@ pub struct TemplateStringProperties { #[derive(Debug, Default)] pub(super) struct Types { - pub(super) enum_attributes: HashMap, - pub(super) class_attributes: HashMap, - pub(super) class_dependencies: HashMap>, - pub(super) function: HashMap, - pub(super) variant_attributes: HashMap, - pub(super) variant_properties: HashMap, - pub(super) client_properties: HashMap, - pub(super) retry_policies: HashMap, - pub(super) printers: HashMap, - pub(super) test_cases: HashMap, + pub(super) enum_attributes: HashMap, + pub(super) class_attributes: HashMap, + pub(super) class_dependencies: HashMap>, + pub(super) function: HashMap, + + pub(super) client_properties: HashMap, + pub(super) retry_policies: HashMap, + pub(super) test_cases: HashMap, pub(super) template_strings: - HashMap, TemplateStringProperties>, + HashMap, TemplateStringProperties>, } impl Types { pub(super) fn refine_class_field( &self, - (class_id, field_id): (ClassId, FieldId), + (class_id, field_id): (TypeExpId, FieldId), ) -> either::Either { match self.class_attributes.get(&class_id) { Some(attrs) => match attrs.field_serilizers.get(&field_id) { @@ -355,7 +255,7 @@ impl Types { pub(super) fn refine_enum_value( &self, - (enum_id, value_id): (EnumId, EnumValueId), + (enum_id, value_id): (TypeExpId, FieldId), ) -> either::Either { match self.enum_attributes.get(&enum_id) { Some(attrs) => match attrs.value_serilizers.get(&value_id) { @@ -365,28 +265,6 @@ impl Types { None => either::Either::Left(value_id.into()), } } - - #[allow(dead_code)] - pub(super) fn refine_serializer_field( - &self, - (variant_id, serializer_id, value_id): ( - VariantConfigId, - VariantSerializerId, - SerializerFieldId, - ), - ) -> either::Either { - match self - .variant_attributes - .get(&variant_id) - .and_then(|r| r.serializers.get(&serializer_id)) - { - Some(attrs) => match attrs.field_serilizers.get(&value_id) { - Some(ToStringAttributes::Dynamic(_)) => either::Either::Right(value_id.into()), - _ => either::Either::Left(value_id.into()), - }, - None => either::Either::Left(value_id.into()), - } - } } fn visit_template_string<'db>( @@ -414,35 +292,40 @@ fn visit_template_string<'db>( ); } -fn visit_enum<'db>(_enm: &'db ast::Enum, _ctx: &mut Context<'db>) {} +fn visit_enum<'db>(_enm: &'db ast::TypeExpressionBlock, _ctx: &mut Context<'db>) {} -fn visit_class<'db>(class_id: ast::ClassId, class: &'db ast::Class, ctx: &mut Context<'db>) { +fn visit_class<'db>( + class_id: ast::TypeExpId, + class: &'db ast::TypeExpressionBlock, + ctx: &mut Context<'db>, +) { let used_types = class .iter_fields() - .flat_map(|(_, f)| f.field_type.flat_idns()) - .filter(|id| { - id.is_valid_type() - && match id { - ast::Identifier::Primitive(..) => false, - _ => true, - } - }) - .map(|f| f.name().to_string()) + .flat_map(|(_, f)| f.expr.iter().flat_map(|e| e.flat_idns())) + // .filter(|id| { + // id.is_valid_type() + // && match id { + // ast::Identifier::Primitive(..) => false, + // _ => true, + // } + // }) + .map(|id| id.name().to_string()) .collect::>(); ctx.types.class_dependencies.insert(class_id, used_types); } -fn visit_function<'db>(idx: FunctionId, function: &'db ast::Function, ctx: &mut Context<'db>) { +fn visit_function<'db>(idx: ValExpId, function: &'db ast::ValueExprBlock, ctx: &mut Context<'db>) { let input_deps = function .input() - .flat_idns() + .map(|input| input.flat_idns()) + .unwrap_or_else(Vec::new) .iter() .map(|f| f.name().to_string()) .collect::>(); - let output_deps = function .output() - .flat_idns() + .map(|output| output.field_type.flat_idns()) + .unwrap_or_else(Vec::new) .iter() .map(|f| f.name().to_string()) .collect::>(); @@ -453,25 +336,13 @@ fn visit_function<'db>(idx: FunctionId, function: &'db ast::Function, ctx: &mut .iter_fields() .for_each(|(_idx, field)| match field.name() { "prompt" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Template args are not allowed in `prompt`.", - field.span().clone(), - )); - } - prompt = match &field.value { + prompt = match &field.expr { Some(val) => coerce::template_string(val, ctx.diagnostics), None => None, } } "client" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Template args are not allowed in `client`.", - field.span().clone(), - )); - } - client = match &field.value { + client = match &field.expr { Some(val) => coerce::string_with_span(val, ctx.diagnostics) .map(|(v, span)| (v.to_string(), span.clone())), None => None, @@ -525,97 +396,17 @@ fn visit_function<'db>(idx: FunctionId, function: &'db ast::Function, ctx: &mut } } -fn visit_old_function<'db>(idx: FunctionId, function: &'db ast::Function, ctx: &mut Context<'db>) { - let input_deps = function - .input() - .flat_idns() - .iter() - .map(|f| f.name().to_string()) - .collect::>(); - - let output_deps = function - .output() - .flat_idns() - .iter() - .map(|f| f.name().to_string()) - .collect::>(); - - let mut default_impl = None; - function - .iter_fields() - .for_each(|(_idx, field)| match field.name() { - "default_impl" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `impl` instead of `impl<...>`?", - field.span().clone(), - )); - } - default_impl = match &field.value { - Some(val) => coerce::string_with_span(val, ctx.diagnostics) - .map(|(v, span)| (v.to_string(), span.clone())), - None => None, - } - } - config => ctx.push_error(DatamodelError::new_validation_error( - &format!("Unknown field `{}` in function", config), - field.span().clone(), - )), - }); - - ctx.types.function.insert( - idx, - FunctionType { - default_impl, - dependencies: (input_deps, output_deps), - prompt: None, - client: None, - }, - ); -} - -fn visit_client<'db>(idx: ClientId, client: &'db ast::Client, ctx: &mut Context<'db>) { - if !client.is_llm() { - ctx.push_error(DatamodelError::new_validation_error( - "Only LLM clients are supported. Use: client", - client.identifier().span().clone(), - )); - return; - } - +fn visit_client<'db>(idx: ValExpId, client: &'db ast::ValueExprBlock, ctx: &mut Context<'db>) { let mut provider = None; let mut retry_policy = None; let mut options: Vec<(String, Expression)> = Vec::new(); client .iter_fields() .for_each(|(_idx, field)| match field.name() { - "provider" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `provider` instead of `provider<...>`?", - field.span().clone(), - )); - } - provider = field.value.as_ref() - } - "retry_policy" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `retry_policy` instead of `retry_policy<...>`?", - field.span().clone(), - )); - } - retry_policy = field.value.as_ref() - } + "provider" => provider = field.expr.as_ref(), + "retry_policy" => retry_policy = field.expr.as_ref(), "options" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `options` instead of `options<...>`?", - field.span().clone(), - )); - } - - match field.value.as_ref() { + match field.expr.as_ref() { Some(ast::Expression::Map(map, span)) => { map.iter().for_each(|(key, value)| { if let Some(key) = coerce::string(key, ctx.diagnostics) { @@ -679,233 +470,6 @@ fn visit_client<'db>(idx: ClientId, client: &'db ast::Client, ctx: &mut Context< } } -fn visit_variant<'db>(idx: VariantConfigId, variant: &'db ast::Variant, ctx: &mut Context<'db>) { - if !variant.is_llm() { - ctx.push_error(DatamodelError::new_validation_error( - "Only LLM variants are supported. Use: impl", - variant.span().clone(), - )); - return; - } - - let mut client = None; - let mut prompt = None; - - variant - .iter_fields() - .for_each(|(_idx, field)| match field.name() { - "client" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `client` instead of `client<...>`?", - field.span().clone(), - )); - } - match field.value.as_ref() { - Some(item) => client = Some((item, field.identifier().span().clone())), - _ => {} - } - } - "prompt" => { - if field.template_args.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "Did you mean `prompt` instead of `prompt<...>`?", - field.span().clone(), - )); - } - match field.value.as_ref() { - Some(item) => prompt = Some((item, field.identifier().span().clone())), - _ => {} - } - } - config => ctx.push_error(DatamodelError::new_validation_error( - &format!("Unknown field `{}` in impl", config), - field.span().clone(), - )), - }); - - let client = if let Some((client, client_key_span)) = client { - coerce::string_with_span(client, ctx.diagnostics).map(|client| (client, client_key_span)) - } else { - ctx.push_error(DatamodelError::new_validation_error( - "Missing `client` field in impl", - variant.identifier().span().clone(), - )); - None - }; - - let prompt = if let Some((prompt, prompt_key_span)) = prompt { - if let Some(prompt) = prompt.as_raw_string_value() { - validate_prompt(ctx, prompt).map(|(cleaned_prompt, replacer)| { - ((cleaned_prompt, prompt.span(), replacer), prompt_key_span) - }) - } else if let Some((prompt, span)) = coerce::string_with_span(prompt, ctx.diagnostics) { - // warn the user that we are using this without validation. - ctx.push_warning(DatamodelWarning::new( - "To use comments and {#vars} use a block string. #\"...\"# instead.".into(), - span.clone(), - )); - Some(( - (prompt.to_string(), span, Default::default()), - prompt_key_span, - )) - } else { - // Errors are handled by coerce. - None - } - } else { - ctx.push_error(DatamodelError::new_validation_error( - "Missing `prompt` field in impl", - variant.identifier().span().clone(), - )); - None - }; - - // Ensure that the adapters are valid. - let (_input_adapter, output_adapter) = - variant - .iter_adapters() - .fold((None, None), |prev, (idx, adapter)| { - let is_input = match &adapter.from { - FieldType::Identifier(arity, idn) if idn.name() == "input" => { - if arity.is_optional() { - ctx.push_error(DatamodelError::new_validation_error( - "The `input` adapter cannot be optional.", - idn.span().clone(), - )); - false - } else { - true - } - } - _ => false, - }; - - let is_output = match &adapter.to { - FieldType::Identifier(arity, idn) if idn.name() == "output" => { - if arity.is_optional() { - ctx.push_error(DatamodelError::new_validation_error( - "The `output` adapter cannot be optional.", - idn.span().clone(), - )); - false - } else { - true - } - } - _ => false, - }; - - if is_input && is_output { - ctx.push_error(DatamodelError::new_validation_error( - "The `input` and `output` adapters cannot be used together.", - adapter.span().clone(), - )); - } else if is_input { - if prev.0.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "The `input` adapter can only be used once.", - adapter.span().clone(), - )); - } else { - // Ensure the expr is either a string of array of strings. - let impls = if let Some((arr, _)) = adapter.converter.as_array() { - Some( - arr.iter() - .filter_map(|item| coerce::raw_string(item, ctx.diagnostics)) - .collect::>(), - ) - } else { - coerce::raw_string(&adapter.converter, ctx.diagnostics) - .map(|raw| vec![raw]) - }; - - if let Some(impls) = impls { - ctx.push_warning(DatamodelWarning::new( - "The `input` adapter is note yet supported.".into(), - adapter.span().clone(), - )); - return (Some((idx, impls)), prev.1); - } - } - } else if is_output { - if prev.1.is_some() { - ctx.push_error(DatamodelError::new_validation_error( - "The `output` adapter can only be used once.", - adapter.span().clone(), - )); - } else { - let impls = if let Some((arr, _)) = adapter.converter.as_array() { - Some( - arr.iter() - .filter_map(|item| coerce::raw_string(item, ctx.diagnostics)) - .cloned() - .collect::>(), - ) - } else { - coerce::raw_string(&adapter.converter, ctx.diagnostics) - .map(|raw| vec![raw.clone()]) - }; - - if let Some(impls) = impls { - return (prev.0, Some((idx, impls))); - } - } - } else { - ctx.push_error(DatamodelError::new_validation_error( - "The `input` or `output` adapter must be used.", - adapter.span().clone(), - )); - } - prev - }); - - match (client, prompt) { - ( - Some(((client, client_span), client_key_span)), - Some(((prompt, prompt_span, replacers), prompt_key_span)), - ) => { - ctx.types.variant_properties.insert( - idx, - VariantProperties { - client: StringValue { - value: client.to_string(), - span: client_span.clone(), - key_span: client_key_span, - }, - prompt: StringValue { - value: prompt.to_string(), - span: prompt_span.clone(), - key_span: prompt_key_span, - }, - prompt_replacements: replacers, - replacers: Default::default(), - output_adapter, - }, - ); - } - _ => {} - } -} - -fn visit_config<'db>( - idx: ConfigurationId, - config: &'db ast::Configuration, - ctx: &mut Context<'db>, -) { - match config { - ast::Configuration::RetryPolicy(retry) => { - configurations::visit_retry_policy(idx, retry, ctx); - } - ast::Configuration::Printer(printer) => { - configurations::visit_printer(idx, printer, ctx); - } - ast::Configuration::TestCase(test_case) => { - configurations::visit_test_case(idx, test_case, ctx); - } - } -} - /// Prisma's builtin scalar types. #[derive(Debug, Copy, Clone, PartialEq, Hash, Eq)] #[allow(missing_docs)] @@ -956,42 +520,18 @@ impl StaticType { #[derive(Copy, Clone, PartialEq, Debug, Hash, Eq, PartialOrd, Ord)] pub struct DynamicFieldId(u32); -impl From for DynamicFieldId { - fn from(id: SerializerFieldId) -> Self { - DynamicFieldId(id.0) - } -} - impl From for DynamicFieldId { fn from(id: FieldId) -> Self { DynamicFieldId(id.0) } } -impl From for DynamicFieldId { - fn from(id: EnumValueId) -> Self { - DynamicFieldId(id.0) - } -} - /// An opaque identifier for a class field. #[derive(Copy, Clone, PartialEq, Debug, Eq, Hash)] pub struct StaticFieldId(u32); -impl From for StaticFieldId { - fn from(id: SerializerFieldId) -> Self { - StaticFieldId(id.0) - } -} - impl From for StaticFieldId { fn from(id: FieldId) -> Self { StaticFieldId(id.0) } } - -impl From for StaticFieldId { - fn from(id: EnumValueId) -> Self { - StaticFieldId(id.0) - } -} diff --git a/engine/baml-lib/parser-database/src/types/post_prompt.rs b/engine/baml-lib/parser-database/src/types/post_prompt.rs index 07a05b436..1a555f5ff 100644 --- a/engine/baml-lib/parser-database/src/types/post_prompt.rs +++ b/engine/baml-lib/parser-database/src/types/post_prompt.rs @@ -3,10 +3,7 @@ use internal_baml_diagnostics::{DatamodelError, DatamodelWarning, Diagnostics}; use internal_baml_prompt_parser::ast::{PrinterBlock, Variable, WithSpan}; use internal_baml_schema_ast::ast::{self, WithName}; -use crate::{ - walkers::{FunctionWalker, VariantWalker}, - ParserDatabase, WithSerialize, -}; +use crate::{walkers::FunctionWalker, ParserDatabase, WithSerialize}; pub(crate) fn process_input( db: &ParserDatabase, @@ -20,48 +17,38 @@ pub(crate) fn process_input( )); } - match walker.ast_function().input() { - ast::FunctionArgs::Unnamed(arg) => { - validate_variable_path(db, variable, 1, &arg.field_type)?; - let mut new_path = variable.path.clone(); - new_path[0] = "arg".to_string(); - Ok(new_path.join(".")) - } - ast::FunctionArgs::Named(args) => { - if variable.path.len() < 2 { - return Err(DatamodelError::new_validation_error( - "Named arguments must have at least one argument (input.my_var_name)", - variable.span.clone(), - )); - } - let path_name = &variable.path[1]; - match args - .iter_args() - .find(|(_, (name, _))| name.name() == path_name) - { - Some((_, (_, arg))) => { - validate_variable_path(db, variable, 2, &arg.field_type)?; - Ok(variable.path[1..].join(".")) - } - None => Err(DatamodelError::new_validation_error( - &format!( - "Unknown arg `{}`. Could be one of: {}", - path_name, - args.iter_args() - .map(|(_, (name, _))| name.name()) - .collect::>() - .join(", ") - ), - variable.span.clone(), - )), - } + let args = walker.ast_function().input().expect("Expected input args"); + if variable.path.len() < 2 { + return Err(DatamodelError::new_validation_error( + "Named arguments must have at least one argument (input.my_var_name)", + variable.span.clone(), + )); + } + let path_name = &variable.path[1]; + match args + .iter_args() + .find(|(_, (name, _))| name.name() == path_name) + { + Some((_, (_, arg))) => { + validate_variable_path(db, variable, 2, &arg.field_type)?; + Ok(variable.path[1..].join(".")) } + None => Err(DatamodelError::new_validation_error( + &format!( + "Unknown arg `{}`. Could be one of: {}", + path_name, + args.iter_args() + .map(|(_, (name, _))| name.name()) + .collect::>() + .join(", ") + ), + variable.span.clone(), + )), } } pub(crate) fn process_print_enum( db: &ParserDatabase, - walker: VariantWalker<'_>, fn_walker: FunctionWalker<'_>, blk: &PrinterBlock, diag: &mut Diagnostics, @@ -99,7 +86,7 @@ pub(crate) fn process_print_enum( variable.span.clone(), )); } - enum_walker.serialize(fn_walker.db, Some(&walker), Some(blk), blk.span()) + enum_walker.serialize(fn_walker.db, blk.span()) } Some(Either::Left(_)) => Err(DatamodelError::new_validation_error( "Expected enum, found class", @@ -118,13 +105,12 @@ pub(crate) fn process_print_enum( pub(crate) fn process_print_type( db: &ParserDatabase, - walker: VariantWalker<'_>, fn_walker: FunctionWalker<'_>, blk: &PrinterBlock, ) -> Result { let variable = &blk.target; if variable.text == "output" { - return fn_walker.serialize(fn_walker.db, Some(&walker), Some(blk), blk.span()); + return fn_walker.serialize(fn_walker.db, blk.span()); } let candidates = fn_walker @@ -140,7 +126,7 @@ pub(crate) fn process_print_type( f.required_classes() .any(|idn| idn.name() == cls_walker.name()) }) { - true => cls_walker.serialize(fn_walker.db, Some(&walker), Some(blk), blk.span()), + true => cls_walker.serialize(fn_walker.db, blk.span()), false => Err(DatamodelError::type_not_used_in_prompt_error( false, true, @@ -179,7 +165,7 @@ fn validate_variable_path( let next_path_name = variable.path[next_index].clone(); match current { - ast::FieldType::Union(_, ft, _) => match ft + ast::FieldType::Union(_, ft, ..) => match ft .iter() .any(|ft| validate_variable_path(db, variable, next_index, ft).is_ok()) { @@ -189,27 +175,56 @@ fn validate_variable_path( variable.span.clone(), )), }, - ast::FieldType::Map(_, _) => Err(DatamodelError::new_validation_error( + ast::FieldType::Primitive(_, ft, _, ..) => Err(DatamodelError::new_validation_error( + "Primitive types are not indexable in the prompt", + variable.span.clone(), + )), + ast::FieldType::Map(_, _, ..) => Err(DatamodelError::new_validation_error( "Dictionary types are not supported", variable.span.clone(), )), - ast::FieldType::Tuple(_, _, _) => Err(DatamodelError::new_validation_error( + ast::FieldType::Tuple(_, _, _, _) => Err(DatamodelError::new_validation_error( "Tuple types are not supported", variable.span.clone(), )), - ast::FieldType::List(_, _, _) => Err(DatamodelError::new_validation_error( + ast::FieldType::List(_, _, _, _) => Err(DatamodelError::new_validation_error( "List types are not yet indexable in the prompt", variable.span.clone(), )), - ast::FieldType::Identifier(_, idn) => match db.find_type(idn) { + ast::FieldType::Symbol(_, idn, ..) => match db.find_type_by_str(idn) { Some(Either::Left(cls)) => { match cls .static_fields() .find(|f| f.name() == next_path_name.as_str()) { Some(field) => { - let t = field.r#type(); - validate_variable_path(db, variable, next_index + 1, t) + if let Some(t) = field.r#type() { + validate_variable_path(db, variable, next_index + 1, t) + } else { + match cls + .dynamic_fields() + .find(|f| f.name() == next_path_name.as_str()) + { + Some(_) => { + // Throw an error if the next path is not the last path. + if next_index + 1 < variable.path.len() { + Err(DatamodelError::new_validation_error( + "get properties must be the last path in the prompt", + variable.span.clone(), + )) + } else { + Ok(()) + } + } + None => Err(DatamodelError::new_validation_error( + &format!( + "Unknown field `{}` in class `{}`", + next_path_name, idn + ), + variable.span.clone(), + )), + } + } } None => match cls .dynamic_fields() @@ -227,40 +242,20 @@ fn validate_variable_path( } } None => Err(DatamodelError::new_validation_error( - &format!( - "Unknown field `{}` in class `{}`", - next_path_name, - idn.name() - ), + &format!("Unknown field `{}` in class `{}`", next_path_name, idn), variable.span.clone(), )), }, } } + Some(Either::Right(_)) => Err(DatamodelError::new_validation_error( "Enum values are not indexable in the prompt", variable.span.clone(), )), None => match idn { - ast::Identifier::Primitive(_p, _) => Err(DatamodelError::new_validation_error( - &format!( - "{0} has no field {1}. {0} is of type: {2}", - variable.path[..next_index].join("."), - next_path_name, - idn.name() - ), - variable.span.clone(), - )), - ast::Identifier::Ref(_, _) => Err(DatamodelError::new_validation_error( - "Namespace imports (using '.') are not yet supported.", - variable.span.clone(), - )), - ast::Identifier::ENV(_, _) => Err(DatamodelError::new_validation_error( - "Environment variables are not indexable in the prompt", - variable.span.clone(), - )), _ => Err(DatamodelError::new_validation_error( - &format!("Unknown type `{}`.", idn.name()), + &format!("Unknown type `{}`.", idn), variable.span.clone(), )), }, diff --git a/engine/baml-lib/parser-database/src/types/types.rs b/engine/baml-lib/parser-database/src/types/types.rs index c6bc23375..260e3791a 100644 --- a/engine/baml-lib/parser-database/src/types/types.rs +++ b/engine/baml-lib/parser-database/src/types/types.rs @@ -1,12 +1,12 @@ use std::collections::HashMap; -use internal_baml_schema_ast::ast::{EnumValueId, FieldId, SerializerFieldId, VariantSerializerId}; +use internal_baml_schema_ast::ast::FieldId; use super::to_string_attributes::ToStringAttributes; #[derive(Debug, Default)] pub struct EnumAttributes { - pub value_serilizers: HashMap, + pub value_serilizers: HashMap, pub serilizer: Option, } @@ -17,15 +17,3 @@ pub struct ClassAttributes { pub serilizer: Option, } - -#[derive(Debug, Default)] -pub struct SerializerAttributes { - pub field_serilizers: HashMap, - - pub serilizer: Option, -} - -#[derive(Debug, Default)] -pub(crate) struct VariantAttributes { - pub serializers: HashMap, -} diff --git a/engine/baml-lib/parser-database/src/walkers/class.rs b/engine/baml-lib/parser-database/src/walkers/class.rs index f7316e481..52a703204 100644 --- a/engine/baml-lib/parser-database/src/walkers/class.rs +++ b/engine/baml-lib/parser-database/src/walkers/class.rs @@ -1,30 +1,30 @@ use std::collections::HashSet; +use crate::{ + printer::{serialize_with_printer, WithSerializeableContent}, + types::ToStringAttributes, + ParserDatabase, WithSerialize, +}; use either::Either; use internal_baml_diagnostics::DatamodelError; +use internal_baml_schema_ast::ast::SubType; use internal_baml_schema_ast::ast::{self, WithIdentifier, WithName, WithSpan}; use serde_json::json; use std::collections::HashMap; -use crate::{ - printer::{serialize_with_printer, WithSerializeableContent, WithStaticRenames}, - types::ToStringAttributes, - ParserDatabase, WithSerialize, -}; - -use super::{field::FieldWalker, EnumWalker, VariantWalker}; +use super::{field::FieldWalker, EnumWalker}; /// A `class` declaration in the Prisma schema. -pub type ClassWalker<'db> = super::Walker<'db, ast::ClassId>; +pub type ClassWalker<'db> = super::Walker<'db, ast::TypeExpId>; impl<'db> ClassWalker<'db> { /// The ID of the class in the db - pub fn class_id(self) -> ast::ClassId { + pub fn class_id(self) -> ast::TypeExpId { self.id } /// The AST node. - pub fn ast_class(self) -> &'db ast::Class { + pub fn ast_class(self) -> &'db ast::TypeExpressionBlock { &self.db.ast[self.id] } @@ -90,10 +90,31 @@ impl<'db> ClassWalker<'db> { types.add_class( self.name(), self.static_fields() - .map(|f| (f.name().to_string(), self.db.to_jinja_type(f.r#type()))) + .filter_map(|f| { + f.r#type() + .as_ref() + .map(|field_type| (f.name().to_string(), self.db.to_jinja_type(field_type))) + }) .collect::>(), ) } + /// Getter for default attributes + pub fn get_default_attributes(&self, sub_type: SubType) -> Option<&'db ToStringAttributes> { + match sub_type { + SubType::Enum => self + .db + .types + .enum_attributes + .get(&self.id) + .and_then(|f| f.serilizer.as_ref()), + _ => self + .db + .types + .class_attributes + .get(&self.id) + .and_then(|f| f.serilizer.as_ref()), + } + } } impl<'db> WithIdentifier for ClassWalker<'db> { @@ -109,53 +130,25 @@ impl<'db> WithSpan for ClassWalker<'db> { } impl<'db> WithSerializeableContent for ClassWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value { json!({ "rtype": "class", "optional": false, - "name": self.alias(variant, db), - "meta": self.meta(variant, db), - "fields": self.static_fields().map(|f| f.serialize_data(variant, db)).collect::>(), + "name": self.name(), + "fields": self.static_fields().map(|f| f.serialize_data(db)).collect::>(), // Dynamic fields are not serialized. }) } } -impl<'db> WithStaticRenames<'db> for ClassWalker<'db> { - fn get_override(&self, variant: &VariantWalker<'db>) -> Option<&'db ToStringAttributes> { - variant.find_serializer_attributes(self.name()) - } - - fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { - self.db - .types - .class_attributes - .get(&self.id) - .and_then(|f| f.serilizer.as_ref()) - } -} - impl<'db> WithSerialize for ClassWalker<'db> { fn serialize( &self, db: &'_ ParserDatabase, - variant: Option<&VariantWalker<'_>>, - block: Option<&internal_baml_prompt_parser::ast::PrinterBlock>, span: &internal_baml_diagnostics::Span, ) -> Result { - let printer_template = match &block.and_then(|b| b.printer.as_ref()) { - Some((p, _)) => self - .db - .find_printer(p) - .map(|w| w.printer().template().to_string()), - _ => None, - }; // Eventually we should validate what parameters are in meta. - match serialize_with_printer(false, printer_template, self.serialize_data(variant, db)) { + match serialize_with_printer(false, self.serialize_data(db)) { Ok(val) => Ok(val), Err(e) => Err(DatamodelError::new_validation_error( &format!("Error serializing class: {}\n{}", self.name(), e), @@ -169,18 +162,16 @@ impl<'db> WithSerialize for ClassWalker<'db> { db: &'_ ParserDatabase, span: &internal_baml_diagnostics::Span, ) -> Result { - let class_schema = self.serialize(db, None, None, span)?; + let class_schema = self.serialize(db, span)?; let mut enum_schemas = self .required_enums() // TODO(sam) - if enum serialization fails, then we do not surface the error to the user. // That is bad!!!!!!! - .filter_map( - |e| match e.serialize(db, None, None, e.identifier().span()) { - Ok(enum_schema) => Some((e.name().to_string(), enum_schema)), - Err(_) => None, - }, - ) + .filter_map(|e| match e.serialize(db, e.identifier().span()) { + Ok(enum_schema) => Some((e.name().to_string(), enum_schema)), + Err(_) => None, + }) .collect::>(); // Enforce a stable order on enum schemas. Without this, the order is actually unstable, and the order can ping-pong // when the vscode ext re-renders the live preview diff --git a/engine/baml-lib/parser-database/src/walkers/client.rs b/engine/baml-lib/parser-database/src/walkers/client.rs index 850c49ae5..c977b8232 100644 --- a/engine/baml-lib/parser-database/src/walkers/client.rs +++ b/engine/baml-lib/parser-database/src/walkers/client.rs @@ -6,16 +6,16 @@ use crate::{ }; /// A `function` declaration in the Prisma schema. -pub type ClientWalker<'db> = super::Walker<'db, ast::ClientId>; +pub type ClientWalker<'db> = super::Walker<'db, ast::ValExpId>; impl<'db> ClientWalker<'db> { /// The ID of the function in the db - pub fn client_id(self) -> ast::ClientId { + pub fn client_id(self) -> ast::ValExpId { self.id } /// The AST node. - pub fn ast_client(self) -> &'db ast::Client { + pub fn ast_client(self) -> &'db ast::ValueExprBlock { &self.db.ast[self.id] } diff --git a/engine/baml-lib/parser-database/src/walkers/configuration.rs b/engine/baml-lib/parser-database/src/walkers/configuration.rs index cb4ffc640..4f885cb0b 100644 --- a/engine/baml-lib/parser-database/src/walkers/configuration.rs +++ b/engine/baml-lib/parser-database/src/walkers/configuration.rs @@ -1,13 +1,13 @@ use internal_baml_schema_ast::ast::{self, WithIdentifier, WithSpan}; -use crate::types::{PrinterType, RetryPolicy, TestCase}; +use crate::types::{RetryPolicy, TestCase}; /// A `class` declaration in the Prisma schema. -pub type ConfigurationWalker<'db> = super::Walker<'db, (ast::ConfigurationId, &'static str)>; +pub type ConfigurationWalker<'db> = super::Walker<'db, (ast::ValExpId, &'static str)>; impl ConfigurationWalker<'_> { /// Get the AST node for this class. - pub fn ast_node(&self) -> &ast::Configuration { + pub fn ast_node(&self) -> &ast::ValueExprBlock { &self.db.ast[self.id.0] } @@ -17,12 +17,6 @@ impl ConfigurationWalker<'_> { &self.db.types.retry_policies[&self.id.0] } - /// Get as a printer configuration. - pub fn printer(&self) -> &PrinterType { - assert!(self.id.1 == "printer"); - &self.db.types.printers[&self.id.0] - } - /// Get as a test case configuration. pub fn test_case(&self) -> &TestCase { assert!(self.id.1 == "test"); @@ -40,15 +34,6 @@ impl ConfigurationWalker<'_> { /// If adapters are not present we can stream pub fn is_streaming_supported(&self) -> bool { - let is_legacy = self.walk_functions().any(|f| { - f.is_old_function() - && f.walk_variants() - .any(|v| v.properties().output_adapter.is_some()) - }); - - if is_legacy { - return false; - } return true; } } diff --git a/engine/baml-lib/parser-database/src/walkers/enum.rs b/engine/baml-lib/parser-database/src/walkers/enum.rs index 82781bbe0..238ac8a86 100644 --- a/engine/baml-lib/parser-database/src/walkers/enum.rs +++ b/engine/baml-lib/parser-database/src/walkers/enum.rs @@ -1,35 +1,24 @@ -use internal_baml_diagnostics::DatamodelError; +use crate::{ast, types::ToStringAttributes, walkers::Walker}; -use internal_baml_schema_ast::ast::{WithDocumentation, WithIdentifier, WithName, WithSpan}; -use serde_json::json; - -use crate::{ - ast, - printer::{serialize_with_printer, WithSerialize, WithSerializeableContent, WithStaticRenames}, - types::ToStringAttributes, - walkers::Walker, - ParserDatabase, -}; - -use super::VariantWalker; +use internal_baml_schema_ast::ast::{WithDocumentation, WithName, WithSpan}; /// An `enum` declaration in the schema. -pub type EnumWalker<'db> = Walker<'db, ast::EnumId>; +pub type EnumWalker<'db> = Walker<'db, ast::TypeExpId>; /// One value in an `enum` declaration in the schema. -pub type EnumValueWalker<'db> = Walker<'db, (ast::EnumId, ast::EnumValueId)>; +pub type EnumValueWalker<'db> = Walker<'db, (ast::TypeExpId, ast::FieldId)>; impl<'db> EnumWalker<'db> { /// The name of the enum. /// The AST node. - pub fn ast_enum(self) -> &'db ast::Enum { + pub fn ast_enum(self) -> &'db ast::TypeExpressionBlock { &self.db.ast()[self.id] } /// The values of the enum. pub fn values(self) -> impl ExactSizeIterator> { self.ast_enum() - .iter_values() + .iter_fields() .filter_map(move |(valid_id, _)| { self.db .types @@ -44,94 +33,18 @@ impl<'db> EnumWalker<'db> { /// Find a value by name. pub fn find_value(&self, name: &str) -> Option> { self.ast_enum() - .values + .fields .iter() .enumerate() .find_map(|(idx, v)| { if v.name() == name { - Some(self.walk((self.id, ast::EnumValueId(idx as u32)))) + Some(self.walk((self.id, ast::FieldId(idx as u32)))) } else { None } }) } } - -impl<'db> WithIdentifier for EnumWalker<'db> { - fn identifier(&self) -> &ast::Identifier { - self.ast_enum().identifier() - } -} - -impl<'db> WithSpan for EnumWalker<'db> { - fn span(&self) -> &internal_baml_diagnostics::Span { - &self.ast_enum().span - } -} - -impl<'db> WithSerializeableContent for EnumWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { - json!({ - "name": self.alias(variant, db), - "meta": self.meta(variant, db), - "values": self.values().filter(|f| !f.skip(variant)).map(|f| f.serialize_data(variant, db)).collect::>(), - }) - } -} - -impl<'db> WithStaticRenames<'db> for EnumWalker<'db> { - fn get_override(&self, variant: &VariantWalker<'db>) -> Option<&'db ToStringAttributes> { - variant.find_serializer_attributes(self.name()) - } - - fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { - self.db - .types - .enum_attributes - .get(&self.id) - .and_then(|f| f.serilizer.as_ref()) - } -} - -impl<'db> WithSerialize for EnumWalker<'db> { - fn serialize( - &self, - db: &'_ ParserDatabase, - variant: Option<&VariantWalker<'_>>, - block: Option<&internal_baml_prompt_parser::ast::PrinterBlock>, - span: &internal_baml_diagnostics::Span, - ) -> Result { - let printer_template = match block.and_then(|b| b.printer.as_ref()) { - Some((p, _)) => self - .db - .find_printer(p) - .map(|w| w.printer().template().to_string()), - _ => None, - }; - // let printer = self.db.find_printer(&block.printer); - // Eventually we should validate what parameters are in meta. - match serialize_with_printer(true, printer_template, self.serialize_data(variant, db)) { - Ok(val) => Ok(val), - Err(e) => Err(DatamodelError::new_validation_error( - &format!("Error serializing enum: {}\n{}", self.name(), e), - span.clone(), - )), - } - } - - fn output_format( - &self, - db: &'_ ParserDatabase, - span: &internal_baml_diagnostics::Span, - ) -> Result { - self.serialize(db, None, None, span) - } -} - impl<'db> EnumValueWalker<'db> { fn r#enum(self) -> EnumWalker<'db> { self.walk(self.id.0) @@ -141,11 +54,23 @@ impl<'db> EnumValueWalker<'db> { pub fn documentation(self) -> Option<&'db str> { self.r#enum().ast_enum()[self.id.1].documentation() } + + /// The enum value attributes. + pub fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { + let result = self + .db + .types + .enum_attributes + .get(&self.id.0) + .and_then(|f| f.value_serilizers.get(&self.id.1)); + + result + } } impl<'db> WithSpan for EnumValueWalker<'db> { fn span(&self) -> &internal_baml_diagnostics::Span { - &self.r#enum().ast_enum()[self.id.1].span + &self.r#enum().ast_enum()[self.id.1].span() } } @@ -154,31 +79,3 @@ impl<'db> WithName for EnumValueWalker<'db> { self.r#enum().ast_enum()[self.id.1].name() } } - -impl<'db> WithSerializeableContent for EnumValueWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { - json!({ - "name": self.alias(variant, db), - "meta": self.meta(variant, db), - "skip": self.skip(variant), - }) - } -} - -impl<'db> WithStaticRenames<'db> for EnumValueWalker<'db> { - fn get_override(&self, variant: &VariantWalker<'db>) -> Option<&'db ToStringAttributes> { - variant.find_serializer_field_attributes(self.r#enum().name(), self.name()) - } - - fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { - self.db - .types - .enum_attributes - .get(&self.id.0) - .and_then(|f| f.value_serilizers.get(&self.id.1)) - } -} diff --git a/engine/baml-lib/parser-database/src/walkers/field.rs b/engine/baml-lib/parser-database/src/walkers/field.rs index 0a65abb03..e90a1e319 100644 --- a/engine/baml-lib/parser-database/src/walkers/field.rs +++ b/engine/baml-lib/parser-database/src/walkers/field.rs @@ -1,28 +1,28 @@ use std::ops::Deref; use crate::{ - printer::{WithSerializeableContent, WithStaticRenames}, + printer::WithSerializeableContent, types::{DynamicStringAttributes, StaticStringAttributes, ToStringAttributes}, ParserDatabase, }; -use super::{ClassWalker, VariantWalker, Walker}; +use super::{ClassWalker, Walker}; use internal_baml_schema_ast::ast::{self, FieldType, Identifier, WithName, WithSpan}; use serde_json::json; /// A model field, scalar or relation. -pub type FieldWalker<'db> = Walker<'db, (ast::ClassId, ast::FieldId, bool)>; +pub type FieldWalker<'db> = Walker<'db, (ast::TypeExpId, ast::FieldId, bool)>; impl<'db> FieldWalker<'db> { /// The AST node for the field. - pub fn ast_field(self) -> &'db ast::Field { + pub fn ast_field(self) -> &'db ast::Field { &self.db.ast[self.id.0][self.id.1] } /// The field type. - pub fn r#type(self) -> &'db FieldType { - &self.ast_field().field_type + pub fn r#type(self) -> &'db Option { + &self.ast_field().expr } /// Traverse the field's parent model. @@ -67,6 +67,20 @@ impl<'db> FieldWalker<'db> { None => None, } } + + /// The field's default attributes. + pub fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { + println!("Field is triggered"); + + let result = self + .db + .types + .class_attributes + .get(&self.id.0) + .and_then(|f| f.field_serilizers.get(&self.id.1)); + println!("Result: {:?}", result); + result + } } impl<'db> WithName for FieldWalker<'db> { @@ -83,93 +97,67 @@ impl<'db> WithSpan for FieldWalker<'db> { } impl<'db> WithSerializeableContent for (&ParserDatabase, &FieldType) { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value { match self.1 { FieldType::Tuple(..) | FieldType::Map(..) => json!({ "rtype": "unsupported", "optional": false, }), - FieldType::Union(arity, fts, _) => json!({ + FieldType::Union(arity, fts, ..) => json!({ "rtype": "union", "optional": arity.is_optional(), - "options": fts.iter().map(|ft| (self.0, ft).serialize_data(variant, db)).collect::>(), + "options": fts.iter().map(|ft| (self.0, ft).serialize_data( db)).collect::>(), }), - FieldType::List(ft, dims, _) => json!({ + FieldType::List(ft, dims, ..) => json!({ "rtype": "list", "dims": dims, - "inner": (self.0, ft.deref()).serialize_data(variant, db), + "inner": (self.0, ft.deref()).serialize_data( db), + }), + FieldType::Primitive(arity, t, ..) => json!({ + "rtype": match t.to_string().as_str() { + "string" => "string", + "int" => "int", + "float" => "float", + "bool" => "bool", + _ => "unknown", + }, + "optional": arity.is_optional(), }), - FieldType::Identifier(arity, Identifier::Primitive(name, ..)) => { - json!({ - "rtype": "primitive", - "optional": arity.is_optional(), - "value": match name { - baml_types::TypeValue::Bool => "bool", - baml_types::TypeValue::Int => "int", - baml_types::TypeValue::Float => "float", - baml_types::TypeValue::String => "string", - baml_types::TypeValue::Null => "null", - baml_types::TypeValue::Image => "image", - baml_types::TypeValue::Audio => "audio", - } - }) - } - FieldType::Identifier(arity, Identifier::Local(name, ..)) => { - match self.0.find_type_by_str(name) { - Some(either::Either::Left(cls)) => { - let mut class_type = cls.serialize_data(variant, db); - let Some(obj) = class_type.as_object_mut() else { - return class_type; - }; - obj.insert("optional".to_string(), arity.is_optional().into()); - class_type - } - Some(either::Either::Right(enm)) => { - json!({ - "rtype": "enum", - "optional": arity.is_optional(), - "name": enm.alias(variant, db), - }) - } - None => json!({ - "rtype": "unsupported", - "optional": false, - }), + FieldType::Symbol(arity, name, ..) => match self.0.find_type_by_str(name) { + Some(either::Either::Left(cls)) => { + let mut class_type = cls.serialize_data(db); + let Some(obj) = class_type.as_object_mut() else { + return class_type; + }; + obj.insert("optional".to_string(), arity.is_optional().into()); + class_type + } + Some(either::Either::Right(enm)) => { + json!({ + "rtype": "enum", + "optional": arity.is_optional(), + "name": enm.name(), + }) } - } - FieldType::Identifier(..) => serde_json::Value::Null, + None => json!({ + "rtype": "unsupported", + "optional": false, + }), + }, } } } impl<'db> WithSerializeableContent for FieldWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value { + let type_meta = match self.r#type() { + Some(field_type) => (self.db, field_type).serialize_data(db), + None => json!(null), + }; + json!({ - "name": self.alias(variant, db), - "meta": self.meta(variant, db), - "type_meta": (self.db, self.r#type()).serialize_data(variant, db), + "name": self.name(), + "type_meta": type_meta, }) } } - -impl<'db> WithStaticRenames<'db> for FieldWalker<'db> { - fn get_override(&self, variant: &VariantWalker<'db>) -> Option<&'db ToStringAttributes> { - variant.find_serializer_field_attributes(self.model().name(), self.name()) - } - - fn get_default_attributes(&self) -> Option<&'db ToStringAttributes> { - self.db - .types - .class_attributes - .get(&self.id.0) - .and_then(|f| f.field_serilizers.get(&self.id.1)) - } -} diff --git a/engine/baml-lib/parser-database/src/walkers/function.rs b/engine/baml-lib/parser-database/src/walkers/function.rs index 7c409c420..b242720a0 100644 --- a/engine/baml-lib/parser-database/src/walkers/function.rs +++ b/engine/baml-lib/parser-database/src/walkers/function.rs @@ -1,6 +1,6 @@ use either::Either; use internal_baml_diagnostics::DatamodelError; -use internal_baml_schema_ast::ast::{FuncArguementId, Identifier, WithIdentifier, WithSpan}; +use internal_baml_schema_ast::ast::{ArgumentId, Identifier, WithIdentifier, WithSpan}; use serde_json::json; use crate::{ @@ -10,12 +10,12 @@ use crate::{ ParserDatabase, WithSerialize, }; -use super::{ClassWalker, ClientWalker, ConfigurationWalker, EnumWalker, VariantWalker, Walker}; +use super::{ClassWalker, ClientWalker, ConfigurationWalker, EnumWalker, Walker}; use std::{collections::HashMap, iter::ExactSizeIterator}; /// A `function` declaration in the Prisma schema. -pub type FunctionWalker<'db> = Walker<'db, (bool, ast::FunctionId)>; +pub type FunctionWalker<'db> = Walker<'db, (bool, ast::ValExpId)>; impl<'db> FunctionWalker<'db> { /// The name of the function. @@ -29,103 +29,68 @@ impl<'db> FunctionWalker<'db> { } /// The ID of the function in the db - pub fn function_id(self) -> ast::FunctionId { + pub fn function_id(self) -> ast::ValExpId { self.id.1 } /// The AST node. - pub fn ast_function(self) -> &'db ast::Function { + pub fn ast_function(self) -> &'db ast::ValueExprBlock { &self.db.ast[self.id.1] } /// The name of the function. pub fn is_positional_args(self) -> bool { - match self.ast_function().input() { - ast::FunctionArgs::Named(_) => false, - ast::FunctionArgs::Unnamed(_) => true, - } + false } /// Arguments of the function. pub fn find_input_arg_by_name(self, name: &str) -> Option> { - match self.ast_function().input() { - ast::FunctionArgs::Named(arg_list) => { - arg_list.iter_args().find_map(|(idx, (idn, _))| { - if idn.name() == name { - Some(ArgWalker { - db: self.db, - id: (self.id.1, true, idx), - }) - } else { - None - } - }) - } - ast::FunctionArgs::Unnamed(_) => None, - } - } - - /// Arguments of the function. - pub fn find_input_arg_by_position(self, position: u32) -> Option> { - match self.ast_function().input() { - ast::FunctionArgs::Named(_) => None, - ast::FunctionArgs::Unnamed(_) => { - if position == 0_u32 { + self.ast_function().input().and_then(|args| { + args.iter_args().find_map(|(idx, (idn, _))| { + if idn.name() == name { Some(ArgWalker { db: self.db, - id: (self.id.1, true, FuncArguementId(position)), + id: (self.id.1, true, idx), }) } else { None } - } - } + }) + }) + } + + /// Arguments of the function. + pub fn find_input_arg_by_position(self, position: u32) -> Option> { + None } /// Iterates over the input arguments of the function. pub fn walk_input_args(self) -> impl ExactSizeIterator> { - let range_end = match self.ast_function().input() { - ast::FunctionArgs::Named(arg_list) => arg_list.iter_args().len(), - ast::FunctionArgs::Unnamed(_) => 1, - } as u32; - - (0..range_end).map(move |f| ArgWalker { - db: self.db, - id: (self.id.1, true, FuncArguementId(f)), - }) + match self.ast_function().input() { + Some(input) => { + let range_end = input.iter_args().len() as u32; + (0..range_end) + .map(move |f| ArgWalker { + db: self.db, + id: (self.id.1, true, ArgumentId(f)), + }) + .collect::>() + .into_iter() + } + None => Vec::new().into_iter(), + } } /// Iterates over the output arguments of the function. pub fn walk_output_args(self) -> impl ExactSizeIterator> { - let range_end = match self.ast_function().output() { - ast::FunctionArgs::Named(arg_list) => arg_list.iter_args().len(), - ast::FunctionArgs::Unnamed(_) => 1, - } as u32; + let range_end = 1; (0..range_end).map(move |f| ArgWalker { db: self.db, - id: (self.id.1, false, FuncArguementId(f)), + id: (self.id.1, false, ArgumentId(f)), }) } - /// Iterates over the variants for this function. - pub fn walk_variants(self) -> impl ExactSizeIterator> { - assert!(!self.id.0, "Only old functions have variants"); - self.db - .ast() - .iter_tops() - .filter_map(|(id, t)| match (id, t) { - (ast::TopId::Variant(id), ast::Top::Variant(impl_)) - if impl_.function_name().name() == self.name() => - { - Some(VariantWalker { db: self.db, id }) - } - _ => None, - }) - .collect::>() - .into_iter() - } - /// All the test cases for this function. pub fn walk_tests(self) -> impl ExactSizeIterator> { let mut tests = self @@ -163,36 +128,39 @@ impl<'db> FunctionWalker<'db> { pub fn client(self) -> Option> { assert!(self.id.0, "Only new functions have clients"); let client = self.metadata().client.as_ref()?; + self.db.find_client(client.0.as_str()) } } /// A `function` declaration in the Prisma schema. -pub type ArgWalker<'db> = super::Walker<'db, (ast::FunctionId, bool, FuncArguementId)>; +pub type ArgWalker<'db> = super::Walker<'db, (ast::ValExpId, bool, ArgumentId)>; impl<'db> ArgWalker<'db> { /// The ID of the function in the db - pub fn function_id(self) -> ast::FunctionId { + pub fn function_id(self) -> ast::ValExpId { self.id.0 } /// The AST node. - pub fn ast_function(self) -> &'db ast::Function { + pub fn ast_function(self) -> &'db ast::ValueExprBlock { &self.db.ast[self.id.0] } /// The AST node. - pub fn ast_arg(self) -> (Option<&'db Identifier>, &'db ast::FunctionArg) { - let args = match self.id.1 { - true => self.ast_function().input(), - false => self.ast_function().output(), - }; - match args { - ast::FunctionArgs::Named(arg_list) => { - let res = &arg_list[self.id.2]; + pub fn ast_arg(self) -> (Option<&'db Identifier>, &'db ast::BlockArg) { + match self.id.1 { + true => { + let args = self.ast_function().input(); + let res = &args.expect("Expected input args")[self.id.2]; (Some(&res.0), &res.1) } - ast::FunctionArgs::Unnamed(arg) => (None, arg), + + false => { + let output = self.ast_function().output(); + let res = output.expect("Error: Output is undefined for function ID"); + (None, res) + } } } @@ -237,45 +205,28 @@ impl WithSpan for FunctionWalker<'_> { } } -impl WithIdentifier for ArgWalker<'_> { - fn identifier(&self) -> &ast::Identifier { - self.ast_arg().0.unwrap() - } -} +// impl WithIdentifier for ArgWalker<'_> { +// fn identifier(&self) -> &ast::Identifier { +// self.ast_arg().0.unwrap() +// } +// } impl<'db> WithSerializeableContent for ArgWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value { json!({ "rtype": "inline", - "value": (self.db, &self.ast_arg().1.field_type).serialize_data(variant, db) + "value": (self.db, &self.ast_arg().1.field_type).serialize_data( db) }) } } impl<'db> WithSerializeableContent for FunctionWalker<'db> { - fn serialize_data( - &self, - variant: Option<&VariantWalker<'_>>, - db: &'_ ParserDatabase, - ) -> serde_json::Value { - if let Some((idx, _)) = variant.and_then(|v| v.properties().output_adapter.as_ref()) { - let adapter = &variant.unwrap().ast_variant()[*idx]; - - return json!({ - "rtype": "output", - "value": (self.db, &adapter.from).serialize_data(variant, db) - }); - } - + fn serialize_data(&self, db: &'_ ParserDatabase) -> serde_json::Value { // TODO: We should handle the case of multiple output args json!({ "rtype": "output", "value": self.walk_output_args() - .map(|f| f.serialize_data(variant, db)) + .map(|f| f.serialize_data(db)) .next() .unwrap_or(serde_json::Value::Null) }) @@ -286,19 +237,10 @@ impl<'db> WithSerialize for FunctionWalker<'db> { fn serialize( &self, db: &'_ ParserDatabase, - variant: Option<&VariantWalker<'_>>, - block: Option<&internal_baml_prompt_parser::ast::PrinterBlock>, span: &internal_baml_diagnostics::Span, ) -> Result { - let printer_template = match &block.and_then(|b| b.printer.as_ref()) { - Some((p, _)) => self - .db - .find_printer(p) - .map(|w| w.printer().template().to_string()), - _ => None, - }; // Eventually we should validate what parameters are in meta. - match serialize_with_printer(false, printer_template, self.serialize_data(variant, db)) { + match serialize_with_printer(false, self.serialize_data(db)) { Ok(val) => Ok(val), Err(e) => Err(DatamodelError::new_validation_error( &format!("Error serializing output for {}\n{}", self.name(), e), @@ -312,7 +254,7 @@ impl<'db> WithSerialize for FunctionWalker<'db> { db: &'_ ParserDatabase, span: &internal_baml_diagnostics::Span, ) -> Result { - let class_schema = self.serialize(db, None, None, span)?; + let class_schema = self.serialize(db, span)?; let mut enum_schemas = self .walk_output_args() @@ -322,12 +264,10 @@ impl<'db> WithSerialize for FunctionWalker<'db> { .iter() // TODO(sam) - if enum serialization fails, then we do not surface the error to the user. // That is bad!!!!!!! - .filter_map( - |(_, e)| match e.serialize(db, None, None, e.identifier().span()) { - Ok(enum_schema) => Some((e.name().to_string(), enum_schema)), - Err(_) => None, - }, - ) + .filter_map(|(_, e)| match e.serialize(db, e.identifier().span()) { + Ok(enum_schema) => Some((e.name().to_string(), enum_schema)), + Err(_) => None, + }) .collect::>(); if enum_schemas.is_empty() { diff --git a/engine/baml-lib/parser-database/src/walkers/mod.rs b/engine/baml-lib/parser-database/src/walkers/mod.rs index 36c89ed05..a132b83b9 100644 --- a/engine/baml-lib/parser-database/src/walkers/mod.rs +++ b/engine/baml-lib/parser-database/src/walkers/mod.rs @@ -13,7 +13,6 @@ mod r#enum; mod field; mod function; mod template_string; -mod variants; pub use client::*; pub use configuration::*; @@ -23,7 +22,6 @@ pub use function::*; use internal_baml_schema_ast::ast::{self, FieldType, Identifier, TopId, WithName}; pub use r#class::*; pub use r#enum::*; -pub use variants::*; pub use self::template_string::TemplateStringWalker; @@ -112,13 +110,13 @@ impl<'db> crate::ParserDatabase { /// Find a function by name. pub fn find_function_by_name(&'db self, name: &str) -> Option> { - self.find_top_by_str(name).and_then(|top_id| { - match (top_id.as_old_function_id(), top_id.as_new_function_id()) { - (Some(model_id), _) => Some(self.walk((false, model_id))), - (_, Some(model_id)) => Some(self.walk((true, model_id))), - _ => None, - } - }) + self.find_top_by_str(name) + .and_then(|top_id| { + top_id + .as_function_id() + .map(|function_id| (true, function_id)) + }) + .map(|function_id| self.walk(function_id)) } /// Find a function by name. @@ -130,15 +128,6 @@ impl<'db> crate::ParserDatabase { .map(|model_id| self.walk((model_id, "retry_policy"))) } - /// Find printer by name. - pub fn find_printer(&'db self, name: &str) -> Option> { - self.interner - .lookup(name) - .and_then(|name_id| self.names.tops.get(&name_id)) - .and_then(|top_id| top_id.as_printer_id()) - .map(|model_id| self.walk((model_id, "printer"))) - } - /// Traverse a schema element by id. pub fn walk(&self, id: I) -> Walker<'_, I> { Walker { db: self, id } @@ -159,11 +148,9 @@ impl<'db> crate::ParserDatabase { /// Get all the types that are valid in the schema. (including primitives) pub fn valid_function_names(&self) -> Vec { - let oldfns = self.walk_old_functions().map(|c| c.name().to_string()); - - let newfns = self.walk_new_functions().map(|c| c.name().to_string()); - - oldfns.chain(newfns).collect() + self.walk_functions() + .map(|c| c.name().to_string()) + .collect::>() } /// Get all the types that are valid in the schema. (including primitives) @@ -173,11 +160,6 @@ impl<'db> crate::ParserDatabase { .collect() } - /// Get all the types that are valid in the schema. (including primitives) - pub fn valid_printer_names(&self) -> Vec { - self.walk_printers().map(|c| c.name().to_string()).collect() - } - /// Get all the types that are valid in the schema. (including primitives) pub fn valid_client_names(&self) -> Vec { self.walk_clients().map(|c| c.name().to_string()).collect() @@ -217,25 +199,10 @@ impl<'db> crate::ParserDatabase { } /// Walk all classes in the schema. - pub fn walk_old_functions(&self) -> impl Iterator> { - self.ast() - .iter_tops() - .filter_map(|(top_id, _)| { - top_id - .as_old_function_id() - .map(|model_id| (false, model_id)) - }) - .map(move |top_id| Walker { - db: self, - id: top_id, - }) - } - - /// Walk all classes in the schema. - pub fn walk_new_functions(&self) -> impl Iterator> { + pub fn walk_functions(&self) -> impl Iterator> { self.ast() .iter_tops() - .filter_map(|(top_id, _)| top_id.as_new_function_id().map(|model_id| (true, model_id))) + .filter_map(|(top_id, _)| top_id.as_function_id().map(|model_id| (true, model_id))) .map(move |top_id| Walker { db: self, id: top_id, @@ -253,17 +220,6 @@ impl<'db> crate::ParserDatabase { }) } - /// Walk all variants in the schema. - pub fn walk_variants(&self) -> impl Iterator> { - self.ast() - .iter_tops() - .filter_map(|(top_id, _)| top_id.as_variant_id()) - .map(move |top_id| Walker { - db: self, - id: top_id, - }) - } - /// Walk all classes in the schema. pub fn walk_retry_policies(&self) -> impl Iterator> { self.ast() @@ -275,17 +231,6 @@ impl<'db> crate::ParserDatabase { }) } - /// Walk all classes in the schema. - pub fn walk_printers(&self) -> impl Iterator> { - self.ast() - .iter_tops() - .filter_map(|(top_id, _)| top_id.as_printer_id()) - .map(move |top_id| Walker { - db: self, - id: (top_id, "printer"), - }) - } - /// Walk all classes in the schema. pub fn walk_test_cases(&self) -> impl Iterator> { self.ast() @@ -301,62 +246,49 @@ impl<'db> crate::ParserDatabase { pub fn to_jinja_type(&self, ft: &FieldType) -> internal_baml_jinja::Type { use internal_baml_jinja::Type; match ft { - FieldType::Identifier(arity, idn) => { - let t = match idn { - ast::Identifier::ENV(_, _) => Type::String, - ast::Identifier::Ref(x, _) => match self.find_type(idn) { - None => Type::Undefined, - Some(Either::Left(_)) => Type::ClassRef(x.full_name.clone()), - Some(Either::Right(_)) => Type::String, - }, - ast::Identifier::Local(x, _) => match self.find_type(idn) { - None => Type::Undefined, - Some(Either::Left(_)) => Type::ClassRef(x.clone()), - Some(Either::Right(_)) => Type::String, - }, - ast::Identifier::Primitive(idx, _) => match idx { - baml_types::TypeValue::String => Type::String, - baml_types::TypeValue::Int => Type::Int, - baml_types::TypeValue::Float => Type::Float, - baml_types::TypeValue::Bool => Type::Bool, - baml_types::TypeValue::Null => Type::None, - baml_types::TypeValue::Image => Type::Image, - baml_types::TypeValue::Audio => Type::Audio, - }, - ast::Identifier::String(_, _) => Type::String, - ast::Identifier::Invalid(_, _) => Type::Unknown, - }; - if arity.is_optional() { - Type::None | t - } else { - t - } - } - FieldType::List(inner, dims, _) => { + FieldType::Symbol(arity, idn, ..) => match self.find_type_by_str(idn) { + None => Type::Undefined, + Some(Either::Left(_)) => Type::ClassRef(idn.to_string()), + Some(Either::Right(_)) => Type::String, + }, + FieldType::List(inner, dims, ..) => { let mut t = self.to_jinja_type(inner); for _ in 0..*dims { t = Type::List(Box::new(t)); } t } - FieldType::Tuple(arity, c, _) => { + FieldType::Tuple(arity, c, ..) => { let mut t = Type::Tuple(c.iter().map(|e| self.to_jinja_type(e)).collect()); if arity.is_optional() { t = Type::None | t; } t } - FieldType::Union(arity, options, _) => { + FieldType::Union(arity, options, ..) => { let mut t = Type::Union(options.iter().map(|e| self.to_jinja_type(e)).collect()); if arity.is_optional() { t = Type::None | t; } t } - FieldType::Map(kv, _) => Type::Map( + FieldType::Map(kv, ..) => Type::Map( Box::new(self.to_jinja_type(&kv.0)), Box::new(self.to_jinja_type(&kv.1)), ), + FieldType::Primitive(arity, t, ..) => { + let mut t = match t.to_string().as_str() { + "string" => Type::String, + "int" => Type::Int, + "float" => Type::Float, + "bool" => Type::Bool, + _ => Type::Unknown, + }; + if arity.is_optional() { + t = Type::None | t; + } + t + } } } } diff --git a/engine/baml-lib/parser-database/src/walkers/template_string.rs b/engine/baml-lib/parser-database/src/walkers/template_string.rs index c2cb215c4..9652995de 100644 --- a/engine/baml-lib/parser-database/src/walkers/template_string.rs +++ b/engine/baml-lib/parser-database/src/walkers/template_string.rs @@ -1,6 +1,6 @@ use either::Either; use internal_baml_jinja::{PredefinedTypes, Type}; -use internal_baml_schema_ast::ast::{self, FunctionArgs, Span, WithIdentifier, WithName, WithSpan}; +use internal_baml_schema_ast::ast::{self, BlockArgs, Span, WithIdentifier, WithName, WithSpan}; use crate::types::TemplateStringProperties; @@ -35,7 +35,7 @@ impl<'db> TemplateStringWalker<'db> { let ret_type = Type::String; let mut params = vec![]; - if let Some(FunctionArgs::Named(p)) = self.ast_node().input() { + if let Some(p) = self.ast_node().input() { p.args.iter().for_each(|(name, t)| { params.push(( name.name().to_string(), diff --git a/engine/baml-lib/parser-database/src/walkers/variants.rs b/engine/baml-lib/parser-database/src/walkers/variants.rs deleted file mode 100644 index fe172809f..000000000 --- a/engine/baml-lib/parser-database/src/walkers/variants.rs +++ /dev/null @@ -1,149 +0,0 @@ -use internal_baml_schema_ast::ast::{Identifier, WithName, WithSpan}; - -use crate::{ - ast::{self, WithIdentifier}, - types::{PromptAst, ToStringAttributes, VariantProperties}, -}; - -use super::{ClassWalker, ClientWalker, EnumWalker, FunctionWalker, Walker}; - -/// A `function` declaration in the Prisma schema. -pub type VariantWalker<'db> = Walker<'db, ast::VariantConfigId>; - -impl<'db> VariantWalker<'db> { - /// The name of the function. - pub fn function_identifier(self) -> &'db Identifier { - self.ast_variant().function_name() - } - - /// The ID of the function in the db - pub fn variant_id(self) -> ast::VariantConfigId { - self.id - } - - /// Helper to access every client. - pub fn client(self) -> Option> { - self.db - .types - .variant_properties - .get(&self.id) - .and_then(|f| self.db.find_client(&f.client.value)) - } - - /// The function node. - pub fn walk_function(self) -> Option> { - self.db.find_function(self.function_identifier()) - } - - /// The AST node. - pub fn ast_variant(self) -> &'db ast::Variant { - &self.db.ast[self.id] - } - - /// Finds a serializer by name - pub fn find_serializer_attributes(self, name: &str) -> Option<&'db ToStringAttributes> { - self.ast_variant() - .iter_serializers() - .find(|(_, s)| s.name() == name) - .and_then(|(idx, _s)| { - self.db.types.variant_attributes[&self.id] - .serializers - .get(&idx) - .and_then(|f| f.serilizer.as_ref()) - }) - } - - /// Finds a serializer for a field by name - pub fn find_serializer_field_attributes( - self, - name: &str, - field_name: &str, - ) -> Option<&'db ToStringAttributes> { - self.ast_variant() - .iter_serializers() - .find(|(_, s)| s.name() == name) - .and_then(|(idx, s)| { - let fid = s.field_id_for(field_name); - - if let Some(fid) = fid { - self.db.types.variant_attributes[&self.id] - .serializers - .get(&idx) - .and_then(|s| s.field_serilizers.get(&fid)) - } else { - None - } - }) - } - - /// The properties of the variant. - pub fn properties(self) -> &'db VariantProperties { - &self.db.types.variant_properties[&self.id] - } - - /// The prompt representation. - pub fn to_prompt(&self) -> PromptAst<'_> { - self.properties().to_prompt() - } - - /// Get the output of a function. - pub fn output_type(self) -> impl ExactSizeIterator> { - self.walk_function().unwrap().walk_output_args() - } - - /// The name of the function. - pub fn output_required_enums(self) -> impl Iterator> { - if let Some((idx, _)) = self.properties().output_adapter { - let adapter = &self.ast_variant()[idx]; - - return adapter - .from - .flat_idns() - .iter() - .filter_map(|f| self.db.find_enum(f)) - .collect::>() - .into_iter(); - } - - self.walk_function() - .unwrap() - .walk_output_args() - .flat_map(|f| f.required_enums()) - .collect::>() - .into_iter() - } - - /// The name of the function. - pub fn output_required_classes(self) -> impl Iterator> { - if let Some((idx, _)) = self.properties().output_adapter { - let adapter = &self.ast_variant()[idx]; - - return adapter - .from - .flat_idns() - .iter() - .filter_map(|f| self.db.find_class(f)) - .collect::>() - .into_iter(); - } - - self.walk_function() - .unwrap() - .walk_output_args() - .flat_map(|f| f.required_classes()) - .collect::>() - .into_iter() - } -} - -impl<'db> WithIdentifier for VariantWalker<'db> { - fn identifier(&self) -> &'db Identifier { - self.ast_variant().identifier() - } -} - -impl<'db> WithSpan for VariantWalker<'db> { - fn span(&self) -> &internal_baml_diagnostics::Span { - self.ast_variant().span() - } -} diff --git a/engine/baml-lib/schema-ast/Cargo.toml b/engine/baml-lib/schema-ast/Cargo.toml index 42459f431..4b2488b85 100644 --- a/engine/baml-lib/schema-ast/Cargo.toml +++ b/engine/baml-lib/schema-ast/Cargo.toml @@ -17,6 +17,7 @@ serde.workspace = true pest = "2.1.3" pest_derive = "2.1.0" either = "1.8.1" +test-log = "0.2.16" [features] diff --git a/engine/baml-lib/schema-ast/src/ast.rs b/engine/baml-lib/schema-ast/src/ast.rs index 12f091288..df322df8f 100644 --- a/engine/baml-lib/schema-ast/src/ast.rs +++ b/engine/baml-lib/schema-ast/src/ast.rs @@ -1,55 +1,38 @@ -mod adapter; mod argument; mod attribute; -mod r#class; -mod client; + mod comment; mod config; -mod configurations; -mod r#enum; + mod expression; mod field; -mod find_at_position; -mod function; -mod generator_config; + mod identifier; mod indentation_type; mod newline_type; -mod printer_config; -mod retry_policy_config; -mod serializer; + mod template_string; mod top; mod traits; -mod variant; - +mod type_expression_block; +mod value_expression_block; pub(crate) use self::comment::Comment; -pub use adapter::Adapter; pub use argument::{ArguementId, Argument, ArgumentsList}; pub use attribute::{Attribute, AttributeContainer, AttributeId}; -pub use client::Client; pub use config::ConfigBlockProperty; -pub use configurations::Configuration; pub use expression::{Expression, RawString}; pub use field::{Field, FieldArity, FieldType}; -pub use find_at_position::*; -pub use function::{FuncArguementId, Function, FunctionArg, FunctionArgs, NamedFunctionArgList}; -pub use generator_config::GeneratorConfig; pub use identifier::{Identifier, RefIdentifier}; pub use indentation_type::IndentationType; pub use internal_baml_diagnostics::Span; pub use newline_type::NewlineType; -pub use printer_config::PrinterConfig; -pub use r#class::{Class, FieldId}; -pub use r#enum::{Enum, EnumValue, EnumValueId}; -pub use retry_policy_config::RetryPolicyConfig; -pub use serializer::{Serializer, SerializerField, SerializerFieldId}; pub use template_string::TemplateString; pub use top::Top; pub use traits::{WithAttributes, WithDocumentation, WithIdentifier, WithName, WithSpan}; -pub use variant::{ - AdapterId, FieldId as VariantFieldId, SerializerId as VariantSerializerId, Variant, +pub use type_expression_block::{FieldId, SubType, TypeExpressionBlock}; +pub use value_expression_block::{ + ArgumentId, BlockArg, BlockArgs, ValueExprBlock, ValueExprBlockType, }; /// AST representation of a prisma schema. @@ -87,85 +70,42 @@ impl SchemaAst { } /// Iterate over all the generator blocks in the schema. - pub fn generators(&self) -> impl Iterator { - self.tops.iter().filter_map(|top| top.as_generator()) + pub fn generators(&self) -> impl Iterator { + self.tops.iter().filter_map(|top| { + if let Top::Generator(gen) = top { + Some(gen) + } else { + None + } + }) } } /// An opaque identifier for an enum in a schema AST. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumId(u32); -impl std::ops::Index for SchemaAst { - type Output = Enum; - - fn index(&self, index: EnumId) -> &Self::Output { - self.tops[index.0 as usize].as_enum().unwrap() - } -} - -/// An opaque identifier for a model in a schema AST. Use the -/// `schema[model_id]` syntax to resolve the id to an `ast::Model`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ClassId(u32); -impl std::ops::Index for SchemaAst { - type Output = Class; +pub struct TypeExpId(u32); +impl std::ops::Index for SchemaAst { + type Output = TypeExpressionBlock; - fn index(&self, index: ClassId) -> &Self::Output { - self.tops[index.0 as usize].as_class().unwrap() + fn index(&self, index: TypeExpId) -> &Self::Output { + self.tops[index.0 as usize] + .as_type_expression() + .expect("expected type expression") } } /// An opaque identifier for a model in a schema AST. Use the /// `schema[model_id]` syntax to resolve the id to an `ast::Model`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FunctionId((bool, u32)); -impl std::ops::Index for SchemaAst { - type Output = Function; +pub struct ValExpId(u32); +impl std::ops::Index for SchemaAst { + type Output = ValueExprBlock; - fn index(&self, index: FunctionId) -> &Self::Output { - let (ver, idx) = index.0; + fn index(&self, index: ValExpId) -> &Self::Output { + let idx = index.0; let var = &self.tops[idx as usize]; - if ver { - var.as_function().unwrap() - } else { - var.as_function_old().unwrap() - } - } -} - -/// An opaque identifier for a model in a schema AST. Use the -/// `schema[model_id]` syntax to resolve the id to an `ast::Model`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ClientId(u32); -impl std::ops::Index for SchemaAst { - type Output = Client; - - fn index(&self, index: ClientId) -> &Self::Output { - self.tops[index.0 as usize].as_client().unwrap() - } -} - -/// An opaque identifier for a model in a schema AST. Use the -/// `schema[model_id]` syntax to resolve the id to an `ast::Model`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct GeneratorConfigId(u32); -impl std::ops::Index for SchemaAst { - type Output = GeneratorConfig; - - fn index(&self, index: GeneratorConfigId) -> &Self::Output { - self.tops[index.0 as usize].as_generator().unwrap() - } -} -/// An opaque identifier for a model in a schema AST. Use the -/// `schema[model_id]` syntax to resolve the id to an `ast::Model`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct VariantConfigId(u32); -impl std::ops::Index for SchemaAst { - type Output = Variant; - - fn index(&self, index: VariantConfigId) -> &Self::Output { - self.tops[index.0 as usize].as_variant().unwrap() + var.as_value_exp().expect("expected value expression") } } @@ -181,57 +121,37 @@ impl std::ops::Index for SchemaAst { } } -/// An opaque identifier for a model in a schema AST. Use the -/// `schema[model_id]` syntax to resolve the id to an `ast::Model`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct ConfigurationId(u32); -impl std::ops::Index for SchemaAst { - type Output = Configuration; - - fn index(&self, index: ConfigurationId) -> &Self::Output { - self.tops[index.0 as usize].as_configurations().unwrap() - } -} - /// An identifier for a top-level item in a schema AST. Use the `schema[top_id]` /// syntax to resolve the id to an `ast::Top`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TopId { /// An enum declaration - Enum(EnumId), + Enum(TypeExpId), // A class declaration - Class(ClassId), + Class(TypeExpId), // A function declaration - Function(FunctionId), + Function(ValExpId), // A client declaration - Client(ClientId), + Client(ValExpId), // A generator declaration - Generator(GeneratorConfigId), - - // A variant declaration - Variant(VariantConfigId), + Generator(ValExpId), // Template Strings TemplateString(TemplateStringId), // A config block - Config((ConfigurationId, &'static str)), + TestCase(ValExpId), + + RetryPolicy(ValExpId), } impl TopId { - pub fn as_variant_id(self) -> Option { - match self { - TopId::Variant(id) => Some(id), - _ => None, - } - } - /// Try to interpret the top as an enum. - pub fn as_enum_id(self) -> Option { + pub fn as_enum_id(self) -> Option { match self { TopId::Enum(id) => Some(id), _ => None, @@ -239,7 +159,7 @@ impl TopId { } /// Try to interpret the top as a class. - pub fn as_class_id(self) -> Option { + pub fn as_class_id(self) -> Option { match self { TopId::Class(id) => Some(id), _ => None, @@ -247,27 +167,14 @@ impl TopId { } /// Try to interpret the top as a function. - // pub fn as_function_id(self) -> Option { - // match self { - // TopId::Function(id) => Some(id), - // _ => None, - // } - // } - - pub fn as_old_function_id(self) -> Option { - match self { - TopId::Function(id) if !id.0 .0 => Some(id), - _ => None, - } - } - pub fn as_new_function_id(self) -> Option { + pub fn as_function_id(self) -> Option { match self { - TopId::Function(id) if id.0 .0 => Some(id), + TopId::Function(id) => Some(id), _ => None, } } - pub fn as_client_id(self) -> Option { + pub fn as_client_id(self) -> Option { match self { TopId::Client(id) => Some(id), _ => None, @@ -281,23 +188,16 @@ impl TopId { } } - pub fn as_retry_policy_id(self) -> Option { - match self { - TopId::Config((id, "retry_policy")) => Some(id), - _ => None, - } - } - - pub fn as_printer_id(self) -> Option { + pub fn as_retry_policy_id(self) -> Option { match self { - TopId::Config((id, "printer")) => Some(id), + TopId::RetryPolicy(id) => Some(id), _ => None, } } - pub fn as_test_case_id(self) -> Option { + pub fn as_test_case_id(self) -> Option { match self { - TopId::Config((id, "test")) => Some(id), + TopId::TestCase(id) => Some(id), _ => None, } } @@ -308,14 +208,14 @@ impl std::ops::Index for SchemaAst { fn index(&self, index: TopId) -> &Self::Output { let idx = match index { - TopId::Enum(EnumId(idx)) => idx, - TopId::Class(ClassId(idx)) => idx, - TopId::Function(FunctionId((_, idx))) => idx, + TopId::Enum(TypeExpId(idx)) => idx, + TopId::Class(TypeExpId(idx)) => idx, + TopId::Function(ValExpId(idx)) => idx, TopId::TemplateString(TemplateStringId(idx)) => idx, - TopId::Client(ClientId(idx)) => idx, - TopId::Generator(GeneratorConfigId(idx)) => idx, - TopId::Variant(VariantConfigId(idx)) => idx, - TopId::Config((ConfigurationId(idx), _)) => idx, + TopId::Client(ValExpId(idx)) => idx, + TopId::Generator(ValExpId(idx)) => idx, + TopId::TestCase(ValExpId(idx)) => idx, + TopId::RetryPolicy(ValExpId(idx)) => idx, }; &self.tops[idx as usize] @@ -324,14 +224,13 @@ impl std::ops::Index for SchemaAst { fn top_idx_to_top_id(top_idx: usize, top: &Top) -> TopId { match top { - Top::Enum(_) => TopId::Enum(EnumId(top_idx as u32)), - Top::Class(_) => TopId::Class(ClassId(top_idx as u32)), - Top::FunctionOld(_) => TopId::Function(FunctionId((false, top_idx as u32))), - Top::Function(_) => TopId::Function(FunctionId((true, top_idx as u32))), - Top::Client(_) => TopId::Client(ClientId(top_idx as u32)), + Top::Enum(_) => TopId::Enum(TypeExpId(top_idx as u32)), + Top::Class(_) => TopId::Class(TypeExpId(top_idx as u32)), + Top::Function(_) => TopId::Function(ValExpId(top_idx as u32)), + Top::Client(_) => TopId::Client(ValExpId(top_idx as u32)), Top::TemplateString(_) => TopId::TemplateString(TemplateStringId(top_idx as u32)), - Top::Generator(_) => TopId::Generator(GeneratorConfigId(top_idx as u32)), - Top::Variant(_) => TopId::Variant(VariantConfigId(top_idx as u32)), - Top::Config(c) => TopId::Config((ConfigurationId(top_idx as u32), c.get_type())), + Top::Generator(_) => TopId::Generator(ValExpId(top_idx as u32)), + Top::TestCase(_) => TopId::TestCase(ValExpId(top_idx as u32)), + Top::RetryPolicy(_) => TopId::RetryPolicy(ValExpId(top_idx as u32)), } } diff --git a/engine/baml-lib/schema-ast/src/ast/adapter.rs b/engine/baml-lib/schema-ast/src/ast/adapter.rs deleted file mode 100644 index 519093fb3..000000000 --- a/engine/baml-lib/schema-ast/src/ast/adapter.rs +++ /dev/null @@ -1,18 +0,0 @@ -use internal_baml_diagnostics::Span; - -use super::{Expression, FieldType, WithSpan}; - -#[derive(Debug, Clone)] -pub struct Adapter { - pub from: FieldType, - pub to: FieldType, - pub converter: Expression, - - pub(crate) span: Span, -} - -impl WithSpan for Adapter { - fn span(&self) -> &Span { - &self.span - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/attribute.rs b/engine/baml-lib/schema-ast/src/ast/attribute.rs index a92cdd352..f902a2bb4 100644 --- a/engine/baml-lib/schema-ast/src/ast/attribute.rs +++ b/engine/baml-lib/schema-ast/src/ast/attribute.rs @@ -45,85 +45,24 @@ impl WithSpan for Attribute { /// A node containing attributes. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub enum AttributeContainer { - Class(super::ClassId), - ClassField(super::ClassId, super::FieldId), - Enum(super::EnumId), - EnumValue(super::EnumId, super::EnumValueId), - Variant(super::VariantConfigId), - VariantField(super::VariantConfigId, super::VariantFieldId), - VariantSerializer(super::VariantConfigId, super::VariantSerializerId), - VariantSerializerField( - super::VariantConfigId, - super::VariantSerializerId, - super::SerializerFieldId, - ), + Class(super::TypeExpId), + ClassField(super::TypeExpId, super::FieldId), + Enum(super::TypeExpId), + EnumValue(super::TypeExpId, super::FieldId), } -impl From<(super::VariantConfigId, super::VariantFieldId)> for AttributeContainer { - fn from((enm, val): (super::VariantConfigId, super::VariantFieldId)) -> Self { - Self::VariantField(enm, val) - } -} - -impl From for AttributeContainer { - fn from(v: super::EnumId) -> Self { +impl From for AttributeContainer { + fn from(v: super::TypeExpId) -> Self { Self::Enum(v) } } -impl From<(super::EnumId, super::EnumValueId)> for AttributeContainer { - fn from((enm, val): (super::EnumId, super::EnumValueId)) -> Self { +impl From<(super::TypeExpId, super::FieldId)> for AttributeContainer { + fn from((enm, val): (super::TypeExpId, super::FieldId)) -> Self { Self::EnumValue(enm, val) } } -// For Class variant -impl From for AttributeContainer { - fn from(v: super::ClassId) -> Self { - Self::Class(v) - } -} - -// For ClassField variant -impl From<(super::ClassId, super::FieldId)> for AttributeContainer { - fn from((cls, fld): (super::ClassId, super::FieldId)) -> Self { - Self::ClassField(cls, fld) - } -} - -// For Variant variant -impl From for AttributeContainer { - fn from(v: super::VariantConfigId) -> Self { - Self::Variant(v) - } -} - -// For VariantSerializer variant -impl From<(super::VariantConfigId, super::VariantSerializerId)> for AttributeContainer { - fn from((var, ser): (super::VariantConfigId, super::VariantSerializerId)) -> Self { - Self::VariantSerializer(var, ser) - } -} - -// For VariantSerializerField variant -impl - From<( - super::VariantConfigId, - super::VariantSerializerId, - super::SerializerFieldId, - )> for AttributeContainer -{ - fn from( - (var, ser, fld): ( - super::VariantConfigId, - super::VariantSerializerId, - super::SerializerFieldId, - ), - ) -> Self { - Self::VariantSerializerField(var, ser, fld) - } -} - /// An attribute (@ or @@) node in the AST. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct AttributeId(AttributeContainer, u32); @@ -147,16 +86,6 @@ impl Index for super::SchemaAst { AttributeContainer::EnumValue(enum_id, value_idx) => { &self[enum_id][value_idx].attributes } - AttributeContainer::Variant(variant_id) => &self[variant_id].attributes, - AttributeContainer::VariantField(variant_id, field_id) => { - &self[variant_id][field_id].attributes - } - AttributeContainer::VariantSerializer(variant_id, serializer_idx) => { - &self[variant_id][serializer_idx].attributes - } - AttributeContainer::VariantSerializerField(variant_id, serializer_idx, field_idx) => { - &self[variant_id][serializer_idx][field_idx].attributes - } } } } diff --git a/engine/baml-lib/schema-ast/src/ast/class.rs b/engine/baml-lib/schema-ast/src/ast/class.rs deleted file mode 100644 index 372e4d16c..000000000 --- a/engine/baml-lib/schema-ast/src/ast/class.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::{ - traits::WithAttributes, Attribute, Comment, Field, Identifier, Span, WithDocumentation, - WithIdentifier, WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for Class { - type Output = Field; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// A model declaration. -#[derive(Debug, Clone)] -pub struct Class { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub name: Identifier, - /// The fields of the model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// ^^^^^^^^^^^^^^^^ - /// field String - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub(crate) fields: Vec, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - /// The location of this model in the text representation. - pub(crate) span: Span, -} - -impl Class { - pub fn iter_fields(&self) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn fields(&self) -> &[Field] { - &self.fields - } -} - -impl WithIdentifier for Class { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for Class { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithAttributes for Class { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithDocumentation for Class { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/client.rs b/engine/baml-lib/schema-ast/src/ast/client.rs deleted file mode 100644 index b24bc1e3b..000000000 --- a/engine/baml-lib/schema-ast/src/ast/client.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::{ - traits::WithAttributes, Attribute, Comment, ConfigBlockProperty, Identifier, Span, - WithDocumentation, WithIdentifier, WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub(super) u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for Client { - type Output = ConfigBlockProperty; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// A model declaration. -#[derive(Debug, Clone)] -pub struct Client { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub(crate) name: Identifier, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - - pub fields: Vec, - - pub client_type: String, - - /// The location of this model in the text representation. - pub span: Span, -} - -impl Client { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn fields(&self) -> &[ConfigBlockProperty] { - &self.fields - } - - pub fn is_llm(&self) -> bool { - self.client_type == "llm" - } -} - -impl WithIdentifier for Client { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for Client { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithAttributes for Client { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithDocumentation for Client { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/configurations.rs b/engine/baml-lib/schema-ast/src/ast/configurations.rs deleted file mode 100644 index 84c9caa61..000000000 --- a/engine/baml-lib/schema-ast/src/ast/configurations.rs +++ /dev/null @@ -1,49 +0,0 @@ -use internal_baml_diagnostics::Span; - -use super::{ - ConfigBlockProperty, Identifier, PrinterConfig, RetryPolicyConfig, WithIdentifier, WithSpan, -}; - -#[derive(Debug, Clone)] -pub enum Configuration { - RetryPolicy(RetryPolicyConfig), - Printer(PrinterConfig), - TestCase(RetryPolicyConfig), -} -impl Configuration { - pub fn get_type(&self) -> &'static str { - match self { - Configuration::RetryPolicy(_) => "retry_policy", - Configuration::Printer(_) => "printer", - Configuration::TestCase(_) => "test", - } - } - - pub fn fields(&self) -> &[ConfigBlockProperty] { - match self { - Configuration::RetryPolicy(retry_policy) => retry_policy.fields(), - Configuration::Printer(printer) => printer.fields(), - Configuration::TestCase(retry_policy) => retry_policy.fields(), - } - } -} - -impl WithIdentifier for Configuration { - fn identifier(&self) -> &Identifier { - match self { - Configuration::RetryPolicy(retry_policy) => retry_policy.identifier(), - Configuration::Printer(printer) => printer.identifier(), - Configuration::TestCase(retry_policy) => retry_policy.identifier(), - } - } -} - -impl WithSpan for Configuration { - fn span(&self) -> &Span { - match self { - Configuration::RetryPolicy(retry_policy) => retry_policy.span(), - Configuration::Printer(printer) => printer.span(), - Configuration::TestCase(retry_policy) => retry_policy.span(), - } - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/expression.rs b/engine/baml-lib/schema-ast/src/ast/expression.rs index 885493f89..23d0929d5 100644 --- a/engine/baml-lib/schema-ast/src/ast/expression.rs +++ b/engine/baml-lib/schema-ast/src/ast/expression.rs @@ -157,9 +157,7 @@ pub enum Expression { impl Expression { pub fn from_json(value: serde_json::Value, span: Span, empty_span: Span) -> Expression { match value { - serde_json::Value::Null => { - Expression::Identifier(Identifier::Primitive(TypeValue::Null, span)) - } + serde_json::Value::Null => Expression::StringValue("Null".to_string(), empty_span), serde_json::Value::Bool(b) => Expression::BoolValue(b, span), serde_json::Value::Number(n) => Expression::NumericValue(n.to_string(), span), serde_json::Value::String(s) => Expression::StringValue(s, span), @@ -312,7 +310,6 @@ impl Expression { Identifier::Local(_, _) => "local_type", Identifier::Ref(_, _) => "ref_type", Identifier::ENV(_, _) => "env_type", - Identifier::Primitive(_, _) => "primitive_type", Identifier::Invalid(_, _) => "invalid_type", }, Expression::Map(_, _) => "map", diff --git a/engine/baml-lib/schema-ast/src/ast/field.rs b/engine/baml-lib/schema-ast/src/ast/field.rs index 48890bbf6..0884792a3 100644 --- a/engine/baml-lib/schema-ast/src/ast/field.rs +++ b/engine/baml-lib/schema-ast/src/ast/field.rs @@ -8,14 +8,14 @@ use super::{ /// A field definition in a model or a composite type. #[derive(Debug, Clone)] -pub struct Field { +pub struct Field { /// The field's type. /// /// ```ignore /// name String /// ^^^^^^ /// ``` - pub field_type: FieldType, + pub expr: Option, /// The name of the field. /// /// ```ignore @@ -42,7 +42,7 @@ pub struct Field { pub(crate) span: Span, } -impl Field { +impl Field { /// Finds the position span of the argument in the given field attribute. pub fn span_for_argument(&self, attribute: &str, _argument: &str) -> Option { self.attributes @@ -68,25 +68,25 @@ impl Field { } } -impl WithIdentifier for Field { +impl WithIdentifier for Field { fn identifier(&self) -> &Identifier { &self.name } } -impl WithSpan for Field { +impl WithSpan for Field { fn span(&self) -> &Span { &self.span } } -impl WithAttributes for Field { +impl WithAttributes for Field { fn attributes(&self) -> &[Attribute] { &self.attributes } } -impl WithDocumentation for Field { +impl WithDocumentation for Field { fn documentation(&self) -> Option<&str> { self.documentation.as_ref().map(|doc| doc.text.as_str()) } @@ -109,25 +109,42 @@ impl FieldArity { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone)] pub enum FieldType { - Identifier(FieldArity, Identifier), + Symbol(FieldArity, String, Span, Option>), + Primitive(FieldArity, TypeValue, Span, Option>), // The second field is the number of dims for the list - List(Box, u32, Span), - Tuple(FieldArity, Vec, Span), - // Unions don't have arity, as they are can be flattened. - Union(FieldArity, Vec, Span), - Map(Box<(FieldType, FieldType)>, Span), + List(Box, u32, Span, Option>), + Tuple(FieldArity, Vec, Span, Option>), + // Unions don't have arity, as they can be flattened. + Union(FieldArity, Vec, Span, Option>), + Map(Box<(FieldType, FieldType)>, Span, Option>), +} + +fn arity_suffix(arity: &FieldArity) -> &'static str { + match arity { + FieldArity::Required => "", + FieldArity::Optional => "?", + } } impl FieldType { + pub fn name(&self) -> String { + match self { + FieldType::Symbol(_, name, ..) => name.clone(), + FieldType::Primitive(_, name, ..) => name.to_string(), + _ => "Unknown".to_string(), + } + } + pub fn span(&self) -> &Span { match self { - FieldType::Identifier(.., idn) => idn.span(), - FieldType::Union(.., span) => span, - FieldType::Tuple(.., span) => span, - FieldType::Map(.., span) => span, - FieldType::List(.., span) => span, + FieldType::Primitive(.., span, _) => span, + FieldType::Symbol(.., span, _) => span, + FieldType::Union(.., span, _) => span, + FieldType::Tuple(.., span, _) => span, + FieldType::Map(.., span, _) => span, + FieldType::List(.., span, _) => span, } } @@ -136,31 +153,45 @@ impl FieldType { return Ok(self.to_owned()); } match self { - FieldType::Identifier(_arity, Identifier::Primitive(TypeValue::Null, _)) => { - Ok(self.to_owned()) - } - FieldType::Identifier(_arity, idn) => { - Ok(FieldType::Identifier(FieldArity::Optional, idn.to_owned())) - } - FieldType::Union(arity, items, span) => { + FieldType::Symbol(_arity, idn, span, attributes) => Ok(FieldType::Symbol( + FieldArity::Optional, + idn.to_owned(), + span.to_owned(), + attributes.to_owned(), + )), + FieldType::Primitive(_arity, type_value, span, attributes) => Ok(FieldType::Primitive( + FieldArity::Optional, + type_value.to_owned(), + span.to_owned(), + attributes.to_owned(), + )), + FieldType::Union(arity, items, span, attributes) => { let mut items = items.clone(); - items.push(FieldType::Identifier( + items.push(FieldType::Primitive( FieldArity::Required, - Identifier::Primitive(TypeValue::Null, span.clone()), + TypeValue::Null, + span.clone(), + None, )); - Ok(FieldType::Union(*arity, items, span.to_owned())) + Ok(FieldType::Union( + *arity, + items, + span.to_owned(), + attributes.to_owned(), + )) } - FieldType::Tuple(_arity, options, span) => Ok(FieldType::Tuple( + FieldType::Tuple(_arity, options, span, attributes) => Ok(FieldType::Tuple( FieldArity::Optional, options.to_owned(), span.to_owned(), + attributes.to_owned(), )), - FieldType::Map(.., span) => Err(DatamodelError::new_validation_error( + FieldType::Map(_, span, _) => Err(DatamodelError::new_validation_error( "Dictionaries can not be optional", span.clone(), )), - FieldType::List(.., span) => Err(DatamodelError::new_validation_error( + FieldType::List(_, _, span, _) => Err(DatamodelError::new_validation_error( "Lists can not be optional", span.clone(), )), @@ -169,47 +200,77 @@ impl FieldType { pub fn is_nullable(&self) -> bool { match self { - FieldType::Identifier(arity, t) => { - arity.is_optional() || matches!(t, Identifier::Primitive(TypeValue::Null, _)) - } - FieldType::Union(arity, f, ..) => { + FieldType::Symbol(arity, t, _, _) => arity.is_optional(), + FieldType::Union(arity, f, _, _) => { arity.is_optional() || f.iter().any(|t| t.is_nullable()) } - FieldType::Tuple(arity, ..) => arity.is_optional(), + FieldType::Tuple(arity, _, _, _) => arity.is_optional(), + FieldType::Primitive(arity, _, _, _) => arity.is_optional(), // Lists can't be nullable - FieldType::Map(_kv, _) => false, - FieldType::List(_t, _, _) => false, + FieldType::Map(_kv, _, _) => false, + FieldType::List(_t, _, _, _) => false, } } - // Whether the field could theoretically be made optional. pub fn can_be_null(&self) -> bool { match self { - FieldType::Identifier(_arity, t) => match t { - Identifier::Primitive(TypeValue::Null, _) => true, - _ => true, - }, + FieldType::Symbol(_arity, t, ..) => true, + FieldType::Primitive(_arity, ..) => true, // There's a bug with unions where we cant parse optionals in unions right now FieldType::Union(_arity, _f, ..) => false, FieldType::Tuple(_arity, ..) => true, // Lists can't be nullable - FieldType::Map(_kv, _) => false, - FieldType::List(_t, _, _) => false, + FieldType::Map(_kv, ..) => false, + FieldType::List(_t, ..) => false, } } // All the identifiers used in this type. pub fn flat_idns(&self) -> Vec<&Identifier> { match self { - FieldType::Identifier(.., idn) => vec![idn], + FieldType::Symbol(_, idn, ..) => vec![], FieldType::Union(_, f, ..) => f.iter().flat_map(|t| t.flat_idns()).collect(), FieldType::Tuple(_, f, ..) => f.iter().flat_map(|t| t.flat_idns()).collect(), - FieldType::Map(kv, _) => { + FieldType::Map(kv, ..) => { let mut idns = kv.1.flat_idns(); idns.extend(kv.0.flat_idns()); idns } - FieldType::List(t, _, _) => t.flat_idns(), + FieldType::List(t, ..) => t.flat_idns(), + FieldType::Primitive(..) => vec![], + } + } + + pub fn attributes(&self) -> &[Attribute] { + match self { + FieldType::Symbol(.., attr) + | FieldType::Primitive(.., attr) + | FieldType::Union(.., attr) + | FieldType::Tuple(.., attr) + | FieldType::Map(.., attr) + | FieldType::List(.., attr) => attr.as_deref().unwrap_or(&[]), + } + } + + pub fn reset_attributes(&mut self) { + match self { + FieldType::Symbol(.., attr) + | FieldType::Primitive(.., attr) + | FieldType::Union(.., attr) + | FieldType::Tuple(.., attr) + | FieldType::Map(.., attr) + | FieldType::List(.., attr) => *attr = None, + } + } + + pub fn set_attributes(&mut self, attributes: Vec) { + match self { + FieldType::Symbol(.., attr) + | FieldType::Primitive(.., attr) + | FieldType::Union(.., attr) + | FieldType::Tuple(.., attr) + | FieldType::Map(.., attr) + | FieldType::List(.., attr) => *attr = Some(attributes), } } } @@ -218,15 +279,10 @@ impl FieldType { impl std::fmt::Display for FieldType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - FieldType::Identifier(arity, idn) => { - write!( - f, - "{}{}", - idn.name(), - if arity.is_optional() { "?" } else { "" } - ) + FieldType::Symbol(arity, idn, ..) => { + write!(f, "{}{}", idn, if arity.is_optional() { "?" } else { "" }) } - FieldType::Union(arity, ft, _) => { + FieldType::Union(arity, ft, ..) => { let mut ft = ft.iter().map(|t| t.to_string()).collect::>(); ft.sort(); write!( @@ -236,7 +292,7 @@ impl std::fmt::Display for FieldType { if arity.is_optional() { "?" } else { "" } ) } - FieldType::Tuple(arity, ft, _) => { + FieldType::Tuple(arity, ft, ..) => { let mut ft = ft.iter().map(|t| t.to_string()).collect::>(); ft.sort(); write!( @@ -246,8 +302,11 @@ impl std::fmt::Display for FieldType { if arity.is_optional() { "?" } else { "" } ) } - FieldType::Map(kv, _) => write!(f, "map<{}, {}>", kv.0, kv.1), - FieldType::List(t, _, _) => write!(f, "{}[]", t), + FieldType::Map(kv, ..) => write!(f, "map<{}, {}>", kv.0, kv.1), + FieldType::List(t, ..) => write!(f, "{}[]", t), + FieldType::Primitive(arity, t, ..) => { + write!(f, "{}{}", t, if arity.is_optional() { "?" } else { "" }) + } } } } diff --git a/engine/baml-lib/schema-ast/src/ast/find_at_position.rs b/engine/baml-lib/schema-ast/src/ast/find_at_position.rs deleted file mode 100644 index 2ec07de26..000000000 --- a/engine/baml-lib/schema-ast/src/ast/find_at_position.rs +++ /dev/null @@ -1,124 +0,0 @@ -use crate::ast::{self, top_idx_to_top_id, traits::*}; - -impl ast::SchemaAst { - /// Find the AST node at the given position (byte offset). - pub fn find_at_position(&self, position: usize) -> SchemaPosition<'_> { - self.find_top_at_position(position) - .map(|top_id| match top_id { - ast::TopId::Enum(enum_id) => { - SchemaPosition::Enum(enum_id, EnumPosition::new(&self[enum_id], position)) - } - // Falling back to TopLevel as "not implemented" - _ => SchemaPosition::TopLevel, - }) - // If no top matched, we're in between top-level items. This is normal and expected. - .unwrap_or(SchemaPosition::TopLevel) - } - - /// Do a binary search for the `Top` at the given byte offset. - pub fn find_top_at_position(&self, position: usize) -> Option { - use std::cmp::Ordering; - - let top_idx = self.tops.binary_search_by(|top| { - let span = top.span(); - - if span.start > position { - Ordering::Greater - } else if span.end < position { - Ordering::Less - } else { - Ordering::Equal - } - }); - - top_idx - .map(|idx| top_idx_to_top_id(idx, &self.tops[idx])) - .ok() - } -} - -/// A cursor position in a schema. -#[derive(Debug)] -pub enum SchemaPosition<'ast> { - /// In-between top-level items - TopLevel, - /// In an enum - Enum(ast::EnumId, EnumPosition<'ast>), -} - -/// A cursor position in a context. -#[derive(Debug)] -pub enum EnumPosition<'ast> { - /// In the enum, but not somewhere more specific. - Enum, - // /// In an attribute (attr name, attr index, position). - // EnumAttribute(&'ast str, usize, AttributePosition<'ast>), - /// In a value. - Value(ast::EnumValueId, EnumValuePosition<'ast>), -} - -impl<'ast> EnumPosition<'ast> { - fn new(r#enum: &'ast ast::Enum, position: usize) -> Self { - for (enum_value_id, value) in r#enum.iter_values() { - if value.span().contains(position) { - return EnumPosition::Value(enum_value_id, EnumValuePosition::new(value, position)); - } - } - - // for (attr_id, attr) in r#enum.attributes.iter().enumerate() { - // if attr.span().contains(position) { - // return EnumPosition::EnumAttribute(&attr.name.name, attr_id, AttributePosition::new(attr, position)); - // } - // } - - EnumPosition::Enum - } -} - -/// In an enum value. -#[derive(Debug)] -pub enum EnumValuePosition<'ast> { - /// Nowhere specific inside the value - Value, - /// In an attribute. (name, idx, optional arg) - Attribute(&'ast str, usize, Option<&'ast str>), -} - -impl<'ast> EnumValuePosition<'ast> { - fn new(_value: &'ast ast::EnumValue, _position: usize) -> EnumValuePosition<'ast> { - // for (attr_idx, attr) in value.attributes.iter().enumerate() { - // if attr.span().contains(position) { - // // We can't go by Span::contains() because we also care about the empty space - // // between arguments and that's hard to capture in the pest grammar. - // let mut spans: Vec<(Option<&str>, ast::Span)> = attr - // .arguments - // .iter() - // .map(|arg| (arg.name.as_ref().map(|n| n.name.as_str()), arg.span())) - // .chain( - // attr.arguments - // .empty_arguments - // .iter() - // .map(|arg| (Some(arg.name.name.as_str()), arg.name.span())), - // ) - // .collect(); - // spans.sort_by_key(|(_, span)| span.start); - // let mut arg_name = None; - - // for (name, _) in spans.iter().take_while(|(_, span)| span.start < position) { - // arg_name = Some(*name); - // } - - // // If the cursor is after a trailing comma, we're not in an argument. - // if let Some(span) = attr.arguments.trailing_comma { - // if position > span.start { - // arg_name = None; - // } - // } - - // return EnumValuePosition::Attribute(attr.name(), attr_idx, arg_name.flatten()); - // } - // } - - EnumValuePosition::Value - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/generator_config.rs b/engine/baml-lib/schema-ast/src/ast/generator_config.rs deleted file mode 100644 index 6d6a3f640..000000000 --- a/engine/baml-lib/schema-ast/src/ast/generator_config.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::{ - Attribute, Comment, ConfigBlockProperty, Identifier, Span, WithDocumentation, WithIdentifier, - WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub(super) u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for GeneratorConfig { - type Output = ConfigBlockProperty; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// A Generator block declaration. -#[derive(Debug, Clone)] -pub struct GeneratorConfig { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub(crate) name: Identifier, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - - pub fields: Vec, - - /// The location of this model in the text representation. - pub(crate) span: Span, -} - -impl GeneratorConfig { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn fields(&self) -> &[ConfigBlockProperty] { - &self.fields - } -} - -impl WithIdentifier for GeneratorConfig { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for GeneratorConfig { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithDocumentation for GeneratorConfig { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/identifier.rs b/engine/baml-lib/schema-ast/src/ast/identifier.rs index e20e83f60..05849e2b9 100644 --- a/engine/baml-lib/schema-ast/src/ast/identifier.rs +++ b/engine/baml-lib/schema-ast/src/ast/identifier.rs @@ -1,5 +1,3 @@ -use baml_types::TypeValue; - use super::{Span, WithName, WithSpan}; /// An identifier the refers to a field or type in a different location. @@ -19,8 +17,6 @@ pub enum Identifier { Ref(RefIdentifier, Span), /// A string without spaces or '.' Always starts with a letter. May contain numbers Local(String, Span), - /// Special types (always lowercase). - Primitive(TypeValue, Span), /// A string without spaces, but contains '-' String(String, Span), /// Something that cannot be used for anything. @@ -28,12 +24,20 @@ pub enum Identifier { } impl Identifier { + pub fn to_string(&self) -> String { + match self { + Identifier::ENV(s, _) => format!("env.{}", s), + Identifier::Ref(ref_identifier, _) => ref_identifier.full_name.clone(), + Identifier::Local(s, _) => s.clone(), + Identifier::String(s, _) => s.clone(), + Identifier::Invalid(s, _) => s.clone(), + } + } pub fn is_valid_type(&self) -> bool { match self { Identifier::ENV(_, _) => false, Identifier::Ref(_, _) => true, Identifier::Local(_, _) => true, - Identifier::Primitive(_, _) => true, Identifier::String(_, _) => false, Identifier::Invalid(_, _) => false, } @@ -44,7 +48,7 @@ impl Identifier { Identifier::ENV(_, _) => false, Identifier::Ref(_, _) => true, Identifier::Local(_, _) => true, - Identifier::Primitive(_, _) => true, + Identifier::String(_, _) => false, Identifier::Invalid(_, _) => false, } @@ -56,7 +60,7 @@ impl Identifier { Identifier::Local(_, _) => true, Identifier::String(_, _) => true, Identifier::Ref(_, _) => false, - Identifier::Primitive(_, _) => false, + Identifier::Invalid(_, _) => false, } } @@ -68,7 +72,7 @@ impl WithSpan for Identifier { Identifier::ENV(_, span) => span, Identifier::Ref(_, span) => span, Identifier::Local(_, span) => span, - Identifier::Primitive(_, span) => span, + Identifier::String(_, span) => span, Identifier::Invalid(_, span) => span, } @@ -80,15 +84,7 @@ impl WithName for Identifier { match self { Identifier::Ref(ref_identifier, _) => &ref_identifier.full_name, Identifier::Local(name, _) => name, - Identifier::Primitive(t, _) => match t { - TypeValue::String => "string", - TypeValue::Int => "int", - TypeValue::Float => "float", - TypeValue::Bool => "bool", - TypeValue::Null => "null", - TypeValue::Image => "image", - TypeValue::Audio => "audio", - }, + Identifier::String(s, _) => s, Identifier::ENV(name, _) => name, Identifier::Invalid(name, _) => name, @@ -110,13 +106,7 @@ impl From<(&str, Span)> for Identifier { }, span, ), - "string" => Identifier::Primitive(TypeValue::String, span), - "int" => Identifier::Primitive(TypeValue::Int, span), - "float" => Identifier::Primitive(TypeValue::Float, span), - "bool" => Identifier::Primitive(TypeValue::Bool, span), - "null" => Identifier::Primitive(TypeValue::Null, span), - "image" => Identifier::Primitive(TypeValue::Image, span), - "audio" => Identifier::Primitive(TypeValue::Audio, span), + "env" => Identifier::Invalid("env".into(), span), other if other.contains('-') => Identifier::String(other.to_string(), span), other => Identifier::Local(other.to_string(), span), diff --git a/engine/baml-lib/schema-ast/src/ast/printer_config.rs b/engine/baml-lib/schema-ast/src/ast/printer_config.rs deleted file mode 100644 index e8e378711..000000000 --- a/engine/baml-lib/schema-ast/src/ast/printer_config.rs +++ /dev/null @@ -1,101 +0,0 @@ -use super::{ - Attribute, Comment, ConfigBlockProperty, Expression, Identifier, Span, WithDocumentation, - WithIdentifier, WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub(super) u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for PrinterConfig { - type Output = ConfigBlockProperty; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// A Printer block declaration. -#[derive(Debug, Clone)] -pub struct PrinterConfig { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub(crate) name: Identifier, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - - pub fields: Vec, - - /// The location of this model in the text representation. - pub(crate) span: Span, - - pub printer_type: Expression, -} - -impl PrinterConfig { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn fields(&self) -> &[ConfigBlockProperty] { - &self.fields - } -} - -impl WithIdentifier for PrinterConfig { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for PrinterConfig { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithDocumentation for PrinterConfig { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/retry_policy_config.rs b/engine/baml-lib/schema-ast/src/ast/retry_policy_config.rs deleted file mode 100644 index 3dbff7469..000000000 --- a/engine/baml-lib/schema-ast/src/ast/retry_policy_config.rs +++ /dev/null @@ -1,99 +0,0 @@ -use super::{ - Attribute, Comment, ConfigBlockProperty, Identifier, Span, WithDocumentation, WithIdentifier, - WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub(super) u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for RetryPolicyConfig { - type Output = ConfigBlockProperty; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// A RetryPolicy block declaration. -#[derive(Debug, Clone)] -pub struct RetryPolicyConfig { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub(crate) name: Identifier, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - - pub fields: Vec, - - /// The location of this model in the text representation. - pub(crate) span: Span, -} - -impl RetryPolicyConfig { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn fields(&self) -> &[ConfigBlockProperty] { - &self.fields - } -} - -impl WithIdentifier for RetryPolicyConfig { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for RetryPolicyConfig { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithDocumentation for RetryPolicyConfig { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/serializer.rs b/engine/baml-lib/schema-ast/src/ast/serializer.rs deleted file mode 100644 index 6eee4f1e3..000000000 --- a/engine/baml-lib/schema-ast/src/ast/serializer.rs +++ /dev/null @@ -1,116 +0,0 @@ -use super::{ - traits::WithAttributes, Attribute, Comment, Identifier, Span, WithDocumentation, - WithIdentifier, WithName, WithSpan, -}; - -/// An opaque identifier for a value in an AST enum. Use the -/// `r#enum[enum_value_id]` syntax to resolve the id to an `ast::SerializerField`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SerializerFieldId(pub u32); - -impl SerializerFieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: SerializerFieldId = SerializerFieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: SerializerFieldId = SerializerFieldId(u32::MAX); -} - -impl std::ops::Index for Serializer { - type Output = SerializerField; - - fn index(&self, index: SerializerFieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -/// An enum declaration. Enumeration can either be in the database schema, or completely a Prisma level concept. -/// -/// PostgreSQL stores enums in a schema, while in MySQL the information is in -/// the table definition. On MongoDB the enumerations are handled in the Query -/// Engine. -#[derive(Debug, Clone)] -pub struct Serializer { - pub name: Identifier, - - pub fields: Vec, - - pub attributes: Vec, - - pub(crate) documentation: Option, - pub span: Span, -} - -impl Serializer { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (SerializerFieldId(idx as u32), field)) - } - - pub fn field_id_for(&self, name: &str) -> Option { - self.fields - .iter() - .enumerate() - .find(|(_, field)| field.name() == name) - .map(|(idx, _)| SerializerFieldId(idx as u32)) - } -} - -impl WithIdentifier for Serializer { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for Serializer { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithAttributes for Serializer { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithDocumentation for Serializer { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} - -#[derive(Debug, Clone)] -pub struct SerializerField { - pub name: Identifier, - pub attributes: Vec, - pub(crate) documentation: Option, - pub span: Span, -} - -impl WithIdentifier for SerializerField { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithAttributes for SerializerField { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithSpan for SerializerField { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithDocumentation for SerializerField { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/ast/template_string.rs b/engine/baml-lib/schema-ast/src/ast/template_string.rs index a423a12b7..2be1d7d06 100644 --- a/engine/baml-lib/schema-ast/src/ast/template_string.rs +++ b/engine/baml-lib/schema-ast/src/ast/template_string.rs @@ -1,5 +1,5 @@ use super::{ - traits::WithAttributes, Attribute, Comment, Expression, FunctionArgs, Identifier, Span, + traits::WithAttributes, Attribute, BlockArgs, Comment, Expression, Identifier, Span, WithDocumentation, WithIdentifier, WithSpan, }; @@ -38,7 +38,7 @@ pub struct TemplateString { /// ^^^^^^^^^^^^ /// } /// ``` - pub(crate) input: Option, + pub(crate) input: Option, pub attributes: Vec, /// The location of this model in the text representation. pub span: Span, @@ -50,7 +50,7 @@ impl TemplateString { &self.value } - pub fn input(&self) -> Option<&FunctionArgs> { + pub fn input(&self) -> Option<&BlockArgs> { self.input.as_ref() } } diff --git a/engine/baml-lib/schema-ast/src/ast/top.rs b/engine/baml-lib/schema-ast/src/ast/top.rs index d794a9bf3..595e27e54 100644 --- a/engine/baml-lib/schema-ast/src/ast/top.rs +++ b/engine/baml-lib/schema-ast/src/ast/top.rs @@ -1,32 +1,29 @@ use super::{ - traits::WithSpan, Class, Client, Configuration, Enum, Function, GeneratorConfig, Identifier, - Span, TemplateString, Variant, WithIdentifier, + traits::WithSpan, Identifier, Span, TemplateString, TypeExpressionBlock, ValueExprBlock, + WithIdentifier, }; /// Enum for distinguishing between top-level entries #[derive(Debug, Clone)] pub enum Top { /// An enum declaration - Enum(Enum), + Enum(TypeExpressionBlock), // A class declaration - Class(Class), + Class(TypeExpressionBlock), // A function declaration - FunctionOld(Function), - Function(Function), + Function(ValueExprBlock), // Clients to run - Client(Client), - - // Variant to run - Variant(Variant), + Client(ValueExprBlock), TemplateString(TemplateString), - // Abritrary config (things with names and key-value pairs where keys are known) - Config(Configuration), - // Generator - Generator(GeneratorConfig), + Generator(ValueExprBlock), + + TestCase(ValueExprBlock), + + RetryPolicy(ValueExprBlock), } impl Top { @@ -36,64 +33,31 @@ impl Top { // Top::CompositeType(_) => "composite type", Top::Enum(_) => "enum", Top::Class(_) => "class", - Top::FunctionOld(_) => "function[deprecated signature]", Top::Function(_) => "function", - Top::Client(m) if m.is_llm() => "client", - Top::Client(_) => "client", + Top::Client(_) => "client", Top::TemplateString(_) => "template_string", - Top::Variant(v) if v.is_llm() => "impl", - Top::Variant(_) => "impl", Top::Generator(_) => "generator", - Top::Config(c) => c.get_type(), + Top::TestCase(_) => "test_case", + Top::RetryPolicy(_) => "retry_policy", } } /// Try to interpret the item as an enum declaration. - pub fn as_enum(&self) -> Option<&Enum> { + pub fn as_type_expression(&self) -> Option<&TypeExpressionBlock> { match self { Top::Enum(r#enum) => Some(r#enum), - _ => None, - } - } - - pub fn as_class(&self) -> Option<&Class> { - match self { Top::Class(class) => Some(class), _ => None, } } - pub fn as_function_old(&self) -> Option<&Function> { - match self { - Top::FunctionOld(func) => Some(func), - _ => None, - } - } - - pub fn as_function(&self) -> Option<&Function> { + pub fn as_value_exp(&self) -> Option<&ValueExprBlock> { match self { Top::Function(func) => Some(func), - _ => None, - } - } - - pub fn as_client(&self) -> Option<&Client> { - match self { Top::Client(client) => Some(client), - _ => None, - } - } - - pub fn as_generator(&self) -> Option<&GeneratorConfig> { - match self { Top::Generator(gen) => Some(gen), - _ => None, - } - } - - pub fn as_variant(&self) -> Option<&Variant> { - match self { - Top::Variant(variant) => Some(variant), + Top::TestCase(test) => Some(test), + Top::RetryPolicy(retry) => Some(retry), _ => None, } } @@ -104,13 +68,6 @@ impl Top { _ => None, } } - - pub fn as_configurations(&self) -> Option<&Configuration> { - match self { - Top::Config(config) => Some(config), - _ => None, - } - } } impl WithIdentifier for Top { @@ -120,12 +77,12 @@ impl WithIdentifier for Top { // Top::CompositeType(ct) => &ct.name, Top::Enum(x) => x.identifier(), Top::Class(x) => x.identifier(), - Top::Function(x) | Top::FunctionOld(x) => x.identifier(), + Top::Function(x) => x.identifier(), Top::Client(x) => x.identifier(), Top::TemplateString(x) => x.identifier(), - Top::Variant(x) => x.identifier(), Top::Generator(x) => x.identifier(), - Top::Config(x) => x.identifier(), + Top::TestCase(x) => x.identifier(), + Top::RetryPolicy(x) => x.identifier(), } } } @@ -135,12 +92,12 @@ impl WithSpan for Top { match self { Top::Enum(en) => en.span(), Top::Class(class) => class.span(), - Top::Function(func) | Top::FunctionOld(func) => func.span(), + Top::Function(func) => func.span(), Top::TemplateString(template) => template.span(), Top::Client(client) => client.span(), - Top::Variant(variant) => variant.span(), Top::Generator(gen) => gen.span(), - Top::Config(config) => config.span(), + Top::TestCase(test) => test.span(), + Top::RetryPolicy(retry) => retry.span(), } } } diff --git a/engine/baml-lib/schema-ast/src/ast/enum.rs b/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs similarity index 55% rename from engine/baml-lib/schema-ast/src/ast/enum.rs rename to engine/baml-lib/schema-ast/src/ast/type_expression_block.rs index c4b4e077a..b543b580a 100644 --- a/engine/baml-lib/schema-ast/src/ast/enum.rs +++ b/engine/baml-lib/schema-ast/src/ast/type_expression_block.rs @@ -1,35 +1,42 @@ use super::{ - traits::WithAttributes, Attribute, Comment, Identifier, Span, WithDocumentation, - WithIdentifier, WithSpan, + traits::WithAttributes, Attribute, Comment, Field, FieldType, Identifier, Span, + WithDocumentation, WithIdentifier, WithSpan, }; /// An opaque identifier for a value in an AST enum. Use the /// `r#enum[enum_value_id]` syntax to resolve the id to an `ast::EnumValue`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct EnumValueId(pub u32); +pub struct FieldId(pub u32); -impl EnumValueId { +impl FieldId { /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: EnumValueId = EnumValueId(0); + pub const MIN: FieldId = FieldId(0); /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: EnumValueId = EnumValueId(u32::MAX); + pub const MAX: FieldId = FieldId(u32::MAX); } -impl std::ops::Index for Enum { - type Output = EnumValue; +impl std::ops::Index for TypeExpressionBlock { + type Output = Field; - fn index(&self, index: EnumValueId) -> &Self::Output { - &self.values[index.0 as usize] + fn index(&self, index: FieldId) -> &Self::Output { + &self.fields[index.0 as usize] } } +#[derive(Debug, Clone)] +pub enum SubType { + Enum, + Class, + Other(String), +} + /// An enum declaration. Enumeration can either be in the database schema, or completely a Prisma level concept. /// /// PostgreSQL stores enums in a schema, while in MySQL the information is in /// the table definition. On MongoDB the enumerations are handled in the Query /// Engine. #[derive(Debug, Clone)] -pub struct Enum { +pub struct TypeExpressionBlock { /// The name of the enum. /// /// ```ignore @@ -47,7 +54,7 @@ pub struct Enum { /// ^^^^^^ /// } /// ``` - pub values: Vec, + pub fields: Vec>, // needs to support field as well /// The attributes of this enum. /// @@ -75,71 +82,43 @@ pub struct Enum { pub(crate) documentation: Option, /// The location of this enum in the text representation. pub span: Span, + + /// This is used to distinguish between enums and classes. + pub sub_type: SubType, } -impl Enum { - pub fn iter_values(&self) -> impl ExactSizeIterator { - self.values +impl TypeExpressionBlock { + pub fn iter_fields(&self) -> impl ExactSizeIterator)> { + self.fields .iter() .enumerate() - .map(|(idx, field)| (EnumValueId(idx as u32), field)) + .map(|(idx, field)| (FieldId(idx as u32), field)) + } + + pub fn values(&self) -> &[Field] { + &self.fields } } -impl WithIdentifier for Enum { +impl WithIdentifier for TypeExpressionBlock { fn identifier(&self) -> &Identifier { &self.name } } -impl WithSpan for Enum { +impl WithSpan for TypeExpressionBlock { fn span(&self) -> &Span { &self.span } } -impl WithAttributes for Enum { +impl WithAttributes for TypeExpressionBlock { fn attributes(&self) -> &[Attribute] { &self.attributes } } -impl WithDocumentation for Enum { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} - -/// An enum value definition. -#[derive(Debug, Clone)] -pub struct EnumValue { - /// The name of the enum value as it will be exposed by the api. - pub name: Identifier, - pub attributes: Vec, - pub(crate) documentation: Option, - /// The location of this enum value in the text representation. - pub span: Span, -} - -impl WithIdentifier for EnumValue { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithAttributes for EnumValue { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithSpan for EnumValue { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithDocumentation for EnumValue { +impl WithDocumentation for TypeExpressionBlock { fn documentation(&self) -> Option<&str> { self.documentation.as_ref().map(|doc| doc.text.as_str()) } diff --git a/engine/baml-lib/schema-ast/src/ast/function.rs b/engine/baml-lib/schema-ast/src/ast/value_expression_block.rs similarity index 55% rename from engine/baml-lib/schema-ast/src/ast/function.rs rename to engine/baml-lib/schema-ast/src/ast/value_expression_block.rs index f7d202cb8..7ec5ba5ec 100644 --- a/engine/baml-lib/schema-ast/src/ast/function.rs +++ b/engine/baml-lib/schema-ast/src/ast/value_expression_block.rs @@ -1,12 +1,12 @@ use super::{ - traits::WithAttributes, Attribute, Comment, ConfigBlockProperty, FieldType, Identifier, Span, + traits::WithAttributes, Attribute, Comment, Expression, Field, FieldType, Identifier, Span, WithDocumentation, WithIdentifier, WithSpan, }; /// An opaque identifier for a value in an AST enum. Use the /// `r#enum[enum_value_id]` syntax to resolve the id to an `ast::EnumValue`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FuncArguementId(pub u32); +pub struct ArgumentId(pub u32); /// An opaque identifier for a field in an AST model. Use the /// `model[field_id]` syntax to resolve the id to an `ast::Field`. @@ -20,40 +20,40 @@ impl FieldId { pub const MAX: FieldId = FieldId(u32::MAX); } -impl std::ops::Index for Function { - type Output = ConfigBlockProperty; +impl std::ops::Index for ValueExprBlock { + type Output = Field; fn index(&self, index: FieldId) -> &Self::Output { &self.fields[index.0 as usize] } } -impl FuncArguementId { +impl ArgumentId { /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FuncArguementId = FuncArguementId(0); + pub const MIN: ArgumentId = ArgumentId(0); /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FuncArguementId = FuncArguementId(u32::MAX); + pub const MAX: ArgumentId = ArgumentId(u32::MAX); } -impl std::ops::Index for NamedFunctionArgList { - type Output = (Identifier, FunctionArg); +impl std::ops::Index for BlockArgs { + type Output = (Identifier, BlockArg); - fn index(&self, index: FuncArguementId) -> &Self::Output { + fn index(&self, index: ArgumentId) -> &Self::Output { &self.args[index.0 as usize] } } -impl std::ops::Index for FunctionArg { - type Output = FunctionArg; +impl std::ops::Index for BlockArg { + type Output = BlockArg; - fn index(&self, index: FuncArguementId) -> &Self::Output { - assert_eq!(index, FuncArguementId(0), "FunctionArg only has one arg"); + fn index(&self, index: ArgumentId) -> &Self::Output { + assert_eq!(index, ArgumentId(0), "BlockArg only has one arg"); self } } #[derive(Debug, Clone)] -pub struct FunctionArg { +pub struct BlockArg { /// The field's type. pub field_type: FieldType, @@ -61,58 +61,51 @@ pub struct FunctionArg { pub(crate) span: Span, } +impl BlockArg { + pub fn name(&self) -> String { + self.field_type.name() + } +} #[derive(Debug, Clone)] -pub struct NamedFunctionArgList { +pub struct BlockArgs { pub(crate) documentation: Option, - pub args: Vec<(Identifier, FunctionArg)>, + pub args: Vec<(Identifier, BlockArg)>, pub(crate) span: Span, } -impl NamedFunctionArgList { +#[derive(Debug, Clone)] +pub enum ValueExprBlockType { + Function, + Client, + Generator, + RetryPolicy, + Test, +} + +impl BlockArgs { + pub fn flat_idns(&self) -> Vec<&Identifier> { + self.args + .iter() + .flat_map(|(_, arg)| arg.field_type.flat_idns()) + .filter_map(|f| match f { + Identifier::String(..) => None, + _ => Some(f), + }) + .collect() + } pub fn iter_args( &self, - ) -> impl ExactSizeIterator { + ) -> impl ExactSizeIterator { self.args .iter() .enumerate() - .map(|(id, arg)| (FuncArguementId(id as u32), arg)) - } -} - -#[derive(Debug, Clone)] -pub enum FunctionArgs { - Unnamed(FunctionArg), - Named(NamedFunctionArgList), -} - -impl FunctionArgs { - pub fn flat_idns(&self) -> Vec<&Identifier> { - match self { - FunctionArgs::Unnamed(arg) => arg - .field_type - .flat_idns() - .iter() - .filter_map(|f| match f { - Identifier::Primitive(..) => None, - _ => Some(*f), - }) - .collect(), - FunctionArgs::Named(named) => named - .args - .iter() - .flat_map(|(_, arg)| arg.field_type.flat_idns()) - .filter_map(|f| match f { - Identifier::Primitive(..) => None, - _ => Some(f), - }) - .collect(), - } + .map(|(id, arg)| (ArgumentId(id as u32), arg)) } } /// A model declaration. #[derive(Debug, Clone)] -pub struct Function { +pub struct ValueExprBlock { /// The name of the model. /// /// ```ignore @@ -130,8 +123,8 @@ pub struct Function { /// ^^^^^^^^^^^^ /// } /// ``` - pub(crate) input: FunctionArgs, - pub(crate) output: FunctionArgs, + pub(crate) input: Option, + pub(crate) output: Option, /// The documentation for this model. /// /// ```ignore @@ -159,73 +152,91 @@ pub struct Function { pub attributes: Vec, /// The location of this model in the text representation. pub(crate) span: Span, - pub fields: Vec, + pub fields: Vec>, + + pub block_type: ValueExprBlockType, } -impl Function { - pub fn input(&self) -> &FunctionArgs { - &self.input +impl ValueExprBlock { + pub fn input(&self) -> Option<&BlockArgs> { + match &self.input { + Some(input) => Some(input), + None => None, + } } - pub fn output(&self) -> &FunctionArgs { - &self.output + pub fn output(&self) -> Option<&BlockArg> { + match &self.output { + Some(output) => Some(output), + None => None, + } } pub fn iter_fields( &self, - ) -> impl ExactSizeIterator + Clone { + ) -> impl ExactSizeIterator)> + Clone { self.fields .iter() .enumerate() .map(|(idx, field)| (FieldId(idx as u32), field)) } - pub fn fields(&self) -> &[ConfigBlockProperty] { + pub fn fields(&self) -> &[Field] { &self.fields } + + pub fn get_type(&self) -> &'static str { + match &self.block_type { + ValueExprBlockType::RetryPolicy => "retry_policy", + ValueExprBlockType::Function => "function", + ValueExprBlockType::Client => "client", + ValueExprBlockType::Generator => "generator", + ValueExprBlockType::Test => "test", + } + } } -impl WithIdentifier for Function { +impl WithIdentifier for ValueExprBlock { fn identifier(&self) -> &Identifier { &self.name } } -impl WithSpan for Function { +impl WithSpan for ValueExprBlock { fn span(&self) -> &Span { &self.span } } -impl WithAttributes for Function { +impl WithAttributes for ValueExprBlock { fn attributes(&self) -> &[Attribute] { &self.attributes } } -impl WithDocumentation for Function { +impl WithDocumentation for ValueExprBlock { fn documentation(&self) -> Option<&str> { self.documentation.as_ref().map(|doc| doc.text.as_str()) } } -impl WithSpan for NamedFunctionArgList { +impl WithSpan for BlockArgs { fn span(&self) -> &Span { &self.span } } -impl WithSpan for FunctionArg { +impl WithSpan for BlockArg { fn span(&self) -> &Span { &self.span } } -impl WithDocumentation for NamedFunctionArgList { +impl WithDocumentation for BlockArgs { fn documentation(&self) -> Option<&str> { self.documentation.as_ref().map(|doc| doc.text.as_str()) } } -impl WithDocumentation for FunctionArg { +impl WithDocumentation for BlockArg { fn documentation(&self) -> Option<&str> { None } diff --git a/engine/baml-lib/schema-ast/src/ast/variant.rs b/engine/baml-lib/schema-ast/src/ast/variant.rs deleted file mode 100644 index 4af68a9dd..000000000 --- a/engine/baml-lib/schema-ast/src/ast/variant.rs +++ /dev/null @@ -1,171 +0,0 @@ -use super::{ - traits::WithAttributes, Adapter, Attribute, Comment, ConfigBlockProperty, Identifier, - Serializer, Span, WithDocumentation, WithIdentifier, WithSpan, -}; - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct FieldId(pub(super) u32); - -impl FieldId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: FieldId = FieldId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: FieldId = FieldId(u32::MAX); -} - -impl std::ops::Index for Variant { - type Output = ConfigBlockProperty; - - fn index(&self, index: FieldId) -> &Self::Output { - &self.fields[index.0 as usize] - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct AdapterId(pub(super) u32); - -impl AdapterId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: AdapterId = AdapterId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: AdapterId = AdapterId(u32::MAX); -} - -impl std::ops::Index for Variant { - type Output = Adapter; - - fn index(&self, index: AdapterId) -> &Self::Output { - &self.adapters[index.0 as usize] - } -} - -/// An opaque identifier for a field in an AST model. Use the -/// `model[field_id]` syntax to resolve the id to an `ast::Field`. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SerializerId(pub(super) u32); - -impl SerializerId { - /// Used for range bounds when iterating over BTreeMaps. - pub const MIN: SerializerId = SerializerId(0); - /// Used for range bounds when iterating over BTreeMaps. - pub const MAX: SerializerId = SerializerId(u32::MAX); -} - -impl std::ops::Index for Variant { - type Output = Serializer; - - fn index(&self, index: SerializerId) -> &Self::Output { - &self.serializers[index.0 as usize] - } -} - -/// A model declaration. -#[derive(Debug, Clone)] -pub struct Variant { - /// The name of the model. - /// - /// ```ignore - /// model Foo { .. } - /// ^^^ - /// ``` - pub(crate) name: Identifier, - /// The documentation for this model. - /// - /// ```ignore - /// /// Lorem ipsum - /// ^^^^^^^^^^^ - /// model Foo { - /// id Int @id - /// field String - /// } - /// ``` - pub(crate) documentation: Option, - /// The attributes of this model. - /// - /// ```ignore - /// model Foo { - /// id Int @id - /// field String - /// - /// @@index([field]) - /// ^^^^^^^^^^^^^^^^ - /// @@map("Bar") - /// ^^^^^^^^^^^^ - /// } - /// ``` - pub attributes: Vec, - - pub fields: Vec, - - pub serializers: Vec, - - pub adapters: Vec, - - pub(crate) variant_type: String, - - pub(crate) function_name: Identifier, - - /// The location of this model in the text representation. - pub(crate) span: Span, -} - -impl Variant { - pub fn iter_fields( - &self, - ) -> impl ExactSizeIterator + Clone { - self.fields - .iter() - .enumerate() - .map(|(idx, field)| (FieldId(idx as u32), field)) - } - - pub fn iter_serializers( - &self, - ) -> impl ExactSizeIterator + Clone { - self.serializers - .iter() - .enumerate() - .map(|(idx, field)| (SerializerId(idx as u32), field)) - } - - pub fn iter_adapters(&self) -> impl ExactSizeIterator + Clone { - self.adapters - .iter() - .enumerate() - .map(|(idx, field)| (AdapterId(idx as u32), field)) - } - - pub fn is_llm(&self) -> bool { - self.variant_type == "llm" - } - - pub fn function_name(&self) -> &Identifier { - &self.function_name - } -} - -impl WithIdentifier for Variant { - fn identifier(&self) -> &Identifier { - &self.name - } -} - -impl WithSpan for Variant { - fn span(&self) -> &Span { - &self.span - } -} - -impl WithAttributes for Variant { - fn attributes(&self) -> &[Attribute] { - &self.attributes - } -} - -impl WithDocumentation for Variant { - fn documentation(&self) -> Option<&str> { - self.documentation.as_ref().map(|doc| doc.text.as_str()) - } -} diff --git a/engine/baml-lib/schema-ast/src/parser.rs b/engine/baml-lib/schema-ast/src/parser.rs index 189f95ec6..82ec4c6a7 100644 --- a/engine/baml-lib/schema-ast/src/parser.rs +++ b/engine/baml-lib/schema-ast/src/parser.rs @@ -1,24 +1,16 @@ mod helpers; -mod parse_adapter; mod parse_arguments; mod parse_attribute; -mod parse_class; mod parse_comments; -mod parse_config; -mod parse_enum; mod parse_expression; mod parse_field; -mod parse_function; mod parse_identifier; -mod parse_old_function; +mod parse_named_args_list; mod parse_schema; -mod parse_serializer; -mod parse_template_args; mod parse_template_string; -mod parse_test; +mod parse_type_expression_block; mod parse_types; -mod parse_variant; - +mod parse_value_expression_block; pub use parse_schema::parse_schema; // The derive is placed here because it generates the `Rule` enum which is used in all parsing functions. diff --git a/engine/baml-lib/schema-ast/src/parser/datamodel.pest b/engine/baml-lib/schema-ast/src/parser/datamodel.pest index b7defb4a2..59d1386ea 100644 --- a/engine/baml-lib/schema-ast/src/parser/datamodel.pest +++ b/engine/baml-lib/schema-ast/src/parser/datamodel.pest @@ -1,116 +1,50 @@ schema = { - SOI ~ (interface_declaration | template_declaration | function_declaration | old_function_declaration | variant_block | config_block | enum_declaration | type_alias | arbitrary_block | comment_block | raw_string_literal | empty_lines | CATCH_ALL)* ~ EOI + SOI ~ (value_expression_block | type_expression_block | template_declaration | type_alias | comment_block | raw_string_literal | empty_lines | CATCH_ALL)* ~ EOI } -// a block definition without a keyword. Is not valid. Just acts as a catch for the parser to display a nice error. -arbitrary_block = { identifier ~ BLOCK_OPEN ~ ((!BLOCK_CLOSE ~ ANY) | NEWLINE)* ~ BLOCK_CLOSE } - // ###################################### -// Enum +// Unified Block for Class and Enum // ###################################### -enum_declaration = { - ENUM_KEYWORD ~ identifier ~ BLOCK_OPEN ~ enum_contents ~ BLOCK_CLOSE +type_expression_keyword = { ENUM_KEYWORD | CLASS_KEYWORD | identifier } +type_expression_block = { type_expression_keyword ~ identifier ~ named_argument_list? ~ BLOCK_OPEN ~ type_expression_contents ~ BLOCK_CLOSE } +type_expression_contents = { + (type_expression | block_attribute | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* } - -enum_value_declaration = { identifier ~ (NEWLINE? ~ (field_attribute | trailing_comment))* ~ NEWLINE } -enum_contents = { - (enum_value_declaration | block_attribute | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* +type_expression = { + identifier ~ field_type_chain? ~ (NEWLINE? ~ (field_attribute | trailing_comment))* ~ NEWLINE? } +field_operator = { "|" | "&" } +field_type_chain = { field_type_with_attr ~ (field_operator ~ field_type_with_attr)* } +field_type_with_attr = { field_type ~ (NEWLINE? ~ (field_attribute | trailing_comment))* } + // ###################################### -// Interface blocks are configs which only have types as values. +// Unified Block for Function, Test, Client, Generator // ###################################### - -interface_declaration = { - CLASS_KEYWORD ~ identifier ~ BLOCK_OPEN ~ class_contents ~ BLOCK_CLOSE +value_expression_keyword = { FUNCTION_KEYWORD | TEST_KEYWORD | CLIENT_KEYWORD | RETRY_POLICY_KEYWORD | GENERATOR_KEYWORD } +value_expression_block = { value_expression_keyword ~ identifier ~ named_argument_list? ~ ARROW? ~ field_type? ~ SPACER_TEXT ~ BLOCK_OPEN ~ value_expression_contents ~ BLOCK_CLOSE } +value_expression_contents = { + (value_expression | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* } +value_expression = { identifier ~ expression? ~ (NEWLINE? ~ field_attribute)* ~ trailing_comment? } -field_declaration = { - identifier ~ field_type? ~ ((NEWLINE? ~ field_attribute) | (NEWLINE? ~ trailing_comment))* ~ NEWLINE -} +// ###################################### +ARROW = { SPACER_TEXT ~ "->" ~ SPACER_TEXT } -class_contents = { - (field_declaration | (block_attribute ~ NEWLINE) | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} // ###################################### -// Interface blocks are configs which only have types as values. +// Template Declaration // ###################################### -ARROW = { SPACER_TEXT ~ "->" ~ SPACER_TEXT } -function_declaration = { - FUNCTION_KEYWORD ~ identifier ~ named_argument_list ~ ARROW? ~ field_type? ~ SPACER_TEXT ~ BLOCK_OPEN ~ function_contents ~ BLOCK_CLOSE -} - -template_declaration = { - TEMPLATE_KEYWORD ~ identifier ~ named_argument_list? ~ raw_string_literal -} - -function_contents = { - (key_value | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} +assignment = { "=" } +template_declaration = { TEMPLATE_KEYWORD ~ identifier ~ assignment? ~ named_argument_list? ~ raw_string_literal } -old_function_declaration = { - FUNCTION_KEYWORD ~ identifier ~ BLOCK_OPEN ~ old_function_contents ~ BLOCK_CLOSE -} - -input_field_declaration = { - "input" ~ function_field_type? ~ trailing_comment? ~ NEWLINE -} - -output_field_declaration = { - "output" ~ function_field_type? ~ trailing_comment? ~ NEWLINE -} - -function_field_type = { field_type | named_argument_list } -old_function_contents = { - (input_field_declaration | output_field_declaration | (key_value ~ NEWLINE) | (block_attribute ~ NEWLINE) | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} colon = { ":" } named_argument = { identifier ~ ((":" ~ field_type) | colon)? } // Be forgiving and allow trailing comma -named_argument_list = { "(" ~ SPACER_TEXT ~ named_argument? ~ ("," ~ SPACER_TEXT ~ named_argument)* ~ ","? ~ SPACER_TEXT ~ ")" } - -// ###################################### -// Configuration blocks (generators, clients are syntactically identical) -// The value of each key is an expression. -// ###################################### - -serializer_block = { - SERIALIZER_KEYWORD ~ identifier ~ BLOCK_OPEN ~ serializer_contents ~ BLOCK_CLOSE -} +named_argument_list = { openParan ~ SPACER_TEXT ~ named_argument? ~ ("," ~ SPACER_TEXT ~ named_argument)* ~ ","? ~ SPACER_TEXT ~ closeParan } -serializer_field = { identifier ~ ((NEWLINE? ~ field_attribute) | (NEWLINE? ~ trailing_comment))* ~ NEWLINE } -serializer_contents = { - (serializer_field | (block_attribute ~ NEWLINE) | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} - -variant_block = { - VARIANT_KEYWORD ~ template_args? ~ identifier ~ BLOCK_OPEN ~ variant_contents ~ BLOCK_CLOSE -} - -adapter_block = { - "adapter" ~ field_template_args? ~ expression? ~ NEWLINE? -} - -variant_contents = { - (serializer_block | adapter_block | (key_value ~ NEWLINE) | (block_attribute ~ NEWLINE) | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} - -// ###################################### -// Configuration blocks (generators, clients are syntactically identical) -// The value of each key is an expression. -// ###################################### -config_block = { - (TEST_KEYWORD | CLIENT_KEYWORD | GENERATOR_KEYWORD | RETRY_POLICY_KEYWORD | PRINTER_KEYWORD) ~ template_args? ~ identifier ~ BLOCK_OPEN ~ config_contents ~ BLOCK_CLOSE -} - -key_value = { identifier ~ template_args? ~ expression? ~ (NEWLINE? ~ field_attribute)* ~ trailing_comment? } - -config_contents = { - ((key_value ~ NEWLINE) | (block_attribute ~ NEWLINE) | comment_block | empty_lines | BLOCK_LEVEL_CATCH_ALL)* -} // ###################################### // Attributes @@ -118,27 +52,30 @@ config_contents = { block_attribute = { "@@" ~ identifier ~ arguments_list? } field_attribute = { "@" ~ identifier ~ arguments_list? } -// ###################################### -// Field Type -// ###################################### // Pest is greedy, order is very important here. -field_type = { (union | non_union) ~ optional_token? } +field_type = { (union | non_union ) ~ optional_token? } optional_token = { "?" } -union = { base_type ~ ("|" ~ base_type)+ } -base_type = { array_notation | map | identifier | group | tuple } +union = { base_type_with_attr ~ (field_operator ~ base_type_with_attr)+ } +base_type_with_attr = { base_type ~ (NEWLINE? ~ field_attribute)* } +base_type = { array_notation | map | identifier | group | tuple | parenthesized_type } -array_suffix = { "[]" } +array_suffix = { "[]" } array_notation = { base_type_without_array ~ array_suffix+ } -map = { "map" ~ "<" ~ field_type ~ "," ~ field_type ~ ">" } -group = { "(" ~ field_type ~ ")" } -tuple = { "(" ~ field_type ~ ("," ~ field_type)+ ~ ")" } +map = { "map" ~ "<" ~ field_type ~ "," ~ field_type ~ ">" } + +openParan = { "(" } +closeParan = { ")" } +group = { openParan ~ field_type ~closeParan } +tuple = { openParan ~ field_type ~ ("," ~ field_type)+ ~ closeParan } base_type_without_array = { map | identifier | group | tuple } non_union = { array_notation | map | identifier | group | tuple } +parenthesized_type = {openParan ~ field_type_with_attr ~ closeParan } + path_identifier = { single_word ~ ("." ~ single_word)+ } identifier = { path_identifier | single_word } single_word = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_" | "-")* } @@ -161,7 +98,7 @@ map_entry = { (comment_block | empty_lines)* ~ map_key ~ expression ~ tr splitter = _{ ("," ~ NEWLINE?) | NEWLINE } map_expression = { "{" ~ empty_lines? ~ (map_entry ~ (splitter ~ map_entry)*)? ~ (comment_block | empty_lines)* ~ "}" } array_expression = { "[" ~ empty_lines? ~ (expression ~ trailing_comment? ~ (splitter ~ (comment_block | empty_lines)* ~ expression ~ trailing_comment?)*)? ~ (comment_block | empty_lines)* ~ "]" } -expression = { map_expression | array_expression | numeric_literal | string_literal } +expression = { map_expression | array_expression | numeric_literal | string_literal | identifier } // ###################################### // Literals / Values @@ -177,6 +114,7 @@ banned_end_chars = { WHITESPACE | banned_chars } unquoted_string_literal = { (!banned_start_chars ~ ANY) ~ (!banned_chars ~ ANY)* ~ (!banned_end_chars ~ ANY)* } quoted_string_content = @{ (!"\"" ~ !NEWLINE ~ ANY)* } quoted_string_literal = ${ "\"" ~ quoted_string_content ~ "\"" } + // TODO: Support comments in raw string literals raw_string_literal_content_1 = @{ (!"\"#" ~ ANY)* } raw_string_literal_content_2 = @{ (!"\"##" ~ ANY)* } @@ -208,6 +146,7 @@ unterminated_quoted_string_literal = ${ "\"" ~ quoted_string_content } unterminated_string_literal = ${ unterminated_raw_string_literal | unterminated_quoted_string_literal } string_literal = { raw_string_literal | quoted_string_literal | unquoted_string_literal | unterminated_string_literal } + // ###################################### // Comments and Documentation Comments // ###################################### @@ -229,7 +168,6 @@ empty_lines = @{ (WHITESPACE* ~ NEWLINE)+ } // ###################################### // Utilities // ###################################### - SPACER_TEXT = { (comment_block | empty_lines)* } // the any part is to not crash on comments next to an open block, see test `parse_comments_without_crasing_or_loosing_info` @@ -245,15 +183,6 @@ CLASS_KEYWORD = { "class" } FUNCTION_KEYWORD = { "function" } TEMPLATE_KEYWORD = { "template_string" | "string_template" } TEST_KEYWORD = { "test" } - -empty_template_args = ${ "<" ~ ">" } -template_args = { empty_template_args | ("<" ~ expression ~ ("," ~ expression)* ~ ">") } - -field_template_args = { empty_template_args | ("<" ~ field_type ~ ("," ~ field_type)* ~ ">") } - -RETRY_POLICY_KEYWORD = { "retry_policy" } -CLIENT_KEYWORD = { "client" } +CLIENT_KEYWORD = { "client" | "client" } GENERATOR_KEYWORD = { "generator" } -VARIANT_KEYWORD = { "impl" } -SERIALIZER_KEYWORD = { "override" } -PRINTER_KEYWORD = { "printer" } +RETRY_POLICY_KEYWORD = { "retry_policy" } \ No newline at end of file diff --git a/engine/baml-lib/schema-ast/src/parser/helpers.rs b/engine/baml-lib/schema-ast/src/parser/helpers.rs index b8fd784c2..dcc2ec70d 100644 --- a/engine/baml-lib/schema-ast/src/parser/helpers.rs +++ b/engine/baml-lib/schema-ast/src/parser/helpers.rs @@ -3,7 +3,7 @@ use super::Rule; pub type Pair<'a> = pest::iterators::Pair<'a, Rule>; #[track_caller] -pub fn parsing_catch_all(token: &Pair<'_>, kind: &str) { +pub fn parsing_catch_all(token: Pair<'_>, kind: &str) { match token.as_rule() { Rule::empty_lines | Rule::trailing_comment diff --git a/engine/baml-lib/schema-ast/src/parser/parse_adapter.rs b/engine/baml-lib/schema-ast/src/parser/parse_adapter.rs deleted file mode 100644 index 6378dfc10..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_adapter.rs +++ /dev/null @@ -1,114 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_expression::parse_expression, - Rule, -}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -use crate::{ - assert_correct_parser, - ast::{Adapter, FieldType}, - parser::parse_types::parse_field_type, -}; - -pub fn parse_adapter( - pair: Pair<'_>, - _doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Option { - assert_correct_parser!(pair, Rule::adapter_block); - - let mut types = None; - let mut expr = None; - - let mut span = diagnostics.span(pair.as_span()); - - for item in pair.into_inner() { - match item.as_rule() { - Rule::field_template_args => { - span = diagnostics.span(item.as_span()); - types = parse_field_template_args(item, diagnostics); - } - Rule::expression => { - expr = Some(parse_expression(item, diagnostics)); - } - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - - match (types, expr) { - (Some((from, to)), Some(expr)) => { - if from == to { - diagnostics.push_error(DatamodelError::new_validation_error( - "The adapter's input and output types must be different.", - span, - )); - return None; - } - Some(Adapter { - from, - to, - converter: expr, - span, - }) - } - (None, _) => { - diagnostics.push_error(DatamodelError::new_validation_error( - "An adapter must have 2 template args.", - span, - )); - None - } - (_, None) => { - diagnostics.push_error(DatamodelError::new_validation_error( - "An adapter must have an expression.", - span, - )); - None - } - } -} - -fn parse_field_template_args( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Option<(FieldType, FieldType)> { - assert_correct_parser!(pair, Rule::field_template_args); - - let mut fields = vec![]; - let span = diagnostics.span(pair.as_span()); - - for item in pair.into_inner() { - match item.as_rule() { - Rule::field_type => { - if let Some(f) = parse_field_type(item, diagnostics) { - fields.push(f) - } - } - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - - match fields.len() { - 2 => Some((fields[0].clone(), fields[1].clone())), - other => { - diagnostics.push_error(DatamodelError::new_validation_error( - &format!("An adapter only has 2 template args, but found {}.", other), - span, - )); - None - } - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_arguments.rs b/engine/baml-lib/schema-ast/src/parser/parse_arguments.rs index 9975a50a3..510825d64 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_arguments.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_arguments.rs @@ -22,7 +22,7 @@ pub(crate) fn parse_arguments_list( value: parse_expression(current, diagnostics), span: diagnostics.span(current_span), }), - _ => parsing_catch_all(¤t, "attribute arguments"), + _ => parsing_catch_all(current, "attribute arguments"), } } } diff --git a/engine/baml-lib/schema-ast/src/parser/parse_attribute.rs b/engine/baml-lib/schema-ast/src/parser/parse_attribute.rs index d01b929f7..99c47915b 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_attribute.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_attribute.rs @@ -21,7 +21,7 @@ pub(crate) fn parse_attribute( Rule::arguments_list => { parse_arguments_list(current, &mut arguments, &name, diagnostics) } - _ => parsing_catch_all(¤t, "attribute"), + _ => parsing_catch_all(current, "attribute"), } } diff --git a/engine/baml-lib/schema-ast/src/parser/parse_class.rs b/engine/baml-lib/schema-ast/src/parser/parse_class.rs deleted file mode 100644 index 10adf0d7b..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_class.rs +++ /dev/null @@ -1,71 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_field::parse_field, - parse_identifier::parse_identifier, - Rule, -}; -use crate::{assert_correct_parser, ast::*}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub(crate) fn parse_class( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Class { - assert_correct_parser!(pair, Rule::interface_declaration); - - let pair_span = pair.as_span(); - let mut name: Option = None; - let mut attributes: Vec = Vec::new(); - let mut fields: Vec = Vec::new(); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::CLASS_KEYWORD | Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::class_contents => { - let mut pending_field_comment: Option> = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)); - } - Rule::field_declaration => match parse_field( - &name, - "class", - item, - pending_field_comment.take(), - diagnostics, - ) { - Ok(field) => fields.push(field), - Err(err) => diagnostics.push_error(err), - }, - Rule::comment_block => pending_field_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition. A valid class property looks like: 'myProperty string[] @description(\"This is a description\")'", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "class"), - } - } - } - _ => parsing_catch_all(¤t, "model"), - } - } - - match name { - Some(name) => Class { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span: diagnostics.span(pair_span), - }, - _ => panic!("Encountered impossible model declaration during parsing",), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_comments.rs b/engine/baml-lib/schema-ast/src/parser/parse_comments.rs index 5a1b5f1bb..f193239df 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_comments.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_comments.rs @@ -11,7 +11,7 @@ pub(crate) fn parse_comment_block(token: Pair<'_>) -> Option { match comment.as_rule() { Rule::doc_comment => lines.push(parse_doc_comment(comment)), Rule::comment | Rule::NEWLINE | Rule::WHITESPACE => {} - _ => parsing_catch_all(&comment, "comment block"), + _ => parsing_catch_all(comment, "comment block"), } } @@ -31,7 +31,7 @@ pub(crate) fn parse_trailing_comment(pair: Pair<'_>) -> Option { match current.as_rule() { Rule::doc_comment => lines.push(parse_doc_comment(current)), Rule::comment | Rule::NEWLINE | Rule::WHITESPACE => {} - _ => parsing_catch_all(¤t, "trailing comment"), + _ => parsing_catch_all(current, "trailing comment"), } } diff --git a/engine/baml-lib/schema-ast/src/parser/parse_config.rs b/engine/baml-lib/schema-ast/src/parser/parse_config.rs deleted file mode 100644 index 221f5a44f..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_config.rs +++ /dev/null @@ -1,202 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_expression::parse_expression, - parse_identifier::parse_identifier, - parse_template_args::parse_template_args, - Rule, -}; -use crate::{assert_correct_parser, ast::*, unreachable_rule}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub(crate) fn parse_config_block( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let pair_span = pair.as_span(); - let mut template_args = None; - let mut name: Option = None; - let mut attributes: Vec = Vec::new(); - let mut fields: Vec = Vec::new(); - let mut kw = None; - - for current in pair.into_inner() { - match current.as_rule() { - Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} - Rule::template_args => template_args = parse_template_args(current, diagnostics), - Rule::config_contents => { - let mut pending_field_comment: Option> = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)); - } - Rule::key_value => { - fields.push(parse_key_value( - item, - pending_field_comment.take(), - diagnostics, - )); - } - Rule::comment_block => pending_field_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition. A valid property may look like: 'myProperty \"some value\"' for example, with no colons.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - } - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::TEST_KEYWORD - | Rule::PRINTER_KEYWORD - | Rule::RETRY_POLICY_KEYWORD - | Rule::GENERATOR_KEYWORD - | Rule::CLIENT_KEYWORD => kw = Some(current.as_str()), - _ => parsing_catch_all(¤t, "client"), - } - } - - let span = match kw { - Some(_) => diagnostics.span(pair_span), - _ => unreachable!("Encountered impossible model declaration during parsing"), - }; - - match (kw, name, template_args) { - (Some("printer"), _, None) => Err(DatamodelError::new_validation_error( - "Missing template for printer. (did you forget or )", - span, - )), - (Some("printer"), Some(name), Some(args)) => match args.len() { - 1 => Ok(Top::Config(Configuration::Printer(PrinterConfig { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span, - printer_type: args.first().unwrap().to_owned(), - }))), - _ => Err(DatamodelError::new_validation_error( - "printer requires 1 template args. (did you forget or )", - span, - )), - }, - (Some("client"), _, None) => Err(DatamodelError::new_validation_error( - "Missing template for client. (did you forget )", - span, - )), - (Some("client"), Some(name), Some(args)) => match args.len() { - 1 => Ok(Top::Client(Client { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span, - client_type: args.first().unwrap().to_string(), - })), - _ => Err(DatamodelError::new_validation_error( - "client requires 1 template args. (did you forget )", - span, - )), - }, - (Some("retry_policy"), _, Some(_)) => Err(DatamodelError::new_validation_error( - "Template arguments are not allowed for retry_policy.", - span, - )), - (Some("retry_policy"), Some(name), None) => { - Ok(Top::Config(Configuration::RetryPolicy(RetryPolicyConfig { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span, - }))) - } - (Some("generator"), _, Some(_)) => Err(DatamodelError::new_validation_error( - "Template arguments are not allowed for generators.", - span, - )), - (Some("generator"), Some(name), None) => Ok(Top::Generator(GeneratorConfig { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span, - })), - (Some("test"), _, Some(_)) => Err(DatamodelError::new_validation_error( - "Template arguments are not allowed for test.", - span, - )), - (Some("test"), None, None) => Err(DatamodelError::new_validation_error( - "Missing name for test.", - span, - )), - (Some("test"), Some(name), None) => { - Ok(Top::Config(Configuration::TestCase(RetryPolicyConfig { - name, - fields, - attributes, - documentation: doc_comment.and_then(parse_comment_block), - span, - }))) - } - _ => unreachable!("Encountered impossible model declaration during parsing",), - } -} - -pub(crate) fn parse_key_value( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> ConfigBlockProperty { - assert_correct_parser!(pair, Rule::key_value); - - let mut name: Option = None; - let mut value: Option = None; - let mut attributes = Vec::new(); - let mut comment: Option = doc_comment.and_then(parse_comment_block); - let mut template_args = None; - let (pair_span, pair_str) = (pair.as_span(), pair.as_str()); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::identifier => { - name = Some(parse_identifier(current, diagnostics)); - } - Rule::field_attribute => attributes.push(parse_attribute(current, diagnostics)), - Rule::expression => value = Some(parse_expression(current, diagnostics)), - Rule::trailing_comment => { - comment = match (comment, parse_trailing_comment(current)) { - (c, None) | (None, c) => c, - (Some(existing), Some(new)) => Some(Comment { - text: [existing.text, new.text].join("\n"), - }), - }; - } - Rule::template_args => { - template_args = parse_template_args(current, diagnostics); - } - _ => unreachable_rule!(current, Rule::key_value), - } - } - - match name { - Some(name) => ConfigBlockProperty { - name, - template_args, - value, - attributes, - span: diagnostics.span(pair_span), - documentation: comment, - }, - _ => unreachable!( - "Encountered impossible source property declaration during parsing: {:?}", - pair_str, - ), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_enum.rs b/engine/baml-lib/schema-ast/src/parser/parse_enum.rs deleted file mode 100644 index bb3f697ab..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_enum.rs +++ /dev/null @@ -1,107 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_identifier::parse_identifier, - Rule, -}; -use crate::ast::{Attribute, Comment, Enum, EnumValue, Identifier}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub fn parse_enum( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Enum { - let comment: Option = doc_comment.and_then(parse_comment_block); - let pair_span = pair.as_span(); - let mut name: Option = None; - let mut attributes: Vec = vec![]; - let mut values: Vec = vec![]; - let pairs = pair.into_inner().peekable(); - - for current in pairs { - match current.as_rule() { - Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE | Rule::ENUM_KEYWORD => {} - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::enum_contents => { - let mut pending_value_comment = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)) - } - Rule::enum_value_declaration => { - match parse_enum_value(item, pending_value_comment.take(), diagnostics) - { - Ok(enum_value) => values.push(enum_value), - Err(err) => diagnostics.push_error(err), - } - } - Rule::comment_block => pending_value_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not an enum value definition. BAML enums don't have commas, and all values must be all caps", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "enum"), - } - } - } - _ => parsing_catch_all(¤t, "enum"), - } - } - - match name { - Some(name) => Enum { - name, - values, - attributes, - documentation: comment, - span: diagnostics.span(pair_span), - }, - _ => panic!("Encountered impossible enum declaration during parsing, name is missing.",), - } -} - -fn parse_enum_value( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let (pair_str, pair_span) = (pair.as_str(), pair.as_span()); - let mut name: Option = None; - let mut attributes: Vec = vec![]; - let mut comment: Option = doc_comment.and_then(parse_comment_block); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::field_attribute => attributes.push(parse_attribute(current, diagnostics)), - Rule::trailing_comment => { - comment = match (comment, parse_trailing_comment(current)) { - (None, a) | (a, None) => a, - (Some(a), Some(b)) => Some(Comment { - text: [a.text, b.text].join("\n"), - }), - }; - } - Rule::comment_block => { - parse_comment_block(current); - } - _ => parsing_catch_all(¤t, "enum value"), - } - } - - match name { - Some(name) => Ok(EnumValue { - name, - attributes, - documentation: comment, - span: diagnostics.span(pair_span), - }), - _ => panic!("Encountered impossible enum value declaration during parsing, name is missing: {pair_str:?}",), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_expression.rs b/engine/baml-lib/schema-ast/src/parser/parse_expression.rs index 3171b755b..b6f7bfb54 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_expression.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_expression.rs @@ -17,6 +17,7 @@ pub(crate) fn parse_expression( Rule::string_literal => parse_string_literal(first_child, diagnostics), Rule::map_expression => parse_map(first_child, diagnostics), Rule::array_expression => parse_array(first_child, diagnostics), + Rule::identifier => Expression::Identifier(parse_identifier(first_child, diagnostics)), _ => unreachable_rule!(first_child, Rule::expression), } } @@ -28,7 +29,7 @@ fn parse_array(token: Pair<'_>, diagnostics: &mut Diagnostics) -> Expression { for current in token.into_inner() { match current.as_rule() { Rule::expression => elements.push(parse_expression(current, diagnostics)), - _ => parsing_catch_all(¤t, "array"), + _ => parsing_catch_all(current, "array"), } } @@ -85,7 +86,7 @@ fn parse_map(token: Pair<'_>, diagnostics: &mut Diagnostics) -> Expression { entries.push(f) } } - _ => parsing_catch_all(¤t, "map key value"), + _ => parsing_catch_all(current, "map key value"), } } @@ -105,7 +106,7 @@ fn parse_map_entry( match current.as_rule() { Rule::map_key => key = Some(parse_map_key(current, diagnostics)), Rule::expression => value = Some(parse_expression(current, diagnostics)), - _ => parsing_catch_all(¤t, "dict entry"), + _ => parsing_catch_all(current, "dict entry"), } } diff --git a/engine/baml-lib/schema-ast/src/parser/parse_field.rs b/engine/baml-lib/schema-ast/src/parser/parse_field.rs index 77624a108..502d2ad7f 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_field.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_field.rs @@ -2,6 +2,7 @@ use super::{ helpers::{parsing_catch_all, Pair}, parse_attribute::parse_attribute, parse_comments::*, + parse_expression::parse_expression, parse_identifier::parse_identifier, parse_types::parse_field_type, Rule, @@ -9,13 +10,13 @@ use super::{ use crate::ast::*; use internal_baml_diagnostics::{DatamodelError, Diagnostics}; -pub(crate) fn parse_field( +pub(crate) fn parse_expr_as_value( model_name: &Option, container_type: &'static str, pair: Pair<'_>, block_comment: Option>, diagnostics: &mut Diagnostics, -) -> Result { +) -> Result, DatamodelError> { let pair_span = pair.as_span(); let mut name: Option = None; let mut attributes: Vec = Vec::new(); @@ -25,7 +26,6 @@ pub(crate) fn parse_field( for current in pair.into_inner() { match current.as_rule() { Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::field_type => field_type = parse_field_type(current, diagnostics), Rule::field_attribute => { attributes.push(parse_attribute(current, diagnostics)); } @@ -37,23 +37,180 @@ pub(crate) fn parse_field( }), }; } - _ => parsing_catch_all(¤t, "field"), + Rule::expression => field_type = Some(parse_expression(current, diagnostics)), + + _ => parsing_catch_all(current, "field"), } } match (name, field_type) { (Some(name), Some(field_type)) => Ok(Field { - field_type, + expr: Some(field_type), name, attributes, documentation: comment, span: diagnostics.span(pair_span), }), _ => Err(DatamodelError::new_model_validation_error( - "This field declaration is invalid. It is either missing a name or a type.", + "expr as val!! This field declaration is invalid. It is either missing a name or a type.", + container_type, + model_name.as_ref().map_or("", |f| f.name()), + diagnostics.span(pair_span), + )), + } +} + +pub(crate) fn parse_expr_as_type( + model_name: &Option, + container_type: &'static str, + pair: Pair<'_>, + block_comment: Option>, + diagnostics: &mut Diagnostics, + is_enum: bool, +) -> Result, DatamodelError> { + let pair_span = pair.as_span(); + let mut name: Option = None; + let mut enum_attributes = Vec::::new(); + let mut field_type = None; + let mut comment: Option = block_comment.and_then(parse_comment_block); + + for current in pair.into_inner() { + match current.as_rule() { + Rule::identifier => name = Some(parse_identifier(current, diagnostics)), + Rule::trailing_comment => { + comment = merge_comments(comment, parse_trailing_comment(current)); + } + Rule::field_type_chain => { + if !is_enum { + field_type = parse_field_type_chain(current, diagnostics); + } + } + Rule::field_attribute => enum_attributes.push(parse_attribute(current, diagnostics)), + _ => parsing_catch_all(current, "field"), + } + } + + match (name, field_type) { + (Some(name), Some(field_type)) => { + + Ok(Field { + expr: Some(field_type.clone()), + name, + attributes: field_type.attributes().to_vec(), + documentation: comment, + span: diagnostics.span(pair_span), + }) + }, + (Some(name), None) => { + + Ok(Field { + expr: None, + name, + attributes: enum_attributes, + documentation: comment, + span: diagnostics.span(pair_span), + }) + }, + _ => Err(DatamodelError::new_model_validation_error( + "expr as type!! This field declaration is invalid. It is either missing a name or a type.", container_type, model_name.as_ref().map_or("", |f| f.name()), diagnostics.span(pair_span), )), } } + +fn merge_comments(existing: Option, new: Option) -> Option { + match (existing, new) { + (Some(existing), Some(new)) => Some(Comment { + text: format!("{}\n{}", existing.text, new.text), + }), + (existing, None) | (None, existing) => existing, + } +} + +fn parse_field_type_chain(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { + let mut types = Vec::new(); + let mut operators = Vec::new(); + + for current in pair.into_inner() { + match current.as_rule() { + Rule::field_type_with_attr => { + if let Some(field_type) = parse_field_type_with_attr(current, diagnostics) { + types.push(field_type); + } + } + Rule::field_operator => operators.push(current.as_str().to_string()), + _ => parsing_catch_all(current, "field_type_chain"), + } + } + + //do not need to pass in operators, as the only operator we can have is of union (|) type, so we handle this implicitly in the combine_field_types function + combine_field_types(types) +} + +fn parse_field_type_with_attr(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { + let mut field_type = None; + let mut field_attributes = Vec::new(); + + for current in pair.into_inner() { + match current.as_rule() { + Rule::field_type => field_type = parse_field_type(current, diagnostics), + Rule::field_type_with_attr => {} + Rule::field_attribute => field_attributes.push(parse_attribute(current, diagnostics)), + Rule::trailing_comment => {} + _ => { + parsing_catch_all(current, "field_type_with_attr!"); + } + } + } + + match field_type { + Some(mut ft) => { + ft.set_attributes(field_attributes); + + Some(ft) // Return the field type with attributes + } + None => { + log::info!("field_type is None"); + None + } + } +} +fn combine_field_types(types: Vec) -> Option { + if types.is_empty() { + return None; + } + + let mut combined_type = types[0].clone(); + + let mut seen_types = vec![combined_type.clone()]; + + let mut earliest_start = combined_type.span().start; + let mut latest_end = combined_type.span().end; + + for next_type in types.into_iter().skip(1) { + seen_types.push(next_type.clone()); + + let span = next_type.span(); + if span.start < earliest_start { + earliest_start = span.start; + } + if span.end > latest_end { + latest_end = span.end; + } + + combined_type = FieldType::Union( + FieldArity::Required, + seen_types.clone(), + Span { + file: combined_type.span().file.clone(), + start: earliest_start, + end: latest_end, + }, + None, + ); + } + + Some(combined_type) +} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_function.rs b/engine/baml-lib/schema-ast/src/parser/parse_function.rs deleted file mode 100644 index a04f5d022..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_function.rs +++ /dev/null @@ -1,199 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_config::parse_key_value, - parse_identifier::parse_identifier, - Rule, -}; -use crate::{assert_correct_parser, ast::*, parser::parse_types::parse_field_type}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub(crate) fn parse_function( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let pair_span = pair.as_span(); - let mut name: Option = None; - let mut attributes: Vec = Vec::new(); - let mut input = None; - let mut output = None; - let mut fields = vec![]; - let mut has_arrow = false; - - for current in pair.into_inner() { - match current.as_rule() { - Rule::FUNCTION_KEYWORD | Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} - Rule::ARROW => { - has_arrow = true; - } - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::named_argument_list => match parse_named_arguement_list(current, diagnostics) { - Ok(FunctionArgs::Named(arg)) => input = Some(FunctionArgs::Named(arg)), - Ok(FunctionArgs::Unnamed(arg)) => { - diagnostics.push_error(DatamodelError::new_validation_error( - "Unnamed arguments are not supported for function input. Define a new class instead.", - arg.span, - )) - } - Err(err) => diagnostics.push_error(err), - }, - Rule::field_type => { - match parse_function_arg(current, diagnostics) { - Ok(arg) => output = Some(FunctionArgs::Unnamed(arg)), - Err(err) => diagnostics.push_error(err), - } - } - Rule::function_contents => { - let mut pending_field_comment: Option> = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)); - } - Rule::key_value => { - fields.push(parse_key_value( - item, - pending_field_comment.take(), - diagnostics, - )); - } - Rule::comment_block => pending_field_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - } - _ => parsing_catch_all(¤t, "function"), - } - } - - let response = match name { - Some(name) => { - let msg = match (input, output) { - (Some(input), Some(output)) => { - if has_arrow { - return Ok(Function { - name, - input, - output, - attributes, - fields, - documentation: doc_comment.and_then(parse_comment_block), - span: diagnostics.span(pair_span), - }); - } else { - "Invalid function syntax." - } - } - (Some(_), None) => "No return type specified.", - (None, Some(_)) => "No input parameters specified.", - _ => "Invalid function syntax.", - }; - (msg, Some(name.name().to_string())) - } - None => ("Invalid function syntax.", None), - }; - - Err(DatamodelError::new_model_validation_error( - format!( - r##"{} Valid function syntax is -``` -function {}(param1: String, param2: String) -> ReturnType {{ - client SomeClient - prompt #"..."# -}} -```"##, - response.0, - response.1.as_deref().unwrap_or("MyFunction") - ) - .as_str(), - "function", - response.1.as_deref().unwrap_or(""), - diagnostics.span(pair_span), - )) -} - -fn parse_named_arguement_list( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::named_argument_list, - "parse_named_arguement_list called on the wrong rule: {:?}", - pair.as_rule() - ); - let span = diagnostics.span(pair.as_span()); - let mut args: Vec<(Identifier, FunctionArg)> = Vec::new(); - for named_arg in pair.into_inner() { - if matches!(named_arg.as_rule(), Rule::SPACER_TEXT) { - continue; - } - assert_correct_parser!(named_arg, Rule::named_argument); - - let mut name = None; - let mut r#type = None; - for arg in named_arg.into_inner() { - match arg.as_rule() { - Rule::identifier => { - name = Some(parse_identifier(arg, diagnostics)); - } - Rule::colon => {} - Rule::field_type => { - r#type = Some(parse_function_arg(arg, diagnostics)?); - } - _ => parsing_catch_all(&arg, "named_argument_list"), - } - } - - match (name, r#type) { - (Some(name), Some(r#type)) => args.push((name, r#type)), - (Some(name), None) => diagnostics.push_error(DatamodelError::new_validation_error( - &format!( - "No type specified for argument: {name}. Expected: `{name}: type`", - name = name.name() - ), - name.span().clone(), - )), - (None, _) => { - unreachable!("parse_function_field_type: unexpected rule:") - } - } - } - - Ok(FunctionArgs::Named(NamedFunctionArgList { - documentation: None, - args, - span, - })) -} - -fn parse_function_arg( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::field_type, - "parse_function_arg called on the wrong rule: {:?}", - pair.as_rule() - ); - let span = diagnostics.span(pair.as_span()); - - match parse_field_type(pair, diagnostics) { - Some(ftype) => Ok(FunctionArg { - span, - field_type: ftype, - }), - None => Err(DatamodelError::new_validation_error( - "Failed to find type", - span, - )), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_named_args_list.rs b/engine/baml-lib/schema-ast/src/parser/parse_named_args_list.rs new file mode 100644 index 000000000..18dcb0485 --- /dev/null +++ b/engine/baml-lib/schema-ast/src/parser/parse_named_args_list.rs @@ -0,0 +1,97 @@ +use internal_baml_diagnostics::Diagnostics; + +use super::{ + helpers::parsing_catch_all, parse_identifier::parse_identifier, parse_types::parse_field_type, +}; +use crate::{ + assert_correct_parser, + ast::{BlockArg, BlockArgs, Identifier, WithName, WithSpan}, + parser::Rule, +}; +use internal_baml_diagnostics::DatamodelError; // Add this line + +use super::helpers::Pair; + +pub(crate) fn parse_named_argument_list( + pair: Pair<'_>, + diagnostics: &mut Diagnostics, +) -> Result { + assert!( + pair.as_rule() == Rule::named_argument_list, + "parse_named_argument_list called on the wrong rule: {:?}", + pair.as_rule() + ); + let span = diagnostics.span(pair.as_span()); + let mut args: Vec<(Identifier, BlockArg)> = Vec::new(); + for named_arg in pair.into_inner() { + if matches!(named_arg.as_rule(), Rule::SPACER_TEXT) { + continue; + } + if named_arg.as_rule() == Rule::named_argument || named_arg.as_rule() == Rule::openParan { + assert_correct_parser!(named_arg, named_arg.as_rule()); + } + // assert_correct_parser!(named_arg, Rule::named_argument); + + if named_arg.as_rule() == Rule::openParan || named_arg.as_rule() == Rule::closeParan { + continue; + } + + let mut name = None; + let mut r#type = None; + for arg in named_arg.into_inner() { + match arg.as_rule() { + Rule::identifier => { + name = Some(parse_identifier(arg, diagnostics)); + } + Rule::colon => {} + Rule::field_type => { + r#type = Some(parse_function_arg(arg, diagnostics)?); + } + _ => parsing_catch_all(arg, "named_argument_list"), + } + } + + match (name, r#type) { + (Some(name), Some(r#type)) => args.push((name, r#type)), + (Some(name), None) => diagnostics.push_error(DatamodelError::new_validation_error( + &format!( + "No type specified for argument: {name}. Expected: `{name}: type`", + name = name.name() + ), + name.span().clone(), + )), + (None, _) => { + unreachable!("parse_named_args_list:, none for name of field/missing type") + } + } + } + + Ok(BlockArgs { + documentation: None, + args, + span, + }) +} + +pub fn parse_function_arg( + pair: Pair<'_>, + diagnostics: &mut Diagnostics, +) -> Result { + assert!( + pair.as_rule() == Rule::field_type, + "parse_function_arg called on the wrong rule: {:?}", + pair.as_rule() + ); + let span = diagnostics.span(pair.as_span()); + + match parse_field_type(pair, diagnostics) { + Some(ftype) => Ok(BlockArg { + span, + field_type: ftype, + }), + None => Err(DatamodelError::new_validation_error( + "Failed to find type", + span, + )), + } +} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_old_function.rs b/engine/baml-lib/schema-ast/src/parser/parse_old_function.rs deleted file mode 100644 index d4e3089e3..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_old_function.rs +++ /dev/null @@ -1,243 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_config::parse_key_value, - parse_identifier::parse_identifier, - Rule, -}; -use crate::{assert_correct_parser, ast::*, parser::parse_types::parse_field_type}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub(crate) fn parse_old_function( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let pair_span = pair.as_span(); - let mut name: Option = None; - let mut attributes: Vec = Vec::new(); - let mut input = None; - let mut output = None; - let mut fields = vec![]; - - for current in pair.into_inner() { - match current.as_rule() { - Rule::FUNCTION_KEYWORD | Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::old_function_contents => { - let mut pending_field_comment: Option> = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)); - } - Rule::output_field_declaration => { - if output.is_some() { - diagnostics.push_error(DatamodelError::new_duplicate_field_error( - "", - "output", - "function", - diagnostics.span(pair_span), - )) - } else { - match parse_function_field_type(item, pending_field_comment.take(), diagnostics) { - Ok(FunctionArgs::Named(arg)) => { - diagnostics.push_error(DatamodelError::new_validation_error( - "Named arguments are not supported for function output. Define a new class instead.", - arg.span, - )) - }, - Ok(FunctionArgs::Unnamed(arg)) => output = Some(FunctionArgs::Unnamed(arg)), - Err(err) => diagnostics.push_error(err), - } - } - } - Rule::input_field_declaration => { - if input.is_some() { - diagnostics.push_error(DatamodelError::new_duplicate_field_error( - "", - "input", - "function", - diagnostics.span(pair_span), - )) - } else { - match parse_function_field_type( - item, - pending_field_comment.take(), - diagnostics, - ) { - Ok(out) => input = Some(out), - Err(err) => diagnostics.push_error(err), - } - } - } - Rule::key_value => { - fields.push(parse_key_value( - item, - pending_field_comment.take(), - diagnostics, - )); - } - Rule::comment_block => pending_field_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - } - _ => parsing_catch_all(¤t, "model"), - } - } - - match (name, input, output) { - (Some(name), Some(input), Some(output)) => Ok(Function { - name, - input, - output, - attributes, - fields, - documentation: doc_comment.and_then(parse_comment_block), - span: diagnostics.span(pair_span), - }), - (Some(name), _, _) => Err(DatamodelError::new_model_validation_error( - "This function declaration is invalid. It is missing an input or output field.", - "function", - name.name(), - diagnostics.span(pair_span), - )), - _ => Err(DatamodelError::new_model_validation_error( - "This function declaration is invalid. It is either missing a name or a type.", - "function", - "", - diagnostics.span(pair_span), - )), - } -} - -fn parse_function_field_type( - pair: Pair<'_>, - block_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::output_field_declaration - || pair.as_rule() == Rule::input_field_declaration, - "parse_function_field_type called on the wrong rule: {:?}", - pair.as_rule() - ); - let mut comment = block_comment.and_then(parse_comment_block); - let span = diagnostics.span(pair.as_span()); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::function_field_type => { - for item in current.into_inner() { - match item.as_rule() { - Rule::field_type => { - return Ok(FunctionArgs::Unnamed(parse_function_arg( - item, - diagnostics, - )?)); - } - Rule::trailing_comment => { - comment = match (comment, parse_trailing_comment(item)) { - (c, None) | (None, c) => c, - (Some(existing), Some(new)) => Some(Comment { - text: [existing.text, new.text].join("\n"), - }), - }; - } - Rule::named_argument_list => { - let mut args: Vec<(Identifier, FunctionArg)> = Vec::new(); - for named_arg in item.into_inner() { - if matches!(named_arg.as_rule(), Rule::SPACER_TEXT) { - continue; - } - assert_correct_parser!(named_arg, Rule::named_argument); - - let mut name = None; - let mut r#type = None; - for arg in named_arg.into_inner() { - match arg.as_rule() { - Rule::identifier => { - name = Some(parse_identifier(arg, diagnostics)); - } - - Rule::colon => {} - Rule::field_type => { - r#type = Some(parse_function_arg(arg, diagnostics)?); - } - _ => parsing_catch_all(&arg, "named_argument_list"), - } - } - - match (name, r#type) { - (Some(name), Some(r#type)) => args.push((name, r#type)), - (Some(name), None) => diagnostics.push_error( - DatamodelError::new_validation_error( - &format!( - "No type specified for argument: {}", - name.name() - ), - name.span().clone(), - ), - ), - (None, _) => { - unreachable!("parse_function_field_type: unexpected rule:") - } - } - } - return Ok(FunctionArgs::Named(NamedFunctionArgList { - documentation: comment, - args, - span, - })); - } - _ => unreachable!( - "parse_function_field_type: unexpected rule: {:?}", - item.as_rule() - ), - } - } - } - _ => unreachable!( - "parse_function_field_type: unexpected rule: {:?}", - current.as_rule() - ), - } - } - - Err(DatamodelError::new_validation_error( - "Missing function field type", - span, - )) -} - -fn parse_function_arg( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::field_type, - "parse_function_arg called on the wrong rule: {:?}", - pair.as_rule() - ); - let span = diagnostics.span(pair.as_span()); - - match parse_field_type(pair, diagnostics) { - Some(ftype) => Ok(FunctionArg { - span, - field_type: ftype, - }), - None => Err(DatamodelError::new_validation_error( - "Failed to find type", - span, - )), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_schema.rs b/engine/baml-lib/schema-ast/src/parser/parse_schema.rs index 44569a516..ea80f36fb 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_schema.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_schema.rs @@ -1,11 +1,11 @@ use std::path::PathBuf; use super::{ - parse_class::parse_class, parse_config, parse_enum::parse_enum, parse_function::parse_function, - parse_old_function::parse_old_function, parse_template_string::parse_template_string, - parse_test::parse_test_from_json, BAMLParser, Rule, + parse_template_string::parse_template_string, + parse_type_expression_block::parse_type_expression_block, + parse_value_expression_block::parse_value_expression_block, BAMLParser, Rule, }; -use crate::{ast::*, parser::parse_variant}; +use crate::ast::*; use internal_baml_diagnostics::{DatamodelError, Diagnostics, SourceFile}; use pest::Parser; @@ -32,18 +32,14 @@ pub fn parse_schema( let mut diagnostics = Diagnostics::new(root_path.clone()); diagnostics.set_source(source); - if !source.path().ends_with(".json") && !source.path().ends_with(".baml") { + if !source.path().ends_with(".baml") { diagnostics.push_error(DatamodelError::new_validation_error( - "A BAML file must have the file extension `.baml` or `.json`.", + "A BAML file must have the file extension `.baml`", Span::empty(source.clone()), )); return Err(diagnostics); } - if source.path().ends_with(".json") { - return parse_test_from_json(source, &mut diagnostics).map(|ast| (ast, diagnostics)); - } - let datamodel_result = BAMLParser::parse(Rule::schema, source.as_str()); match datamodel_result { Ok(mut datamodel_wrapped) => { @@ -61,54 +57,42 @@ pub fn parse_schema( while let Some(current) = pairs.next() { match current.as_rule() { - Rule::enum_declaration => top_level_definitions.push(Top::Enum(parse_enum(current,pending_block_comment.take(), &mut diagnostics))), - Rule::interface_declaration => { - let keyword = current.clone().into_inner().find(|pair| matches!(pair.as_rule(), Rule::CLASS_KEYWORD | Rule::FUNCTION_KEYWORD) ).expect("Expected class keyword"); - match keyword.as_rule() { - Rule::CLASS_KEYWORD => { - top_level_definitions.push(Top::Class(parse_class(current, pending_block_comment.take(), &mut diagnostics))); - }, - _ => unreachable!("Expected class keyword"), - }; - } - Rule::function_declaration => { - match parse_function(current, pending_block_comment.take(), &mut diagnostics) { - Ok(function) => top_level_definitions.push(Top::Function(function)), - Err(e) => diagnostics.push_error(e), - } - }, - Rule::old_function_declaration => { - match parse_old_function(current, pending_block_comment.take(), &mut diagnostics) { - Ok(function) => top_level_definitions.push(Top::FunctionOld(function)), - Err(e) => diagnostics.push_error(e), - } - }, - Rule::config_block => { - match parse_config::parse_config_block( - current, - pending_block_comment.take(), - &mut diagnostics, - ) { - Ok(config) => top_level_definitions.push(config), - Err(e) => diagnostics.push_error(e), - } + + Rule::type_expression_block => { + let type_expr = parse_type_expression_block(current, pending_block_comment.take(), &mut diagnostics); + + + match type_expr.sub_type { + SubType::Class => top_level_definitions.push(Top::Class(type_expr)), + SubType::Enum => top_level_definitions.push(Top::Enum(type_expr)), + _ => (), // may need to save other somehow for error propagation + } } - Rule::variant_block => { - match parse_variant::parse_variant_block( - current, - pending_block_comment.take(), - &mut diagnostics, - ) { - Ok(config) => top_level_definitions.push(Top::Variant(config)), + Rule::value_expression_block => { + let val_expr = parse_value_expression_block(current, pending_block_comment.take(), &mut diagnostics); + match val_expr { + Ok(val) => { + if let Some(top) = match val.block_type { + ValueExprBlockType::Function => Some(Top::Function(val)), + ValueExprBlockType::Test => Some(Top::TestCase(val)), + ValueExprBlockType::Client => Some(Top::Client(val)), + ValueExprBlockType::RetryPolicy => Some(Top::RetryPolicy(val)), + ValueExprBlockType::Generator => Some(Top::Generator(val)), + } { + top_level_definitions.push(top); + } + } Err(e) => diagnostics.push_error(e), } } + Rule::template_declaration => { match parse_template_string(current, pending_block_comment.take(), &mut diagnostics) { Ok(template) => top_level_definitions.push(Top::TemplateString(template)), Err(e) => diagnostics.push_error(e), } } + Rule::EOI => {} Rule::CATCH_ALL => diagnostics.push_error(DatamodelError::new_validation_error( "This line is invalid. It does not start with any known Baml schema keyword.", @@ -119,18 +103,14 @@ pub fn parse_schema( Some(Rule::empty_lines) => { // free floating } - Some(Rule::enum_declaration) => { - pending_block_comment = Some(current); - } + // Some(Rule::enum_declaration) => { + // pending_block_comment = Some(current); + // } _ => (), } }, // We do nothing here. Rule::raw_string_literal => (), - Rule::arbitrary_block => diagnostics.push_error(DatamodelError::new_validation_error( - "This block is invalid. It does not start with any known BAML keyword. Common keywords include 'enum', 'class', 'function', and 'impl'.", - diagnostics.span(current.as_span()), - )), Rule::empty_lines => (), _ => unreachable!("Encountered an unknown rule: {:?}", current.as_rule()), } @@ -170,6 +150,44 @@ pub fn parse_schema( } } +#[cfg(test)] +mod tests { + + use super::parse_schema; + use crate::ast::*; // Add this line to import the ast module + use internal_baml_diagnostics::SourceFile; + + #[test] + // #[test_log::test] + fn test_parse_schema() { + let input = r#" + class MyClass { + myProperty string[] @description("This is a description") @alias("MP") + } + "#; + + let root_path = "test_file.baml"; + let source = SourceFile::new_static(root_path.into(), input); + + let result = parse_schema(&root_path.into(), &source); + + assert!(result.is_ok()); + let (schema_ast, _) = result.unwrap(); + + assert_eq!(schema_ast.tops.len(), 1); + + match &schema_ast.tops[0] { + Top::Class(model) => { + assert_eq!(model.name.name(), "MyClass"); + assert_eq!(model.fields.len(), 1); + assert_eq!(model.fields[0].name.name(), "myProperty"); + assert_eq!(model.fields[0].attributes.len(), 2) + } + _ => panic!("Expected a model declaration"), + } + } +} + fn get_expected_from_error(positives: &[Rule]) -> String { use std::fmt::Write as _; let mut out = String::with_capacity(positives.len() * 6); diff --git a/engine/baml-lib/schema-ast/src/parser/parse_serializer.rs b/engine/baml-lib/schema-ast/src/parser/parse_serializer.rs deleted file mode 100644 index b5287c57b..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_serializer.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_attribute::parse_attribute, - parse_comments::*, - parse_identifier::parse_identifier, - Rule, -}; -use crate::ast::{Attribute, Comment, Serializer, SerializerField}; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub fn parse_serializer( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Serializer { - let comment = doc_comment.and_then(parse_comment_block); - let pair_span = pair.as_span(); - let mut name = None; - let mut attributes: Vec = vec![]; - let mut fields = vec![]; - - for current in pair.into_inner().peekable() { - match current.as_rule() { - Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE | Rule::SERIALIZER_KEYWORD => {} - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::serializer_contents => { - let mut pending_value_comment = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)) - } - Rule::serializer_field => { - match parse_serializer_field( - item, - pending_value_comment.take(), - diagnostics, - ) { - Ok(field) => fields.push(field), - Err(err) => diagnostics.push_error(err), - } - } - Rule::comment_block => pending_value_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not valid.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "serializer_content"), - } - } - } - _ => parsing_catch_all(¤t, "serializer"), - } - } - - match name { - Some(name) => Serializer { - name, - fields, - attributes, - documentation: comment, - span: diagnostics.span(pair_span), - }, - _ => { - panic!("Encountered impossible serializer declaration during parsing, name is missing.",) - } - } -} - -fn parse_serializer_field( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let (pair_str, pair_span) = (pair.as_str(), pair.as_span()); - let mut name = None; - let mut attributes = vec![]; - let mut comment = doc_comment.and_then(parse_comment_block); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::field_attribute => attributes.push(parse_attribute(current, diagnostics)), - Rule::trailing_comment => { - comment = match (comment, parse_trailing_comment(current)) { - (None, a) | (a, None) => a, - (Some(a), Some(b)) => Some(Comment { - text: [a.text, b.text].join("\n"), - }), - }; - } - Rule::comment_block => { - parse_comment_block(current); - } - _ => parsing_catch_all(¤t, "serializer field"), - } - } - - match name { - Some(name) => Ok(SerializerField { - name, - attributes, - documentation: comment, - span: diagnostics.span(pair_span), - }), - _ => panic!("Encountered impossible serializer field declaration during parsing, name is missing: {pair_str:?}",), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_template_args.rs b/engine/baml-lib/schema-ast/src/parser/parse_template_args.rs deleted file mode 100644 index 148ac6a73..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_template_args.rs +++ /dev/null @@ -1,31 +0,0 @@ -use super::{ - helpers::{parsing_catch_all, Pair}, - Rule, -}; -use crate::{assert_correct_parser, ast::*, parser::parse_expression::parse_expression}; - -pub(crate) fn parse_template_args( - token: Pair<'_>, - diagnostics: &mut internal_baml_diagnostics::Diagnostics, -) -> Option> { - assert_correct_parser!(token, Rule::template_args); - - let mut template_args = Vec::new(); - for current in token.into_inner() { - match current.as_rule() { - Rule::empty_template_args => { - return None; - } - Rule::expression => { - template_args.push(parse_expression(current, diagnostics)); - } - _ => parsing_catch_all(¤t, "template args"), - } - } - - if template_args.is_empty() { - return None; - } - - Some(template_args) -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_template_string.rs b/engine/baml-lib/schema-ast/src/parser/parse_template_string.rs index d509d5bb5..f60009ea6 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_template_string.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_template_string.rs @@ -3,9 +3,10 @@ use super::{ parse_comments::*, parse_expression::parse_raw_string, parse_identifier::parse_identifier, + parse_named_args_list::parse_named_argument_list, Rule, }; -use crate::{assert_correct_parser, ast::*, parser::parse_types::parse_field_type}; +use crate::ast::*; use internal_baml_diagnostics::{DatamodelError, Diagnostics}; pub(crate) fn parse_template_string( @@ -23,20 +24,18 @@ pub(crate) fn parse_template_string( match current.as_rule() { Rule::TEMPLATE_KEYWORD => {} Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::named_argument_list => match parse_named_arguement_list(current, diagnostics) { - Ok(FunctionArgs::Named(arg)) => input = Some(FunctionArgs::Named(arg)), - Ok(FunctionArgs::Unnamed(arg)) => { - diagnostics.push_error(DatamodelError::new_validation_error( - "Unnamed arguments are not supported for function input. Define a new class instead.", - arg.span, - )) - } + Rule::assignment => {} + Rule::named_argument_list => match parse_named_argument_list(current, diagnostics) { + Ok(arg) => input = Some(arg), Err(err) => diagnostics.push_error(err), }, Rule::raw_string_literal => { - value = Some(Expression::RawStringValue(parse_raw_string(current, diagnostics))) + value = Some(Expression::RawStringValue(parse_raw_string( + current, + diagnostics, + ))) } - _ => parsing_catch_all(¤t, "function"), + _ => parsing_catch_all(current, "function"), } } @@ -77,80 +76,3 @@ template_string {}(param1: String, param2: String) #" diagnostics.span(pair_span), )) } - -fn parse_named_arguement_list( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::named_argument_list, - "parse_named_arguement_list called on the wrong rule: {:?}", - pair.as_rule() - ); - let span = diagnostics.span(pair.as_span()); - let mut args: Vec<(Identifier, FunctionArg)> = Vec::new(); - for named_arg in pair.into_inner() { - if matches!(named_arg.as_rule(), Rule::SPACER_TEXT) { - continue; - } - assert_correct_parser!(named_arg, Rule::named_argument); - - let mut name = None; - let mut r#type = None; - for arg in named_arg.into_inner() { - match arg.as_rule() { - Rule::identifier => { - name = Some(parse_identifier(arg, diagnostics)); - } - Rule::colon => {} - Rule::field_type => { - r#type = Some(parse_function_arg(arg, diagnostics)?); - } - _ => parsing_catch_all(&arg, "named_argument_list"), - } - } - - match (name, r#type) { - (Some(name), Some(r#type)) => args.push((name, r#type)), - (Some(name), None) => diagnostics.push_error(DatamodelError::new_validation_error( - &format!( - "No type specified for argument: {name}. Expected: `{name}: type`", - name = name.name() - ), - name.span().clone(), - )), - (None, _) => { - unreachable!("parse_function_field_type: unexpected rule:") - } - } - } - - Ok(FunctionArgs::Named(NamedFunctionArgList { - documentation: None, - args, - span, - })) -} - -fn parse_function_arg( - pair: Pair<'_>, - diagnostics: &mut Diagnostics, -) -> Result { - assert!( - pair.as_rule() == Rule::field_type, - "parse_function_arg called on the wrong rule: {:?}", - pair.as_rule() - ); - let span = diagnostics.span(pair.as_span()); - - match parse_field_type(pair, diagnostics) { - Some(ftype) => Ok(FunctionArg { - span, - field_type: ftype, - }), - None => Err(DatamodelError::new_validation_error( - "Failed to find type", - span, - )), - } -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_test.rs b/engine/baml-lib/schema-ast/src/parser/parse_test.rs deleted file mode 100644 index 035a5ee8a..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_test.rs +++ /dev/null @@ -1,195 +0,0 @@ -#[cfg(target_arch = "wasm32")] -use std::path::PathBuf; - -use crate::ast::*; -use internal_baml_diagnostics::{DatamodelError, Diagnostics, SourceFile}; -use serde::Deserialize; -use serde_json::Value; - -// Define an enum for the different types of input -#[derive(Deserialize, Debug)] -#[serde(untagged)] // This allows for different shapes of JSON -enum Input { - ObjectInput(Value), // Use serde_json::Value for a generic JSON object -} - -impl Input { - // Method to get the string representation of the input - fn to_string(&self) -> String { - match self { - Input::ObjectInput(obj) => serde_json::to_string(obj).unwrap_or_default(), - } - } -} - -#[derive(Deserialize, Debug)] -struct TestFileContent { - input: Input, -} - -pub(crate) fn parse_test_from_json( - source: &SourceFile, - diagnostics: &mut Diagnostics, -) -> Result { - // Path relative to the root of the project. - let source_path = source.path_buf().clone(); - let root_path = diagnostics.root_path.clone(); - - #[cfg(not(target_arch = "wasm32"))] - let relative_path = source_path.strip_prefix(&root_path); - - #[cfg(target_arch = "wasm32")] - let relative_path = match source_path - .to_string_lossy() - .to_string() - .strip_prefix(&root_path.to_string_lossy().to_string()) - { - Some(path) => { - // Remove the leading slash or backslash. - let path = match path.chars().next() { - Some('/') => &path[1..], - Some('\\') => &path[1..], - _ => path, - }; - Ok(PathBuf::from(path)) - } - None => Err(()), - }; - - match relative_path { - Err(_) => { - diagnostics.push_error(DatamodelError::new_validation_error( - &format!( - "The path of the test file must be inside the project root: {} {}", - root_path.display(), - source_path.display() - ), - Span::empty(source.clone()), - )); - } - _ => (), - }; - - diagnostics.to_result()?; - let relative_path = relative_path.unwrap(); - - #[cfg(target_arch = "wasm32")] - let relative_path = match relative_path.to_string_lossy().contains("\\") { - true => { - // replace all \\ with / - PathBuf::from( - relative_path - .to_string_lossy() - .to_string() - .replace("\\", "/"), - ) - } - false => relative_path, - }; - - let parts = relative_path.components(); - - // Ensure is of the form `__tests__//.json` using regex - // or throw an error. - let mut function_name = None; - let mut test_name = None; - let mut group_name = None; - for (idx, part) in parts.enumerate() { - let part = part.as_os_str().to_str().unwrap(); - match idx { - 0 => { - if part != "__tests__" { - diagnostics.push_error(DatamodelError::new_validation_error( - "A BAML test file must be in a `__tests__` directory.", - Span::empty(source.clone()), - )); - } - } - 1 => { - function_name = Some(part); - } - _ => { - if part.ends_with(".json") { - test_name = Some( - part.strip_suffix(".json") - .unwrap() - .replace(|c: char| !c.is_alphanumeric() && c != '_', "_"), - ); - } else { - group_name = match group_name { - None => Some(part.to_string()), - Some(prev) => Some(format!("{}_{}", prev, part)), - } - } - } - } - } - - if function_name.is_none() { - diagnostics.push_error(DatamodelError::new_validation_error( - "Missing a function name in the path.", - Span::empty(source.clone()), - )); - } - - if test_name.is_none() { - diagnostics.push_error(DatamodelError::new_validation_error( - "Test file must have a name", - Span::empty(source.clone()), - )); - } - - diagnostics.to_result()?; - - let function_name = function_name.unwrap(); - let test_name = test_name.unwrap(); - - let file_content: TestFileContent = match serde_json::from_str(source.as_str()) { - Ok(file_content) => file_content, - Err(err) => { - diagnostics.push_error(DatamodelError::new_validation_error( - &format!("Failed to parse JSON: {}", err), - Span::empty(source.clone()), - )); - diagnostics.to_result()?; - unreachable!("Failed to parse JSON for test:"); - } - }; - let test_input = file_content.input.to_string(); - let end_range = test_input.len(); - let span = Span::new(source.clone(), 0, end_range); - let content = match file_content.input { - Input::ObjectInput(val) => { - Expression::from_json(val, span.clone(), Span::empty(source.clone())) - } - }; - let test_case = ConfigBlockProperty { - name: Identifier::Local("input".into(), span.clone()), - value: Some(content), - template_args: None, - attributes: vec![], - documentation: None, - span: span.clone(), - }; - let function_names = ConfigBlockProperty { - name: Identifier::Local("functions".into(), span.clone()), - value: Some(Expression::Array( - vec![Expression::StringValue(function_name.into(), span.clone())], - span.clone(), - )), - template_args: None, - attributes: vec![], - documentation: None, - span: span.clone(), - }; - let top = RetryPolicyConfig { - name: Identifier::Local(test_name, span.clone()), - documentation: None, - attributes: vec![], - fields: vec![test_case, function_names], - span: span.clone(), - }; - Ok(SchemaAst { - tops: vec![Top::Config(Configuration::TestCase(top))], - }) -} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_type_expression_block.rs b/engine/baml-lib/schema-ast/src/parser/parse_type_expression_block.rs new file mode 100644 index 000000000..c752949c3 --- /dev/null +++ b/engine/baml-lib/schema-ast/src/parser/parse_type_expression_block.rs @@ -0,0 +1,111 @@ +use super::{ + helpers::{parsing_catch_all, Pair}, + parse_attribute::parse_attribute, + parse_comments::*, + parse_identifier::parse_identifier, + parse_named_args_list::parse_named_argument_list, + Rule, +}; + +use crate::{assert_correct_parser, ast::*}; +use crate::{ast::TypeExpressionBlock, parser::parse_field::parse_expr_as_type}; // Add this line to import DatamodelParser + +use internal_baml_diagnostics::{DatamodelError, Diagnostics}; + +pub(crate) fn parse_type_expression_block( + pair: Pair<'_>, + doc_comment: Option>, + diagnostics: &mut Diagnostics, +) -> TypeExpressionBlock { + assert_correct_parser!(pair, Rule::type_expression_block); + + let pair_span = pair.as_span(); + let mut name: Option = None; + let mut attributes: Vec = Vec::new(); + let mut fields: Vec> = Vec::new(); + let mut sub_type: Option = None; + + for current in pair.into_inner() { + let mut input: Option = None; + + + match current.as_rule() { + Rule::type_expression_keyword => { + match current.as_str() { + "class" => sub_type = Some(SubType::Class.clone()), + "enum" => sub_type = Some(SubType::Enum.clone()), + _ => sub_type = Some(SubType::Other(current.as_str().to_string())), + } + // Rule::CLASS_KEYWORD => sub_type = Some(SubType::Class.clone()); + // Rule::ENUM_KEYWORD => sub_type = Some(SubType::Enum.clone()); + } + + Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} + Rule::identifier => name = Some(parse_identifier(current, diagnostics)), + Rule::named_argument_list => match parse_named_argument_list(current, diagnostics) { + Ok(arg) => input = Some(arg), + Err(err) => diagnostics.push_error(err), + }, + Rule::type_expression_contents => { + let mut pending_field_comment: Option> = None; + + for item in current.into_inner() { + + + match item.as_rule() { + Rule::block_attribute => { + attributes.push(parse_attribute(item, diagnostics)); + } + Rule::type_expression =>{ + + match parse_expr_as_type( + &name, + sub_type.clone().map(|st| match st { + SubType::Enum => "Enum", + SubType::Class => "Class", + SubType::Other(_) => "Other", + }).unwrap_or(""), + item, + pending_field_comment.take(), + diagnostics, + matches!(sub_type, Some(SubType::Enum)) + ) { + Ok(field) => { + + fields.push(field); + }, + Err(err) => diagnostics.push_error(err), + } + } + Rule::comment_block => pending_field_comment = Some(item), + Rule::BLOCK_LEVEL_CATCH_ALL => { + diagnostics.push_error(DatamodelError::new_validation_error( + "This line is not a valid field or attribute definition. A valid class property looks like: 'myProperty string[] @description(\"This is a description\")'", + diagnostics.span(item.as_span()), + )) + } + _ => parsing_catch_all(item, "type_expression"), + } + } + } + + _ => { + parsing_catch_all(current, "type_expression") + } + } + } + + match name { + Some(name) => TypeExpressionBlock { + name, + fields, + attributes, + documentation: doc_comment.and_then(parse_comment_block), + span: diagnostics.span(pair_span), + sub_type: sub_type + .clone() + .unwrap_or(SubType::Other("Subtype not found".to_string())), + }, + _ => panic!("Encountered impossible type_expression declaration during parsing",), + } +} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_types.rs b/engine/baml-lib/schema-ast/src/parser/parse_types.rs index 4d0acb688..fa6dff642 100644 --- a/engine/baml-lib/schema-ast/src/parser/parse_types.rs +++ b/engine/baml-lib/schema-ast/src/parser/parse_types.rs @@ -1,21 +1,31 @@ -use super::{helpers::Pair, Rule}; +use super::{helpers::Pair, parse_attribute::parse_attribute, Rule}; use crate::{ assert_correct_parser, ast::*, parser::parse_identifier::parse_identifier, unreachable_rule, }; +use baml_types::TypeValue; use internal_baml_diagnostics::Diagnostics; pub fn parse_field_type(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { - assert_correct_parser!(pair, Rule::field_type); - + assert_correct_parser!(pair, Rule::field_type, Rule::openParan, Rule::closeParan); let mut arity = FieldArity::Required; let mut ftype = None; for current in pair.into_inner() { match current.as_rule() { - Rule::union => ftype = parse_union(current, diagnostics), - Rule::non_union => ftype = parse_base_type(current, diagnostics), + Rule::union => { + let result = parse_union(current, diagnostics); + + ftype = result; + } + Rule::non_union => { + let result = parse_base_type(current, diagnostics); + + ftype = result; + } Rule::optional_token => arity = FieldArity::Optional, - _ => unreachable_rule!(current, Rule::field_type), + _ => { + unreachable_rule!(current, Rule::field_type) + } } } @@ -32,7 +42,9 @@ pub fn parse_field_type(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option } Some(ftype) } - _ => unreachable!("Ftype should aways be defiened"), + None => { + unreachable!("Ftype should always be defined") + } } } @@ -48,17 +60,77 @@ fn parse_union(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { + if let Some(f) = parse_base_type_with_attr(current, diagnostics) { + types.push(f) + } + } + Rule::field_operator => {} + _ => unreachable_rule!(current, Rule::union), } } + let attributes = types + .last_mut() + .and_then(|t| t.attributes().to_owned().into()); + if let Some(last_type) = types.last_mut() { + last_type.reset_attributes(); + } + match types.len() { 0 => unreachable!("A union must have atleast 1 type"), 1 => Some(types[0].to_owned()), - _ => Some(FieldType::Union(FieldArity::Required, types, span)), + _ => Some(FieldType::Union( + FieldArity::Required, + types, + span, + attributes, + )), } } +fn parse_base_type_with_attr(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { + let mut attributes = Vec::new(); + let mut base_type = None; + + for current in pair.into_inner() { + match current.as_rule() { + Rule::base_type => { + base_type = parse_base_type(current, diagnostics); + } + Rule::field_attribute => { + let att = parse_attribute(current, diagnostics); + attributes.push(att); + } + _ => unreachable_rule!(current, Rule::base_type_with_attr), + } + } + + base_type.map(|f| { + let span = f.span().clone(); + let arity = match f { + FieldType::Symbol(arity, ..) => arity, + FieldType::Primitive(arity, ..) => arity, + FieldType::List(_, _, _, _) => FieldArity::Required, + FieldType::Tuple(arity, ..) => arity, + FieldType::Union(arity, ..) => arity, + FieldType::Map(_, _, _) => FieldArity::Required, + }; + + FieldType::Union( + arity, + vec![f], + span, + if attributes.is_empty() { + None + } else { + Some(attributes) + }, + ) + }) +} + fn parse_base_type(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { assert_correct_parser!( pair, @@ -69,10 +141,27 @@ fn parse_base_type(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option Some(FieldType::Identifier( - FieldArity::Required, - parse_identifier(current, diagnostics), - )), + Rule::identifier => { + // log::info!("Parsing identifier {:?}", current.as_str()); + let identifier = parse_identifier(current.clone(), diagnostics); + let field_type = match current.as_str() { + "string" | "int" | "float" | "bool" | "image" | "audio" => { + FieldType::Primitive( + FieldArity::Required, + TypeValue::from_str(identifier.name()).expect("Invalid type value"), + diagnostics.span(current.as_span()), + None, + ) + } + _ => FieldType::Symbol( + FieldArity::Required, + identifier.name().to_string(), + diagnostics.span(current.as_span()), + None, + ), + }; + Some(field_type) + } Rule::array_notation => parse_array(current, diagnostics), Rule::map => parse_map(current, diagnostics), Rule::group => parse_group(current, diagnostics), @@ -99,7 +188,7 @@ fn parse_array(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option Some(FieldType::List(Box::new(field), dims, span)), + Some(field) => Some(FieldType::List(Box::new(field), dims, span, None)), _ => unreachable!("Field must have been defined"), } } @@ -127,6 +216,7 @@ fn parse_map(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option 2 => Some(FieldType::Map( Box::new((fields[0].to_owned(), fields[1].to_owned())), span, + None, )), _ => unreachable!("Maps must specify a key type and value type"), } @@ -134,8 +224,15 @@ fn parse_map(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option fn parse_group(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option { assert_correct_parser!(pair, Rule::group); - if let Some(current) = pair.into_inner().next() { - return parse_field_type(current, diagnostics); + + for current in pair.into_inner() { + match current.as_rule() { + Rule::openParan | Rule::closeParan => continue, + Rule::field_type => { + return parse_field_type(current, diagnostics); + } + _ => unreachable_rule!(current, Rule::group), + } } unreachable!("impossible group parsing"); @@ -150,6 +247,8 @@ fn parse_tuple(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option continue, + Rule::field_type => { if let Some(f) = parse_field_type(current, diagnostics) { fields.push(f) @@ -162,6 +261,6 @@ fn parse_tuple(pair: Pair<'_>, diagnostics: &mut Diagnostics) -> Option None, 1 => Some(fields[0].to_owned()), - _ => Some(FieldType::Tuple(FieldArity::Required, fields, span)), + _ => Some(FieldType::Tuple(FieldArity::Required, fields, span, None)), } } diff --git a/engine/baml-lib/schema-ast/src/parser/parse_value_expression_block.rs b/engine/baml-lib/schema-ast/src/parser/parse_value_expression_block.rs new file mode 100644 index 000000000..53ea9a1d2 --- /dev/null +++ b/engine/baml-lib/schema-ast/src/parser/parse_value_expression_block.rs @@ -0,0 +1,135 @@ +use std::collections::hash_map; + +use super::{ + helpers::{parsing_catch_all, Pair}, + parse_comments::*, + parse_field::{self, parse_expr_as_value}, + parse_identifier::parse_identifier, + parse_named_args_list::{parse_function_arg, parse_named_argument_list}, + Rule, +}; + +use crate::ast::*; +use internal_baml_diagnostics::{DatamodelError, Diagnostics}; // Add this line + +pub(crate) fn parse_value_expression_block( + pair: Pair<'_>, + doc_comment: Option>, + diagnostics: &mut Diagnostics, +) -> Result { + let pair_span = pair.as_span(); + let mut name: Option = None; + let attributes: Vec = Vec::new(); + let mut input = None; + let mut output = None; + let mut fields: Vec> = vec![]; + let mut sub_type: Option = None; + let mut has_arrow = false; + + for current in pair.into_inner() { + match current.as_rule() { + Rule::value_expression_keyword => match current.as_str() { + "function" => sub_type = Some(ValueExprBlockType::Function), + "test" => sub_type = Some(ValueExprBlockType::Test), + "client" | "client" => sub_type = Some(ValueExprBlockType::Client), + "retry_policy" => sub_type = Some(ValueExprBlockType::RetryPolicy), + "generator" => sub_type = Some(ValueExprBlockType::Generator), + _ => panic!("Unexpected value expression keyword: {}", current.as_str()), + }, + Rule::ARROW => { + has_arrow = true; + } + Rule::identifier => name = Some(parse_identifier(current, diagnostics)), + Rule::named_argument_list => match parse_named_argument_list(current, diagnostics) { + Ok(arg) => input = Some(arg), + Err(err) => diagnostics.push_error(err), + }, + Rule::field_type => match parse_function_arg(current, diagnostics) { + Ok(arg) => output = Some(arg), + Err(err) => diagnostics.push_error(err), + }, + Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} + + Rule::value_expression_contents => { + let mut pending_field_comment: Option> = None; + + for item in current.into_inner() { + match item.as_rule() { + Rule::value_expression => { + fields.push(parse_expr_as_value( + &name, + sub_type + .clone() + .map(|st| match st { + ValueExprBlockType::Function => "Function", + ValueExprBlockType::Test => "Test", + ValueExprBlockType::Client => "Client", + ValueExprBlockType::RetryPolicy => "RetryPolicy", + ValueExprBlockType::Generator => "Generator", + }) + .unwrap_or("Other"), + item, + pending_field_comment.take(), + diagnostics, + )?); + + pending_field_comment = None; + } + + Rule::comment_block => pending_field_comment = Some(item), + Rule::empty_lines => {} + Rule::BLOCK_LEVEL_CATCH_ALL => { + diagnostics.push_error(DatamodelError::new_validation_error( + "This line is not a valid field or attribute definition.", + diagnostics.span(item.as_span()), + )) + } + _ => parsing_catch_all(item, "model"), + } + } + } + _ => parsing_catch_all(current, "function"), + } + } + + log::info!("Input = {:?}", input); + + let response = match name { + Some(name) => { + return Ok(ValueExprBlock { + name, + input, + output, + attributes, + fields, + documentation: doc_comment.and_then(parse_comment_block), + span: diagnostics.span(pair_span), + block_type: sub_type.unwrap_or(ValueExprBlockType::Function), // Unwrap or provide a default + }); + // (msg, Some(name.name().to_string())) + } + None => ( + "Could not match on name for value expression.", + None::, + None::, + ), + }; + + Err(DatamodelError::new_model_validation_error( + format!( + r##"{} Valid function syntax is +``` +function {}(param1: String, param2: String) -> ReturnType {{ + client SomeClient + prompt #"..."# +}} +```"##, + response.0, + response.1.as_deref().unwrap_or("MyFunction") + ) + .as_str(), + "function", + response.1.as_deref().unwrap_or(""), + diagnostics.span(pair_span), + )) +} diff --git a/engine/baml-lib/schema-ast/src/parser/parse_variant.rs b/engine/baml-lib/schema-ast/src/parser/parse_variant.rs deleted file mode 100644 index e4c51ebf4..000000000 --- a/engine/baml-lib/schema-ast/src/parser/parse_variant.rs +++ /dev/null @@ -1,115 +0,0 @@ -use std::ops::Index; - -use super::{ - helpers::{parsing_catch_all, Pair}, - parse_adapter::parse_adapter, - parse_attribute::parse_attribute, - parse_comments::*, - parse_config::parse_key_value, - parse_identifier::parse_identifier, - parse_serializer::parse_serializer, - parse_template_args::parse_template_args, - Rule, -}; -use crate::ast::*; -use internal_baml_diagnostics::{DatamodelError, Diagnostics}; - -pub(crate) fn parse_variant_block( - pair: Pair<'_>, - doc_comment: Option>, - diagnostics: &mut Diagnostics, -) -> Result { - let pair_span = pair.as_span(); - let mut template_args = None; - let mut name: Option = None; - let mut serializers: Vec = Vec::new(); - let mut attributes: Vec = Vec::new(); - let mut fields: Vec = Vec::new(); - let mut adapters: Vec = Vec::new(); - - for current in pair.into_inner() { - match current.as_rule() { - Rule::BLOCK_OPEN | Rule::BLOCK_CLOSE => {} - Rule::template_args => template_args = parse_template_args(current, diagnostics), - Rule::variant_contents => { - let mut pending_field_comment: Option> = None; - - for item in current.into_inner() { - match item.as_rule() { - Rule::block_attribute => { - attributes.push(parse_attribute(item, diagnostics)); - } - Rule::key_value => { - fields.push(parse_key_value( - item, - pending_field_comment.take(), - diagnostics, - )); - } - Rule::adapter_block => { - if let Some(f) = parse_adapter(item, None, diagnostics) { - adapters.push(f) - } - } - Rule::serializer_block => { - serializers.push(parse_serializer(item, None, diagnostics)) - } - Rule::comment_block => pending_field_comment = Some(item), - Rule::BLOCK_LEVEL_CATCH_ALL => { - diagnostics.push_error(DatamodelError::new_validation_error( - "This line is not a valid field or attribute definition.", - diagnostics.span(item.as_span()), - )) - } - _ => parsing_catch_all(&item, "model"), - } - } - } - Rule::identifier => name = Some(parse_identifier(current, diagnostics)), - Rule::VARIANT_KEYWORD => {} - _ => parsing_catch_all(¤t, "client"), - } - } - - match (name, template_args) { - (_, None) => Err(DatamodelError::new_validation_error( - "Missing template for impl. (did you forget )", - diagnostics.span(pair_span.get(0..4).unwrap()), - )), - (Some(name), Some(args)) => match args.len() { - 2 => { - let variant_type = args.index(0).as_constant_value().map(|f| f.0); - if variant_type.is_none() { - return Err(DatamodelError::new_validation_error( - "impl's first template arg should be an executor. (did you forget ).", - args[0].span().clone(), - )); - } - - let identifier = args.index(1).as_identifer(); - if identifier.is_none() { - return Err(DatamodelError::new_validation_error( - "impl's second template arg should be a function name. (did you forget ).", - args[1].span().clone(), - )); - } - Ok(Variant { - name, - fields, - serializers, - attributes, - adapters, - documentation: doc_comment.and_then(parse_comment_block), - span: diagnostics.span(pair_span), - variant_type: variant_type.unwrap().to_string(), - function_name: identifier.unwrap().to_owned(), - }) - } - _ => Err(DatamodelError::new_validation_error( - "impl requires 2 template args. (did you forget )", - diagnostics.span(pair_span.get(0..("impl".len())).unwrap()), - )), - }, - _ => unreachable!("Encountered impossible impl declaration during parsing",), - } -} diff --git a/engine/baml-runtime/src/internal/prompt_renderer/mod.rs b/engine/baml-runtime/src/internal/prompt_renderer/mod.rs index 96ff49e2d..daf57e8bb 100644 --- a/engine/baml-runtime/src/internal/prompt_renderer/mod.rs +++ b/engine/baml-runtime/src/internal/prompt_renderer/mod.rs @@ -28,13 +28,7 @@ impl PromptRenderer { ir: &IntermediateRepr, ctx: &RuntimeContext, ) -> Result { - let Some(func_v2) = function.as_v2() else { - error_unsupported!( - "function", - function.name(), - "legacy functions are not supported in the runtime" - ) - }; + let func_v2 = function.elem(); let Some(config) = func_v2.configs.first() else { error_unsupported!("function", function.name(), "no valid prompt found") }; @@ -45,8 +39,8 @@ impl PromptRenderer { Some((Some(client), _)) => client.clone(), _ => config.client.clone(), }, - output_defs: render_output_format(ir, ctx, &func_v2.output.elem)?, - output_type: func_v2.output.elem.clone(), + output_defs: render_output_format(ir, ctx, &func_v2.output)?, + output_type: func_v2.output.clone(), }) } @@ -72,13 +66,7 @@ impl PromptRenderer { ) -> Result { let func = ir.find_function(&self.function_name)?; - let Some(func_v2) = func.as_v2() else { - error_unsupported!( - "function", - self.function_name, - "legacy functions are not supported in the runtime" - ) - }; + let func_v2 = func.elem(); let Some(config) = func_v2.configs.first() else { error_unsupported!("function", self.function_name, "no valid prompt found") diff --git a/engine/baml-runtime/src/runtime/ir_features.rs b/engine/baml-runtime/src/runtime/ir_features.rs index f635c651e..28e53687c 100644 --- a/engine/baml-runtime/src/runtime/ir_features.rs +++ b/engine/baml-runtime/src/runtime/ir_features.rs @@ -12,10 +12,7 @@ impl WithInternal for InternalBamlRuntime { let ir = self.ir(); IrFeatures::from( - ir.walk_functions() - .filter(|f| f.is_v1()) - .map(|f| f.name().to_string()) - .collect(), + vec![], ir.walk_functions().any(|f| f.is_v2()), ir.walk_classes() .filter(|c| !c.elem().dynamic_fields.is_empty()) diff --git a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs index 5ebc38792..51ed069e1 100644 --- a/engine/baml-schema-wasm/src/runtime_wasm/mod.rs +++ b/engine/baml-schema-wasm/src/runtime_wasm/mod.rs @@ -24,7 +24,7 @@ use wasm_bindgen::prelude::*; #[wasm_bindgen(start)] pub fn on_wasm_init() { - match console_log::init_with_level(log::Level::Warn) { + match console_log::init_with_level(log::Level::Info) { Ok(_) => web_sys::console::log_1(&"Initialized BAML runtime logging".into()), Err(e) => web_sys::console::log_1( &format!("Failed to initialize BAML runtime logging: {:?}", e).into(), @@ -751,17 +751,12 @@ impl WasmRuntime { #[wasm_bindgen] pub fn check_if_in_prompt(&self, cursor_idx: usize) -> bool { - self.runtime - .internal() - .ir() - .walk_functions() - .any(|f| match f.as_v2() { - Some(func_v2) => func_v2.configs.iter().any(|config| { - let span = &config.prompt_span; - cursor_idx >= span.start && cursor_idx <= span.end - }), - None => false, + self.runtime.internal().ir().walk_functions().any(|f| { + f.elem().configs().expect("configs").iter().any(|config| { + let span = &config.prompt_span; + cursor_idx >= span.start && cursor_idx <= span.end }) + }) } #[wasm_bindgen] @@ -782,15 +777,11 @@ impl WasmRuntime { name = f.name(), args = f .inputs() - .right() - .map(|func_params| { - func_params - .iter() - .filter_map(|(k, t)| get_dummy_field(2, k, t)) - .collect::>() - .join("\n") - }) - .unwrap_or_default() + .iter() + .map(|(k, t)| get_dummy_field(2, k, t)) + .filter_map(|x| x) // Add this line to filter out None values + .collect::>() + .join("\n") ); let wasm_span = match f.span() { @@ -804,15 +795,12 @@ impl WasmRuntime { signature: { let inputs = f .inputs() - .right() - .map(|func_params| { - func_params - .iter() - .map(|(k, t)| format!("{}: {}", k, t)) - .collect::>() - .join(", ") - }) - .unwrap_or_default(); + .iter() + .map(|(k, t)| get_dummy_field(2, k, t)) + .filter_map(|x| x) // Add this line to filter out None values + .collect::>() + .join(","); + format!("({}) -> {}", inputs, f.output().to_string()) }, test_snippet: snippet, @@ -852,20 +840,17 @@ impl WasmRuntime { }; // Any missing params should be set to an error - let _ = f.inputs().right().map(|func_params| { - for (param_name, t) in func_params { - if !params.iter().any(|p| p.name.cmp(param_name).is_eq()) - && !t.is_optional() - { - params.insert( - 0, - WasmParam { - name: param_name.to_string(), - value: None, - error: Some("Missing parameter".to_string()), - }, - ); - } + f.inputs().iter().for_each(|(param_name, t)| { + if !params.iter().any(|p| p.name == *param_name) && !t.is_optional() + { + params.insert( + 0, + WasmParam { + name: param_name.to_string(), + value: None, + error: Some("Missing parameter".to_string()), + }, + ); } }); diff --git a/engine/language-client-codegen/src/python/mod.rs b/engine/language-client-codegen/src/python/mod.rs index c94cdd547..4cfa227d8 100644 --- a/engine/language-client-codegen/src/python/mod.rs +++ b/engine/language-client-codegen/src/python/mod.rs @@ -150,23 +150,21 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for PythonClient let functions = ir .walk_functions() .map(|f| { - let Either::Right(configs) = f.walk_impls() else { - return Ok(vec![]); - }; + let configs = f.walk_impls(); + let funcs = configs + .into_iter() .map(|c| { let (_function, _impl_) = c.item; Ok(PythonFunction { name: f.name().to_string(), partial_return_type: f.elem().output().to_partial_type_ref(ir), return_type: f.elem().output().to_type_ref(ir), - args: match f.inputs() { - either::Either::Left(_args) => anyhow::bail!("Python codegen does not support unnamed args: please add names to all arguments of BAML function '{}'", f.name().to_string()), - either::Either::Right(args) => args - .iter() - .map(|(name, r#type)| (name.to_string(), r#type.to_type_ref(ir))) - .collect(), - }, + args: f + .inputs() + .iter() + .map(|(name, r#type)| (name.to_string(), r#type.to_type_ref(ir))) + .collect(), }) }) .collect::>>()?; @@ -174,7 +172,8 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for PythonClient }) .collect::>>>()? .into_iter() - .flatten().collect(); + .flatten() + .collect(); Ok(PythonClient { funcs: functions }) } } diff --git a/engine/language-client-codegen/src/ruby/mod.rs b/engine/language-client-codegen/src/ruby/mod.rs index f7de3bb9d..1e7c29b4c 100644 --- a/engine/language-client-codegen/src/ruby/mod.rs +++ b/engine/language-client-codegen/src/ruby/mod.rs @@ -3,7 +3,7 @@ mod field_type; mod generate_types; mod ruby_language_features; -use std::{path::PathBuf}; +use std::path::PathBuf; use anyhow::Result; use indexmap::IndexMap; @@ -58,9 +58,8 @@ impl<'ir> TryFrom<(&'ir IntermediateRepr, &'ir crate::GeneratorArgs)> for RubyCl let functions = ir .walk_functions() .map(|f| { - let Either::Right(configs) = f.walk_impls() else { - return Ok(vec![]); - }; + let configs = f.walk_impls(); + let funcs = configs .map(|c| { let (_function, _impl_) = c.item; @@ -68,13 +67,11 @@ impl<'ir> TryFrom<(&'ir IntermediateRepr, &'ir crate::GeneratorArgs)> for RubyCl name: f.name().to_string(), partial_return_type: f.elem().output().to_partial_type_ref(), return_type: f.elem().output().to_ruby(), - args: match f.inputs() { - either::Either::Left(_args) => anyhow::bail!("Ruby codegen does not support unnamed args: please add names to all arguments of BAML function '{}'", f.name().to_string()), - either::Either::Right(args) => args - .iter() - .map(|(name, r#type)| (name.to_string(), r#type.to_ruby())) - .collect(), - }, + args: f + .inputs() + .iter() + .map(|(name, r#type)| (name.to_string(), r#type.to_type_ref())) + .collect(), }) }) .collect::>>()?; @@ -82,7 +79,8 @@ impl<'ir> TryFrom<(&'ir IntermediateRepr, &'ir crate::GeneratorArgs)> for RubyCl }) .collect::>>>()? .into_iter() - .flatten().collect(); + .flatten() + .collect(); Ok(RubyClient { funcs: functions }) } } diff --git a/engine/language-client-codegen/src/typescript/mod.rs b/engine/language-client-codegen/src/typescript/mod.rs index a4946173d..26d241271 100644 --- a/engine/language-client-codegen/src/typescript/mod.rs +++ b/engine/language-client-codegen/src/typescript/mod.rs @@ -122,9 +122,8 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for TypescriptCli let functions = ir .walk_functions() .map(|f| { - let Either::Right(configs) = f.walk_impls() else { - return Ok(vec![]); - }; + let configs = f.walk_impls(); + let funcs = configs .map(|c| { let (_function, _impl_) = c.item; @@ -132,15 +131,13 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for TypescriptCli name: f.name().to_string(), return_type: f.elem().output().to_type_ref(ir), // partial_return_type: f.elem().output().to_partial_type_ref(ir), - args: match f.inputs() { - either::Either::Left(_args) => anyhow::bail!("Typescript codegen does not support unnamed args: please add names to all arguments of BAML function '{}'", f.name().to_string()), - either::Either::Right(args) => args - .iter() - .map(|(name, r#type)| (name.to_string(), - r#type.is_optional(), - r#type.to_type_ref(ir))) - .collect(), - }, + args: f + .inputs() + .iter() + .map(|(name, r#type)| { + (name.to_string(), false, r#type.to_type_ref(ir)) + }) + .collect(), }) }) .collect::>>()?; @@ -148,7 +145,8 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for TypescriptCli }) .collect::>>>()? .into_iter() - .flatten().collect(); + .flatten() + .collect(); let types = ir .walk_classes() diff --git a/integ-tests/.vscode/settings.json b/integ-tests/.vscode/settings.json deleted file mode 100644 index 02233bba8..000000000 --- a/integ-tests/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "baml.path": "/Users/vbv/repos/gloo-lang/engine/target/debug/baml" -} diff --git a/integ-tests/baml_src/main.baml b/integ-tests/baml_src/main.baml index 8599e7730..e92a2415d 100644 --- a/integ-tests/baml_src/main.baml +++ b/integ-tests/baml_src/main.baml @@ -1,17 +1,17 @@ generator lang_python { output_type python/pydantic output_dir "../python" - version "0.51.0" + version "0.52.1" } generator lang_typescript { output_type typescript output_dir "../typescript" - version "0.51.0" + version "0.52.1" } generator lang_ruby { output_type ruby/sorbet output_dir "../ruby" - version "0.51.0" + version "0.52.1" } diff --git a/integ-tests/baml_src/test-files/dynamic/client-registry.baml b/integ-tests/baml_src/test-files/dynamic/client-registry.baml new file mode 100644 index 000000000..8f6d058f4 --- /dev/null +++ b/integ-tests/baml_src/test-files/dynamic/client-registry.baml @@ -0,0 +1,16 @@ +// Intentionally use a bad key +client BadClient { + provider openai + options { + model "gpt-3.5-turbo" + api_key "sk-invalid" + } +} + +function ExpectFailure() -> string { + client BadClient + + prompt #" + What is the capital of England? + "# +} diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image-list.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image-list.baml new file mode 100644 index 000000000..e9cfaeb32 --- /dev/null +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-image-list.baml @@ -0,0 +1,23 @@ +function TestImageListInput(imgs: image[]) -> string{ + client GPT4o + prompt #" + {{ _.role("user") }} + + What colors do these have in common? {{imgs}} + "# +} + +test TestImageListInput { + functions [TestImageListInput] + args { + imgs [ + { + media_type "image/png" + url "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png" + }, + { + url "https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png" + } + ] + } +} diff --git a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-map-string-to-map.baml b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-map-string-to-map.baml index b00d2bc97..9148282a9 100644 --- a/integ-tests/baml_src/test-files/functions/input/named-args/single/named-map-string-to-map.baml +++ b/integ-tests/baml_src/test-files/functions/input/named-args/single/named-map-string-to-map.baml @@ -15,4 +15,4 @@ test TestFnNamedArgsSingleMapStringToMap { } } } -} +} \ No newline at end of file diff --git a/integ-tests/baml_src/test-files/providers/providers.baml b/integ-tests/baml_src/test-files/providers/providers.baml index db79b8dbb..85888e90e 100644 --- a/integ-tests/baml_src/test-files/providers/providers.baml +++ b/integ-tests/baml_src/test-files/providers/providers.baml @@ -57,10 +57,11 @@ function TestAws(input: string) -> string { test TestProvider { - functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws] + functions [TestAnthropic, TestVertex, PromptTestOpenAI, TestAzure, TestOllama, TestGemini, TestAws] args { input "Donkey kong and peanut butter" } } + diff --git a/integ-tests/python/baml_client/async_client.py b/integ-tests/python/baml_client/async_client.py index 75b753fc0..a7ac3b92b 100644 --- a/integ-tests/python/baml_client/async_client.py +++ b/integ-tests/python/baml_client/async_client.py @@ -371,6 +371,30 @@ async def DynamicListInputOutput( mdl = create_model("DynamicListInputOutputReturnType", inner=(List[types.DynInputOutput], ...)) return coerce(mdl, raw.parsed()) + async def ExpectFailure( + self, + + baml_options: BamlCallOptions = {}, + ) -> str: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = await self.__runtime.call_function( + "ExpectFailure", + { + + }, + self.__ctx_manager.get(), + tb, + __cr__, + ) + mdl = create_model("ExpectFailureReturnType", inner=(str, ...)) + return coerce(mdl, raw.parsed()) + async def ExtractNames( self, input: str, @@ -1523,6 +1547,30 @@ async def TestImageInput( mdl = create_model("TestImageInputReturnType", inner=(str, ...)) return coerce(mdl, raw.parsed()) + async def TestImageListInput( + self, + imgs: List[baml_py.Image], + baml_options: BamlCallOptions = {}, + ) -> str: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = await self.__runtime.call_function( + "TestImageListInput", + { + "imgs": imgs, + }, + self.__ctx_manager.get(), + tb, + __cr__, + ) + mdl = create_model("TestImageListInputReturnType", inner=(str, ...)) + return coerce(mdl, raw.parsed()) + async def TestMulticlassNamedArgs( self, myArg: types.NamedArgsSingleClass,myArg2: types.NamedArgsSingleClass, @@ -2134,6 +2182,38 @@ def DynamicListInputOutput( self.__ctx_manager.get(), ) + def ExpectFailure( + self, + + baml_options: BamlCallOptions = {}, + ) -> baml_py.BamlStream[Optional[str], str]: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.stream_function( + "ExpectFailure", + { + }, + None, + self.__ctx_manager.get(), + tb, + __cr__, + ) + + mdl = create_model("ExpectFailureReturnType", inner=(str, ...)) + partial_mdl = create_model("ExpectFailurePartialReturnType", inner=(Optional[str], ...)) + + return baml_py.BamlStream[Optional[str], str]( + raw, + lambda x: coerce(partial_mdl, x), + lambda x: coerce(mdl, x), + self.__ctx_manager.get(), + ) + def ExtractNames( self, input: str, @@ -3718,6 +3798,39 @@ def TestImageInput( self.__ctx_manager.get(), ) + def TestImageListInput( + self, + imgs: List[baml_py.Image], + baml_options: BamlCallOptions = {}, + ) -> baml_py.BamlStream[Optional[str], str]: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.stream_function( + "TestImageListInput", + { + "imgs": imgs, + }, + None, + self.__ctx_manager.get(), + tb, + __cr__, + ) + + mdl = create_model("TestImageListInputReturnType", inner=(str, ...)) + partial_mdl = create_model("TestImageListInputPartialReturnType", inner=(Optional[str], ...)) + + return baml_py.BamlStream[Optional[str], str]( + raw, + lambda x: coerce(partial_mdl, x), + lambda x: coerce(mdl, x), + self.__ctx_manager.get(), + ) + def TestMulticlassNamedArgs( self, myArg: types.NamedArgsSingleClass,myArg2: types.NamedArgsSingleClass, diff --git a/integ-tests/python/baml_client/inlinedbaml.py b/integ-tests/python/baml_client/inlinedbaml.py index 42299a46e..156658d86 100644 --- a/integ-tests/python/baml_client/inlinedbaml.py +++ b/integ-tests/python/baml_client/inlinedbaml.py @@ -24,10 +24,11 @@ "fiddle-examples/extract-receipt-info.baml": "class ReceiptItem {\n name string\n description string?\n quantity int\n price float\n}\n\nclass ReceiptInfo {\n items ReceiptItem[]\n total_cost float?\n}\n\nfunction ExtractReceiptInfo(email: string) -> ReceiptInfo {\n client GPT4o\n prompt #\"\n Given the receipt below:\n\n ```\n {{email}}\n ```\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "fiddle-examples/images/image.baml": "function DescribeImage(img: image) -> string {\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n\n Describe the image below in 20 words:\n {{ img }}\n \"#\n\n}\n\nclass FakeImage {\n url string\n}\n\nclass ClassWithImage {\n myImage image\n param2 string\n fake_image FakeImage\n}\n\n// chat role user present\nfunction DescribeImage2(classWithImage: ClassWithImage, img2: image) -> string { \n client GPT4Turbo\n prompt #\"\n {{ _.role(\"user\") }}\n You should return 2 answers that answer the following commands.\n\n 1. Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n 2. Also tell me what's happening here in one sentence:\n {{ img2 }}\n \"#\n}\n\n// no chat role\nfunction DescribeImage3(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\n\n// system prompt and chat prompt\nfunction DescribeImage4(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n {{ _.role(\"system\")}}\n\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\ntest TestName {\n functions [DescribeImage]\n args {\n img { url \"https://imgs.xkcd.com/comics/standards.png\"}\n }\n}\n", "fiddle-examples/symbol-tuning.baml": "enum Category3 {\n Refund @alias(\"k1\")\n @description(\"Customer wants to refund a product\")\n\n CancelOrder @alias(\"k2\")\n @description(\"Customer wants to cancel an order\")\n\n TechnicalSupport @alias(\"k3\")\n @description(\"Customer needs help with a technical issue unrelated to account creation or login\")\n\n AccountIssue @alias(\"k4\")\n @description(\"Specifically relates to account-login or account-creation\")\n\n Question @alias(\"k5\")\n @description(\"Customer has a question\")\n}\n\nfunction ClassifyMessage3(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", - "main.baml": "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.51.0\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.51.0\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.51.0\"\n}\n", + "main.baml": "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.52.1\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.52.1\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.52.1\"\n}\n", "test-files/aliases/classes.baml": "class TestClassAlias {\n key string @alias(\"key-dash\") @description(#\"\n This is a description for key\n af asdf\n \"#)\n key2 string @alias(\"key21\")\n key3 string @alias(\"key with space\")\n key4 string //unaliased\n key5 string @alias(\"key.with.punctuation/123\")\n}\n\nfunction FnTestClassAlias(input: string) -> TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml": "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml": "// add some functions, classes, enums etc with comments all over.", + "test-files/dynamic/client-registry.baml": "// Intentionally use a bad key\nclient BadClient {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key \"sk-invalid\"\n }\n}\n\nfunction ExpectFailure() -> string {\n client BadClient\n\n prompt #\"\n What is the capital of England?\n \"#\n}\n", "test-files/dynamic/dynamic.baml": "class DynamicClassOne {\n @@dynamic\n}\n\nenum DynEnumOne {\n @@dynamic\n}\n\nenum DynEnumTwo {\n @@dynamic\n}\n\nclass SomeClassNestedDynamic {\n hi string\n @@dynamic\n\n}\n\nclass DynamicClassTwo {\n hi string\n some_class SomeClassNestedDynamic\n status DynEnumOne\n @@dynamic\n}\n\nfunction DynamicFunc(input: DynamicClassOne) -> DynamicClassTwo {\n client GPT35\n prompt #\"\n Please extract the schema from \n {{ input }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass DynInputOutput {\n testKey string\n @@dynamic\n}\n\nfunction DynamicInputOutput(input: DynInputOutput) -> DynInputOutput {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\nfunction DynamicListInputOutput(input: DynInputOutput[]) -> DynInputOutput[] {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\n\n\nclass DynamicOutput {\n @@dynamic\n}\n \nfunction MyFunc(input: string) -> DynamicOutput {\n client GPT35\n prompt #\"\n Given a string, extract info using the schema:\n\n {{ input}}\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "test-files/functions/input/named-args/single/named-audio.baml": "function AudioInput(aud: audio) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Does this sound like a roar? Yes or no? One word no other characters.\n \n {{ aud }}\n \"#\n}\n\n\ntest TestURLAudioInput{\n functions [AudioInput]\n args {\n aud{ \n url https://actions.google.com/sounds/v1/emergency/beeper_emergency_call.ogg\n }\n } \n}\n\n\n", "test-files/functions/input/named-args/single/named-boolean.baml": "\n\nfunction TestFnNamedArgsSingleBool(myBool: bool) -> string{\n client Vertex\n prompt #\"\n Return this value back to me: {{myBool}}\n \"#\n}\n\ntest TestFnNamedArgsSingleBool {\n functions [TestFnNamedArgsSingleBool]\n args {\n myBool true\n }\n}", @@ -36,10 +37,11 @@ "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", + "test-files/functions/input/named-args/single/named-image-list.baml": "function TestImageListInput(imgs: image[]) -> string{\n client GPT4o\n prompt #\"\n {{ _.role(\"user\") }}\n\n What colors do these have in common? {{imgs}}\n \"#\n}\n\ntest TestImageListInput {\n functions [TestImageListInput]\n args {\n imgs [\n {\n media_type \"image/png\"\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n },\n {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n ]\n }\n}\n", "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n media_type \"image/png\"\n // url gs://cloud-samples-data/vertex-ai/llm/prompts/landmark1.png\n\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n \n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-map-string-to-class.baml": "class StringToClassEntry {\n word string\n}\n// test string\nfunction TestFnNamedArgsSingleMapStringToClass(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToClass {\n functions [TestFnNamedArgsSingleMapStringToClass]\n args {\n myMap {\n \"key\" {\n word \"lorem ipsum\"\n }\n }\n }\n}\n", - "test-files/functions/input/named-args/single/named-map-string-to-map.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}\n", + "test-files/functions/input/named-args/single/named-map-string-to-map.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}", "test-files/functions/input/named-args/single/named-map-string-to-string.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToString(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToString {\n functions [TestFnNamedArgsSingleMapStringToString]\n args {\n myMap {\n \"key\" \"example string\"\n }\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", @@ -64,7 +66,7 @@ "test-files/functions/prompts/no-chat-messages.baml": "\n\nfunction PromptTestClaude(input: string) -> string {\n client Claude\n prompt #\"\n Tell me a haiku about {{ input }}\n \"#\n}\n\n\nfunction PromptTestStreaming(input: string) -> string {\n client GPT35\n prompt #\"\n Tell me a short story about {{ input }}\n \"#\n}\n\ntest TestName {\n functions [PromptTestStreaming]\n args {\n input #\"\n hello world\n \"#\n }\n}\n", "test-files/functions/prompts/with-chat-messages.baml": "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml": "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", - "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", + "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, PromptTestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n\n", "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", "test-files/strategies/roundrobin.baml": "", diff --git a/integ-tests/python/baml_client/sync_client.py b/integ-tests/python/baml_client/sync_client.py index 2e0030472..4de353f9e 100644 --- a/integ-tests/python/baml_client/sync_client.py +++ b/integ-tests/python/baml_client/sync_client.py @@ -369,6 +369,30 @@ def DynamicListInputOutput( mdl = create_model("DynamicListInputOutputReturnType", inner=(List[types.DynInputOutput], ...)) return coerce(mdl, raw.parsed()) + def ExpectFailure( + self, + + baml_options: BamlCallOptions = {}, + ) -> str: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.call_function_sync( + "ExpectFailure", + { + + }, + self.__ctx_manager.get(), + tb, + __cr__, + ) + mdl = create_model("ExpectFailureReturnType", inner=(str, ...)) + return coerce(mdl, raw.parsed()) + def ExtractNames( self, input: str, @@ -1521,6 +1545,30 @@ def TestImageInput( mdl = create_model("TestImageInputReturnType", inner=(str, ...)) return coerce(mdl, raw.parsed()) + def TestImageListInput( + self, + imgs: List[baml_py.Image], + baml_options: BamlCallOptions = {}, + ) -> str: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.call_function_sync( + "TestImageListInput", + { + "imgs": imgs, + }, + self.__ctx_manager.get(), + tb, + __cr__, + ) + mdl = create_model("TestImageListInputReturnType", inner=(str, ...)) + return coerce(mdl, raw.parsed()) + def TestMulticlassNamedArgs( self, myArg: types.NamedArgsSingleClass,myArg2: types.NamedArgsSingleClass, @@ -2133,6 +2181,38 @@ def DynamicListInputOutput( self.__ctx_manager.get(), ) + def ExpectFailure( + self, + + baml_options: BamlCallOptions = {}, + ) -> baml_py.BamlSyncStream[Optional[str], str]: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.stream_function_sync( + "ExpectFailure", + { + }, + None, + self.__ctx_manager.get(), + tb, + __cr__, + ) + + mdl = create_model("ExpectFailureReturnType", inner=(str, ...)) + partial_mdl = create_model("ExpectFailurePartialReturnType", inner=(Optional[str], ...)) + + return baml_py.BamlSyncStream[Optional[str], str]( + raw, + lambda x: coerce(partial_mdl, x), + lambda x: coerce(mdl, x), + self.__ctx_manager.get(), + ) + def ExtractNames( self, input: str, @@ -3717,6 +3797,39 @@ def TestImageInput( self.__ctx_manager.get(), ) + def TestImageListInput( + self, + imgs: List[baml_py.Image], + baml_options: BamlCallOptions = {}, + ) -> baml_py.BamlSyncStream[Optional[str], str]: + __tb__ = baml_options.get("tb", None) + if __tb__ is not None: + tb = __tb__._tb + else: + tb = None + __cr__ = baml_options.get("client_registry", None) + + raw = self.__runtime.stream_function_sync( + "TestImageListInput", + { + "imgs": imgs, + }, + None, + self.__ctx_manager.get(), + tb, + __cr__, + ) + + mdl = create_model("TestImageListInputReturnType", inner=(str, ...)) + partial_mdl = create_model("TestImageListInputPartialReturnType", inner=(Optional[str], ...)) + + return baml_py.BamlSyncStream[Optional[str], str]( + raw, + lambda x: coerce(partial_mdl, x), + lambda x: coerce(mdl, x), + self.__ctx_manager.get(), + ) + def TestMulticlassNamedArgs( self, myArg: types.NamedArgsSingleClass,myArg2: types.NamedArgsSingleClass, diff --git a/integ-tests/python/baml_client/type_builder.py b/integ-tests/python/baml_client/type_builder.py index 4e309e1d2..c27dfba97 100644 --- a/integ-tests/python/baml_client/type_builder.py +++ b/integ-tests/python/baml_client/type_builder.py @@ -27,36 +27,43 @@ def __init__(self): @property + def DummyOutput(self) -> "DummyOutputBuilder": return DummyOutputBuilder(self) @property + def DynInputOutput(self) -> "DynInputOutputBuilder": return DynInputOutputBuilder(self) @property + def DynamicClassOne(self) -> "DynamicClassOneBuilder": return DynamicClassOneBuilder(self) @property + def DynamicClassTwo(self) -> "DynamicClassTwoBuilder": return DynamicClassTwoBuilder(self) @property + def DynamicOutput(self) -> "DynamicOutputBuilder": return DynamicOutputBuilder(self) @property + def Person(self) -> "PersonBuilder": return PersonBuilder(self) @property + def SomeClassNestedDynamic(self) -> "SomeClassNestedDynamicBuilder": return SomeClassNestedDynamicBuilder(self) diff --git a/integ-tests/python/poetry.lock b/integ-tests/python/poetry.lock index 7a6417105..aa14046b0 100644 --- a/integ-tests/python/poetry.lock +++ b/integ-tests/python/poetry.lock @@ -11,8 +11,20 @@ files = [ {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} +[[package]] +name = "ansi2html" +version = "1.9.2" +description = "Convert text with ANSI color codes to HTML or to LaTeX" +optional = false +python-versions = ">=3.7" +files = [ + {file = "ansi2html-1.9.2-py3-none-any.whl", hash = "sha256:dccb75aa95fb018e5d299be2b45f802952377abfdce0504c17a6ee6ef0a420c5"}, + {file = "ansi2html-1.9.2.tar.gz", hash = "sha256:3453bf87535d37b827b05245faaa756dbab4ec3d69925e352b6319c3c955c0a5"}, +] + +[package.extras] +docs = ["mkdocs", "mkdocs-material", "mkdocs-material-extensions", "mkdocstrings", "mkdocstrings-python", "pymdown-extensions"] +test = ["pytest", "pytest-cov"] [[package]] name = "assertpy" @@ -35,6 +47,17 @@ files = [ {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] +[[package]] +name = "docutils" +version = "0.21.2" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +files = [ + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, +] + [[package]] name = "exceptiongroup" version = "1.2.1" @@ -49,6 +72,16 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "htmlmin" +version = "0.1.12" +description = "An HTML Minifier" +optional = false +python-versions = "*" +files = [ + {file = "htmlmin-0.1.12.tar.gz", hash = "sha256:50c1ef4630374a5d723900096a961cff426dff46b48f34d194a81bbe14eca178"}, +] + [[package]] name = "iniconfig" version = "2.0.0" @@ -60,6 +93,92 @@ files = [ {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, ] +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + [[package]] name = "maturin" version = "1.7.0" @@ -278,6 +397,38 @@ pytest = ">=7.0.0,<9" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +[[package]] +name = "pytest-reporter" +version = "0.5.3" +description = "Generate Pytest reports with templates" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-reporter-0.5.3.tar.gz", hash = "sha256:426ae38f3c5304659635eff1d4080c8acf4dc6cd833469caed427a9a80bb41aa"}, + {file = "pytest_reporter-0.5.3-py3-none-any.whl", hash = "sha256:fa39fef46b1926b6f181c2759da0bcfd26b7697ef59d3c5cd260106c59b3a196"}, +] + +[package.dependencies] +pytest = "*" + +[[package]] +name = "pytest-reporter-html1" +version = "0.9.0" +description = "A basic HTML report template for Pytest" +optional = false +python-versions = ">=3.5" +files = [ + {file = "pytest_reporter_html1-0.9.0-py3-none-any.whl", hash = "sha256:bea469c9c5645c8e78fe561acc8f3769523791b64e8356699bcf00ee09fbd2a1"}, + {file = "pytest_reporter_html1-0.9.0.tar.gz", hash = "sha256:587bb31ba1ab1cc3c9b1e50556da0213d2fc47d6a18fa63b457523088877110a"}, +] + +[package.dependencies] +ansi2html = ">=1.3.0" +docutils = "*" +htmlmin = "*" +Jinja2 = "*" +pytest-reporter = ">=0.4.0" + [[package]] name = "python-dotenv" version = "1.0.1" @@ -329,6 +480,17 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "types-assertpy" +version = "1.1.0.20240712" +description = "Typing stubs for assertpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-assertpy-1.1.0.20240712.tar.gz", hash = "sha256:c332d09298b158f09890af12f14d83ebb9f0e5014e91219ae145a6a5af9220f9"}, + {file = "types_assertpy-1.1.0.20240712-py3-none-any.whl", hash = "sha256:3962d4d863e4c091b9a8d7f02e3ee0d2ac06f25bdca0e6e4f848cf54c7214455"}, +] + [[package]] name = "typing-extensions" version = "4.12.2" @@ -342,5 +504,5 @@ files = [ [metadata] lock-version = "2.0" -python-versions = "^3.8" -content-hash = "75bc9294db7074ba805acc12ba1a8a201c8099a40f8ffe1d2e2aefb14d48e5e6" +python-versions = "^3.9" +content-hash = "f1010cbc8be8e1834417568db7e031ae5c263c67eaf867c6cd78c1848b370602" diff --git a/integ-tests/python/pyproject.toml b/integ-tests/python/pyproject.toml index 8c58d850b..425ef3fdf 100644 --- a/integ-tests/python/pyproject.toml +++ b/integ-tests/python/pyproject.toml @@ -20,6 +20,10 @@ pytest = "^8.2.1" pydantic = "^2.7.1" python-dotenv = "^1.0.1" assertpy = "^1.1" +pytest-reporter-html1 = "^0.9.0" + +[tool.poetry.group.dev.dependencies] +types-assertpy = "^1.1.0.20240712" [build-system] requires = ["poetry-core"] diff --git a/integ-tests/python/report.html b/integ-tests/python/report.html new file mode 100644 index 000000000..5771aed5d --- /dev/null +++ b/integ-tests/python/report.html @@ -0,0 +1,1859 @@ + Test Report
Test Report

Summary

52
2 failed 50 passed

Tests

tests/test_functions.py 250 0:01:50.714413

PASSED test_sync 0:00:00.534744

Setup

Call

Captured stdout call
got response key
+true
+52
+
Captured stderr call
[2024-07-24T06:55:26Z INFO  baml_events] Function TestFnNamedArgsSingleClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 428ms
+    ---PROMPT---
+    [chat] system: Print these values back to me:
+    key
+    true
+    52
+    
+    ---LLM REPLY---
+    key
+    true
+    52
+    ---Parsed Response (string)---
+    "key\ntrue\n52"
+

Teardown

FAILED TestAllInputs::test_single_bool 0:00:00.005768

baml_py.BamlError: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Return this value back to me: true")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804126, tv_nsec: 56738000 }, latency: 211.792µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }

Setup

Call

self = 
+
+>   ???
+
+tests/test_functions.py:46: 
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+
+self = , myBool = True, baml_options = {}
+
+    async def TestFnNamedArgsSingleBool(
+        self,
+        myBool: bool,
+        baml_options: BamlCallOptions = {},
+    ) -> str:
+      __tb__ = baml_options.get("tb", None)
+      if __tb__ is not None:
+        tb = __tb__._tb
+      else:
+        tb = None
+      __cr__ = baml_options.get("client_registry", None)
+    
+      raw = await self.__runtime.call_function(
+        "TestFnNamedArgsSingleBool",
+        {
+          "myBool": myBool,
+        },
+        self.__ctx_manager.get(),
+        tb,
+        __cr__,
+      )
+      mdl = create_model("TestFnNamedArgsSingleBoolReturnType", inner=(str, ...))
+>     return coerce(mdl, raw.parsed())
+E     baml_py.BamlError: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Return this value back to me: true")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804126, tv_nsec: 56738000 }, latency: 211.792µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+
+baml_client/async_client.py:1260: BamlError
Captured stderr call
[2024-07-24T06:55:26Z WARN  baml_events] Function TestFnNamedArgsSingleBool:
+    LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Return this value back to me: true")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804126, tv_nsec: 56738000 }, latency: 211.792µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+    
+

Teardown

PASSED TestAllInputs::test_single_string_list 0:00:00.493555

Setup

Call

Captured stderr call
[2024-07-24T06:55:26Z INFO  baml_events] Function TestFnNamedArgsSingleStringList:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 487ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: ["a", "b", "c"]
+    
+    ---LLM REPLY---
+    ["a", "b", "c"]
+    ---Parsed Response (string)---
+    "[\"a\", \"b\", \"c\"]"
+

Teardown

PASSED TestAllInputs::test_single_class 0:00:00.666710

Setup

Call

Captured stderr call
[2024-07-24T06:55:27Z INFO  baml_events] Function TestFnNamedArgsSingleClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 660ms
+    ---PROMPT---
+    [chat] system: Print these values back to me:
+    key
+    true
+    52
+    
+    ---LLM REPLY---
+    key
+    true
+    52
+    ---Parsed Response (string)---
+    "key\ntrue\n52"
+

Teardown

PASSED TestAllInputs::test_multiple_args 0:00:00.500088

Setup

Call

Captured stderr call
[2024-07-24T06:55:27Z INFO  baml_events] Function TestMulticlassNamedArgs:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 496ms
+    ---PROMPT---
+    [chat] system: Print these values back to me:
+    key
+    true
+    52
+    key
+    true
+    64
+    
+    ---LLM REPLY---
+    key
+    true
+    52
+    key
+    true
+    64
+    ---Parsed Response (string)---
+    "key\ntrue\n52\nkey\ntrue\n64"
+

Teardown

PASSED TestAllInputs::test_single_enum_list 0:00:00.449131

Setup

Call

Captured stderr call
[2024-07-24T06:55:28Z INFO  baml_events] Function TestFnNamedArgsSingleEnumList:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 443ms
+    ---PROMPT---
+    [chat] system: Print these values back to me:
+    ["TWO"]
+    
+    ---LLM REPLY---
+    ["TWO"]
+    ---Parsed Response (string)---
+    "[\"TWO\"]"
+

Teardown

PASSED TestAllInputs::test_single_float 0:00:00.356849

Setup

Call

Captured stderr call
[2024-07-24T06:55:28Z INFO  baml_events] Function TestFnNamedArgsSingleFloat:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 349ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: 3.12
+    
+    ---LLM REPLY---
+    3.12
+    ---Parsed Response (string)---
+    "3.12"
+

Teardown

PASSED TestAllInputs::test_single_int 0:00:00.416914

Setup

Call

Captured stderr call
[2024-07-24T06:55:28Z INFO  baml_events] Function TestFnNamedArgsSingleInt:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 409ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: 3566
+    
+    ---LLM REPLY---
+    3566
+    ---Parsed Response (string)---
+    "3566"
+

Teardown

PASSED TestAllInputs::test_single_map_string_to_string 0:00:00.522399

Setup

Call

Captured stderr call
[2024-07-24T06:55:29Z INFO  baml_events] Function TestFnNamedArgsSingleMapStringToString:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 515ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: {"dolor": "sit", "lorem": "ipsum"}
+    
+    ---LLM REPLY---
+    {"dolor": "sit", "lorem": "ipsum"}
+    ---Parsed Response (map<string, string>)---
+    {
+      "dolor": "sit",
+      "lorem": "ipsum"
+    }
+

Teardown

PASSED TestAllInputs::test_single_map_string_to_class 0:00:00.546157

Setup

Call

Captured stderr call
[2024-07-24T06:55:30Z INFO  baml_events] Function TestFnNamedArgsSingleMapStringToClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 538ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: {"lorem": {"word": "ipsum"}}
+    
+    ---LLM REPLY---
+    {"lorem": {"word": "ipsum"}}
+    ---Parsed Response (map<string, class StringToClassEntry>)---
+    {
+      "lorem": {
+        "word": "ipsum"
+      }
+    }
+

Teardown

PASSED TestAllInputs::test_single_map_string_to_map 0:00:00.502944

Setup

Call

Captured stderr call
[2024-07-24T06:55:30Z INFO  baml_events] Function TestFnNamedArgsSingleMapStringToMap:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 494ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: {"lorem": {"word": "ipsum"}}
+    
+    ---LLM REPLY---
+    {"lorem": {"word": "ipsum"}}
+    ---Parsed Response (map<string, map<string, string>>)---
+    {
+      "lorem": {
+        "word": "ipsum"
+      }
+    }
+

Teardown

PASSED test_should_work_for_all_outputs 0:00:03.662266

Setup

Call

Captured stderr call
[2024-07-24T06:55:31Z INFO  baml_events] Function FnOutputBool:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 514ms
+    ---PROMPT---
+    [chat] system: Return a true: Answer as a: bool
+    
+    ---LLM REPLY---
+    True
+    ---Parsed Response (bool)---
+    true
+[2024-07-24T06:55:31Z INFO  baml_events] Function FnOutputClassList:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 685ms
+    ---PROMPT---
+    [chat] system: Return a JSON array that follows this schema: 
+    Answer with a JSON Array using this schema:
+    [
+      {
+        prop1: string,
+        prop2: int,
+      }
+    ]
+    
+    JSON:
+    
+    ---LLM REPLY---
+    [
+      {
+        prop1: "example1",
+        prop2: 123
+      },
+      {
+        prop1: "example2",
+        prop2: 456
+      }
+    ]
+    ---Parsed Response (list<class TestOutputClass>)---
+    [
+      {
+        "prop1": "example1",
+        "prop2": 123
+      },
+      {
+        "prop1": "example2",
+        "prop2": 456
+      }
+    ]
+[2024-07-24T06:55:32Z INFO  baml_events] Function FnOutputClassWithEnum:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 464ms
+    ---PROMPT---
+    [chat] system: Return a made up json blob that matches this schema:
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: 'ONE' or 'TWO',
+    }
+    ---
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "Hello World",
+      "prop2": "ONE"
+    }
+    ---Parsed Response (class TestClassWithEnum)---
+    {
+      "prop1": "Hello World",
+      "prop2": "ONE"
+    }
+[2024-07-24T06:55:32Z INFO  baml_events] Function FnOutputClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 706ms
+    ---PROMPT---
+    [chat] system: Return a JSON blob with this schema: 
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: int,
+    }
+    
+    For the prop2, always return a 540
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "Hello World!",
+      "prop2": 540
+    }
+    ---Parsed Response (class TestOutputClass)---
+    {
+      "prop1": "Hello World!",
+      "prop2": 540
+    }
+[2024-07-24T06:55:33Z INFO  baml_events] Function FnEnumListOutput:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 493ms
+    ---PROMPT---
+    [chat] system: Print out two of these values randomly selected from the list below in a json array.
+    
+    Answer with a JSON Array using this schema:
+    [
+      'ONE' or 'TWO' or 'THREE'
+    ]
+    
+    Answer:
+    
+    ---LLM REPLY---
+    [
+      'TWO',
+      'THREE'
+    ]
+    ---Parsed Response (list<enum EnumOutput>)---
+    [
+      "TWO",
+      "THREE"
+    ]
+[2024-07-24T06:55:34Z INFO  baml_events] Function FnEnumOutput:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 762ms
+    ---PROMPT---
+    [chat] system: Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.
+    
+    VALUE_ENUM
+    ----
+    - ONE
+    - TWO
+    - THREE
+    
+    ---LLM REPLY---
+    In the deep blue sea
+    Whispers of the waves in song
+    Nature's melody
+    
+    VALUE_ENUM: TWO
+    ---Parsed Response (enum EnumOutput)---
+    "TWO"
+

Teardown

PASSED test_should_work_with_image_url 0:00:01.725636

Setup

Call

Captured stderr call
[2024-07-24T06:55:35Z INFO  baml_events] Function TestImageInput:
+    Client: Gemini () - 1384ms
+    ---PROMPT---
+    [chat] user: Describe this in 4 words. One word must be the color<image_placeholder base64>
+    
+    ---LLM REPLY---
+    Smiling Green Ogre Standing 
+    
+    ---Parsed Response (string)---
+    "Smiling Green Ogre Standing \n"
+

Teardown

FAILED test_should_work_with_vertex 0:00:00.003132

baml_py.BamlError: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Write a nice short story about donkey kong")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804135, tv_nsec: 966623000 }, latency: 149.875µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }

Setup

Call

@pytest.mark.asyncio
+    async def test_should_work_with_vertex():
+>       res = await b.TestVertex("donkey kong")
+
+tests/test_functions.py:167: 
+_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
+
+self = , input = 'donkey kong', baml_options = {}
+
+    async def TestVertex(
+        self,
+        input: str,
+        baml_options: BamlCallOptions = {},
+    ) -> str:
+      __tb__ = baml_options.get("tb", None)
+      if __tb__ is not None:
+        tb = __tb__._tb
+      else:
+        tb = None
+      __cr__ = baml_options.get("client_registry", None)
+    
+      raw = await self.__runtime.call_function(
+        "TestVertex",
+        {
+          "input": input,
+        },
+        self.__ctx_manager.get(),
+        tb,
+        __cr__,
+      )
+      mdl = create_model("TestVertexReturnType", inner=(str, ...))
+>     return coerce(mdl, raw.parsed())
+E     baml_py.BamlError: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Write a nice short story about donkey kong")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804135, tv_nsec: 966623000 }, latency: 149.875µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+
+baml_client/async_client.py:1692: BamlError
Captured stderr call
[2024-07-24T06:55:35Z WARN  baml_events] Function TestVertex:
+    LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Write a nice short story about donkey kong")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721804135, tv_nsec: 966623000 }, latency: 149.875µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+    
+

Teardown

PASSED test_should_work_with_image_base64 0:00:00.929227

Setup

Call

Captured stderr call
[2024-07-24T06:55:36Z INFO  baml_events] Function TestImageInput:
+    Client: Gemini () - 920ms
+    ---PROMPT---
+    [chat] user: Describe this in 4 words. One word must be the color<image_placeholder base64>
+    
+    ---LLM REPLY---
+    Smiling green ogre Shrek 
+    
+    ---Parsed Response (string)---
+    "Smiling green ogre Shrek \n"
+

Teardown

PASSED test_should_work_with_audio_base64 0:00:00.742629

Setup

Call

Captured stderr call
[2024-07-24T06:55:37Z INFO  baml_events] Function AudioInput:
+    Client: Gemini () - 737ms
+    ---PROMPT---
+    [chat] user: Does this sound like a roar? Yes or no? One word no other characters.<audio_placeholder base64>
+    
+    ---LLM REPLY---
+    Yes 
+    
+    ---Parsed Response (string)---
+    "Yes \n"
+

Teardown

PASSED test_should_work_with_audio_url 0:00:00.966539

Setup

Call

Captured stderr call
[2024-07-24T06:55:38Z INFO  baml_events] Function AudioInput:
+    Client: Gemini () - 736ms
+    ---PROMPT---
+    [chat] user: Does this sound like a roar? Yes or no? One word no other characters.<audio_placeholder base64>
+    
+    ---LLM REPLY---
+    No 
+    
+    ---Parsed Response (string)---
+    "No \n"
+

Teardown

PASSED test_works_with_retries2 0:00:01.881373

Setup

Call

Captured stdout call
Expected error LLM call failed: LLMErrorResponse { client: "RetryClientExponential", model: None, prompt: Chat([RenderedChatMessage { role: "system", parts: [Text("Say a haiku")] }]), request_options: {"model": String("gpt-3.5-turbo")}, start_time: SystemTime { tv_sec: 1721804140, tv_nsec: 420775000 }, latency: 108.466667ms, message: "Request failed: {\n    \"error\": {\n        \"message\": \"Incorrect API key provided: blahh. You can find your API key at https://platform.openai.com/account/api-keys.\",\n        \"type\": \"invalid_request_error\",\n        \"param\": null,\n        \"code\": \"invalid_api_key\"\n    }\n}\n", code: InvalidAuthentication }
+
+
Captured stderr call
[2024-07-24T06:55:40Z WARN  baml_events] Function TestRetryExponential:
+    LLM call failed: LLMErrorResponse { client: "RetryClientExponential", model: None, prompt: Chat([RenderedChatMessage { role: "system", parts: [Text("Say a haiku")] }]), request_options: {"model": String("gpt-3.5-turbo")}, start_time: SystemTime { tv_sec: 1721804140, tv_nsec: 420775000 }, latency: 108.466667ms, message: "Request failed: {\n    \"error\": {\n        \"message\": \"Incorrect API key provided: blahh. You can find your API key at https://platform.openai.com/account/api-keys.\",\n        \"type\": \"invalid_request_error\",\n        \"param\": null,\n        \"code\": \"invalid_api_key\"\n    }\n}\n", code: InvalidAuthentication }
+    
+

Teardown

PASSED test_works_with_fallbacks 0:00:01.609387

Setup

Call

Captured stderr call
[2024-07-24T06:55:42Z INFO  baml_events] Function TestFallbackClient:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 560ms
+    ---PROMPT---
+    [chat] system: Say a haiku about mexico.
+    
+    ---LLM REPLY---
+    Vibrant colors bloom
+    Mariachi music plays
+    Mexico's beauty
+    ---Parsed Response (string)---
+    "Vibrant colors bloom\nMariachi music plays\nMexico's beauty"
+

Teardown

PASSED test_claude 0:00:01.040701

Setup

Call

Captured stderr call
[2024-07-24T06:55:43Z INFO  baml_events] Function PromptTestClaude:
+    Client: Claude (claude-3-haiku-20240307) - 1037ms
+    ---PROMPT---
+    [chat] user: Tell me a haiku about Mt Rainier is tall
+    
+    ---LLM REPLY---
+    Here is a haiku about Mt. Rainier being tall:
+    
+    Snow-capped peak soars high,
+    Majestic Mount Rainier stands,
+    Towering above.
+    ---Parsed Response (string)---
+    "Here is a haiku about Mt. Rainier being tall:\n\nSnow-capped peak soars high,\nMajestic Mount Rainier stands,\nTowering above."
+

Teardown

PASSED test_gemini 0:00:08.600131

Setup

Call

Captured stdout call
LLM output from Gemini: The late afternoon sun streamed through the dusty window of Millie's Emporium, illuminating shelves crammed with oddities and antiques. Millie herself, a woman with a cloud of white hair and eyes that sparkled like polished agates, stood behind the counter, carefully unwrapping a new acquisition. 
+
+It was a bottle, tall and slender, made of thick, cobalt glass. Etched into its surface was a single word: "Dr. Pepper." But this was no ordinary soda bottle. The glass seemed to hum with an inner light, and the etched letters shimmered as if alive.
+
+A soft chime announced a customer. A young boy, all gangly limbs and nervous energy, shuffled in, his eyes drawn to the glowing bottle. 
+
+"What's that?" he whispered, his gaze fixed on the shimmering word.
+
+Millie smiled. "Why, that's a bottle of dreams, dearie."
+
+The boy's eyes widened. "Dreams?"
+
+"Oh yes," Millie said, her voice like rustling leaves. "Dr. Pepper, they used to say, could bottle your deepest desires, your wildest hopes. One sip, and it would all become clear, possible."
+
+The boy, captivated, reached out a hesitant hand. 
+
+Millie gently pushed the bottle back. "Not for sale, dearie. Not this one. This one," she winked, "is for finding." 
+
+She watched as the boy, his head full of dreams and possibilities, left the shop.  He didn't buy anything that day, but he carried something far more valuable – the spark of an idea, a belief that maybe, just maybe, dreams could be bottled, waiting to be discovered by those who dared to search. 
+
+And Millie? She knew her work was done. The bottle of dreams, with its whispered promises and shimmering possibilities, was exactly where it needed to be. The rest, like the faintest hint of cherry and licorice on the air, was up to fate, and a little bit of magic. 
+
+
Captured stderr call
[2024-07-24T06:55:51Z INFO  baml_events] Function TestGemini:
+    Client: Gemini () - 8596ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about Dr. Pepper
+    
+    ---LLM REPLY---
+    The late afternoon sun streamed through the dusty window of Millie's Emporium, illuminating shelves crammed with oddities and antiques. Millie herself, a woman with a cloud of white hair and eyes that sparkled like polished agates, stood behind the counter, carefully unwrapping a new acquisition. 
+    
+    It was a bottle, tall and slender, made of thick, cobalt glass. Etched into its surface was a single word: "Dr. Pepper." But this was no ordinary soda bottle. The glass seemed to hum with an inner light, and the etched letters shimmered as if alive.
+    
+    A soft chime announced a customer. A young boy, all gangly limbs and nervous energy, shuffled in, his eyes drawn to the glowing bottle. 
+    
+    "What's that?" he whispered, his gaze fixed on the shimmering word.
+    
+    Millie smiled. "Why, that's a bottle of dreams, dearie."
+    
+    The boy's eyes widened. "Dreams?"
+    
+    "Oh yes," Millie said, her voice like rustling leaves. "Dr. Pepper, they used to say, could bottle your deepest desires, your wildest hopes. One sip, and it would all become clear, possible."
+    
+    The boy, captivated, reached out a hesitant hand. 
+    
+    Millie gently pushed the bottle back. "Not for sale, dearie. Not this one. This one," she winked, "is for finding." 
+    
+    She watched as the boy, his head full of dreams and possibilities, left the shop.  He didn't buy anything that day, but he carried something far more valuable – the spark of an idea, a belief that maybe, just maybe, dreams could be bottled, waiting to be discovered by those who dared to search. 
+    
+    And Millie? She knew her work was done. The bottle of dreams, with its whispered promises and shimmering possibilities, was exactly where it needed to be. The rest, like the faintest hint of cherry and licorice on the air, was up to fate, and a little bit of magic. 
+    
+    ---Parsed Response (string)---
+    "The late afternoon sun streamed through the dusty window of Millie's Emporium, illuminating shelves crammed with oddities and antiques. Millie herself, a woman with a cloud of white hair and eyes that sparkled like polished agates, stood behind the counter, carefully unwrapping a new acquisition. \n\nIt was a bottle, tall and slender, made of thick, cobalt glass. Etched into its surface was a single word: \"Dr. Pepper.\" But this was no ordinary soda bottle. The glass seemed to hum with an inner light, and the etched letters shimmered as if alive.\n\nA soft chime announced a customer. A young boy, all gangly limbs and nervous energy, shuffled in, his eyes drawn to the glowing bottle. \n\n\"What's that?\" he whispered, his gaze fixed on the shimmering word.\n\nMillie smiled. \"Why, that's a bottle of dreams, dearie.\"\n\nThe boy's eyes widened. \"Dreams?\"\n\n\"Oh yes,\" Millie said, her voice like rustling leaves. \"Dr. Pepper, they used to say, could bottle your deepest desires, your wildest hopes. One sip, and it would all become clear, possible.\"\n\nThe boy, captivated, reached out a hesitant hand. \n\nMillie gently pushed the bottle back. \"Not for sale, dearie. Not this one. This one,\" she winked, \"is for finding.\" \n\nShe watched as the boy, his head full of dreams and possibilities, left the shop.  He didn't buy anything that day, but he carried something far more valuable – the spark of an idea, a belief that maybe, just maybe, dreams could be bottled, waiting to be discovered by those who dared to search. \n\nAnd Millie? She knew her work was done. The bottle of dreams, with its whispered promises and shimmering possibilities, was exactly where it needed to be. The rest, like the faintest hint of cherry and licorice on the air, was up to fate, and a little bit of magic. \n"
+

Teardown

PASSED test_gemini_streaming 0:00:08.444567

Setup

Call

Captured stdout call
LLM output from Gemini: Dr. Pete Pepper wasn't a real doctor, at least not in the medical sense.  He held a doctorate in fizziology, an obscure and hotly debated field focused entirely on the science of carbonation.  
+
+His lab, a converted bakery smelling faintly of yeast and high hopes, was his domain. It was filled with bubbling concoctions, tubes twisting like unruly vines, and a wall plastered with hand-drawn graphs charting the "perfect fizz." 
+
+Dr. Pepper, with his wild Einstein hair and a lab coat permanently stained a cheery orange, dreamt of creating a soda so perfectly balanced, so exquisitely carbonated, that it would redefine "refreshing."
+
+He had faced countless failures, each one a mini-explosion of sticky syrup and disappointment.  But Dr. Pepper, fueled by fizzy fervor, never lost hope.
+
+One stormy Tuesday, as lightning crackled outside, mirroring the electric hum of his latest experiment, something extraordinary happened.  The mixture in the beaker, instead of its usual volcanic eruption, settled into a calm, deep crimson liquid. 
+
+Hesitantly, Dr. Pepper raised a shaking hand towards the beaker. The aroma hit him first - a complex concoction of sweet, tart, and a hint of something indescribable.  He took a sip.
+
+The world stopped.  
+
+A symphony of tiny bubbles danced on his tongue. Flavors he couldn't place, yet felt deeply familiar, exploded in his mouth.  It was perfect. 
+
+Dr. Pepper, normally a man of science and logic, felt tears prick his eyes.  He had done it.  He had achieved the impossible. He had bottled the perfect fizz.
+
+And so, with a heart full of bubbly joy and a name inspired by his life's work, Dr. Pete Pepper shared his creation with the world.  And the world, thirsty for a taste of perfection, embraced it with open arms and a satisfying "Ahhhh." 
+
+
Captured stderr call
[2024-07-24T06:56:00Z INFO  baml_events] Function TestGemini:
+    Client: Gemini (gemini-1.5-pro-001) - 8434ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about Dr. Pepper
+    
+    ---LLM REPLY---
+    Dr. Pete Pepper wasn't a real doctor, at least not in the medical sense.  He held a doctorate in fizziology, an obscure and hotly debated field focused entirely on the science of carbonation.  
+    
+    His lab, a converted bakery smelling faintly of yeast and high hopes, was his domain. It was filled with bubbling concoctions, tubes twisting like unruly vines, and a wall plastered with hand-drawn graphs charting the "perfect fizz." 
+    
+    Dr. Pepper, with his wild Einstein hair and a lab coat permanently stained a cheery orange, dreamt of creating a soda so perfectly balanced, so exquisitely carbonated, that it would redefine "refreshing."
+    
+    He had faced countless failures, each one a mini-explosion of sticky syrup and disappointment.  But Dr. Pepper, fueled by fizzy fervor, never lost hope.
+    
+    One stormy Tuesday, as lightning crackled outside, mirroring the electric hum of his latest experiment, something extraordinary happened.  The mixture in the beaker, instead of its usual volcanic eruption, settled into a calm, deep crimson liquid. 
+    
+    Hesitantly, Dr. Pepper raised a shaking hand towards the beaker. The aroma hit him first - a complex concoction of sweet, tart, and a hint of something indescribable.  He took a sip.
+    
+    The world stopped.  
+    
+    A symphony of tiny bubbles danced on his tongue. Flavors he couldn't place, yet felt deeply familiar, exploded in his mouth.  It was perfect. 
+    
+    Dr. Pepper, normally a man of science and logic, felt tears prick his eyes.  He had done it.  He had achieved the impossible. He had bottled the perfect fizz.
+    
+    And so, with a heart full of bubbly joy and a name inspired by his life's work, Dr. Pete Pepper shared his creation with the world.  And the world, thirsty for a taste of perfection, embraced it with open arms and a satisfying "Ahhhh." 
+    
+    ---Parsed Response (string)---
+    "Dr. Pete Pepper wasn't a real doctor, at least not in the medical sense.  He held a doctorate in fizziology, an obscure and hotly debated field focused entirely on the science of carbonation.  \n\nHis lab, a converted bakery smelling faintly of yeast and high hopes, was his domain. It was filled with bubbling concoctions, tubes twisting like unruly vines, and a wall plastered with hand-drawn graphs charting the \"perfect fizz.\" \n\nDr. Pepper, with his wild Einstein hair and a lab coat permanently stained a cheery orange, dreamt of creating a soda so perfectly balanced, so exquisitely carbonated, that it would redefine \"refreshing.\"\n\nHe had faced countless failures, each one a mini-explosion of sticky syrup and disappointment.  But Dr. Pepper, fueled by fizzy fervor, never lost hope.\n\nOne stormy Tuesday, as lightning crackled outside, mirroring the electric hum of his latest experiment, something extraordinary happened.  The mixture in the beaker, instead of its usual volcanic eruption, settled into a calm, deep crimson liquid. \n\nHesitantly, Dr. Pepper raised a shaking hand towards the beaker. The aroma hit him first - a complex concoction of sweet, tart, and a hint of something indescribable.  He took a sip.\n\nThe world stopped.  \n\nA symphony of tiny bubbles danced on his tongue. Flavors he couldn't place, yet felt deeply familiar, exploded in his mouth.  It was perfect. \n\nDr. Pepper, normally a man of science and logic, felt tears prick his eyes.  He had done it.  He had achieved the impossible. He had bottled the perfect fizz.\n\nAnd so, with a heart full of bubbly joy and a name inspired by his life's work, Dr. Pete Pepper shared his creation with the world.  And the world, thirsty for a taste of perfection, embraced it with open arms and a satisfying \"Ahhhh.\" \n"
+

Teardown

PASSED test_aws 0:00:02.322850

Setup

Call

Captured stderr call
[2024-07-24T06:56:02Z INFO  baml_events] Function TestAws:
+    Client: AwsBedrock (anthropic.claude-3-haiku-20240307-v1:0) - 2163ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about Mt Rainier is tall
+    
+    ---LLM REPLY---
+    Here is a short story about Mt. Rainier:
+    
+    The Towering Titan
+    
+    As the sun began to peek over the eastern horizon, its golden rays illuminated the majestic peak of Mount Rainier. Standing tall and proud at an imposing elevation of 14,411 feet, the iconic stratovolcano commanded the attention of all who gazed upon it.
+    
+    For countless generations, the indigenous peoples of the Pacific Northwest had revered this towering
+    ---Parsed Response (string)---
+    "Here is a short story about Mt. Rainier:\n\nThe Towering Titan\n\nAs the sun began to peek over the eastern horizon, its golden rays illuminated the majestic peak of Mount Rainier. Standing tall and proud at an imposing elevation of 14,411 feet, the iconic stratovolcano commanded the attention of all who gazed upon it.\n\nFor countless generations, the indigenous peoples of the Pacific Northwest had revered this towering"
+

Teardown

PASSED test_aws_streaming 0:00:02.188260

Setup

Call

Captured stderr call
[2024-07-24T06:56:04Z INFO  baml_events] Function TestAws:
+    Client: AwsBedrock (anthropic.claude-3-haiku-20240307-v1:0) - 2164ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about Mt Rainier is tall
+    
+    ---LLM REPLY---
+    Here is a short story about Mt. Rainier:
+    
+    The Majestic Peak
+    
+    As the car wound its way up the narrow mountain road, Anna couldn't help but gaze in awe at the towering presence before her. Mt. Rainier stood tall and proud, its snow-capped peak piercing the clear blue sky.
+    
+    "Wow, it's even more breathtaking in person," she whispered, her eyes fixed on the magnificent volcanic mountain
+    ---Parsed Response (string)---
+    "Here is a short story about Mt. Rainier:\n\nThe Majestic Peak\n\nAs the car wound its way up the narrow mountain road, Anna couldn't help but gaze in awe at the towering presence before her. Mt. Rainier stood tall and proud, its snow-capped peak piercing the clear blue sky.\n\n\"Wow, it's even more breathtaking in person,\" she whispered, her eyes fixed on the magnificent volcanic mountain"
+

Teardown

PASSED test_streaming 0:00:03.826207

Setup

Call

Captured stderr call
[2024-07-24T06:56:08Z INFO  baml_events] Function PromptTestStreaming:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 3818ms
+    ---PROMPT---
+    [chat] system: Tell me a short story about Programming languages are fun to create
+    
+    ---LLM REPLY---
+    Once upon a time, in a bustling village filled with curious and inventive people, there lived a young programmer named Lily. Lily had always been fascinated by the world of programming languages and would spend hours tinkering away on her computer, constantly experimenting with new syntax and algorithms.
+    
+    One day, after weeks of tireless work and dedication, Lily had a breakthrough. She had finally created her very own programming language, which she named SparkleScript. Excited to share her creation with the world, Lily uploaded SparkleScript to a popular coding platform and waited eagerly for feedback.
+    
+    To her delight, other programmers quickly took notice of SparkleScript and began to experiment with it themselves. They praised Lily for her innovative design and clever features, and soon, SparkleScript gained a following of enthusiastic supporters.
+    
+    As more and more people started using SparkleScript, Lily's village became a hub of creativity and collaboration. Programmers from all around would come to visit, eager to learn from Lily and contribute to the growing community of SparkleScript users.
+    
+    Together, they worked tirelessly to improve and expand the capabilities of SparkleScript, pushing the boundaries of what was possible in programming. With each new update and feature, the language grew more powerful and versatile, opening up endless possibilities for innovation and expression.
+    
+    And so, Lily's passion for programming languages had not only brought joy and excitement to her own life but had also sparked a vibrant community of creators and dreamers, united by their love of crafting code and bringing their ideas to life. And in the end, they all learned that with a little imagination and a lot of hard work, programming languages truly are fun to create.
+    ---Parsed Response (string)---
+    "Once upon a time, in a bustling village filled with curious and inventive people, there lived a young programmer named Lily. Lily had always been fascinated by the world of programming languages and would spend hours tinkering away on her computer, constantly experimenting with new syntax and algorithms.\n\nOne day, after weeks of tireless work and dedication, Lily had a breakthrough. She had finally created her very own programming language, which she named SparkleScript. Excited to share her creation with the world, Lily uploaded SparkleScript to a popular coding platform and waited eagerly for feedback.\n\nTo her delight, other programmers quickly took notice of SparkleScript and began to experiment with it themselves. They praised Lily for her innovative design and clever features, and soon, SparkleScript gained a following of enthusiastic supporters.\n\nAs more and more people started using SparkleScript, Lily's village became a hub of creativity and collaboration. Programmers from all around would come to visit, eager to learn from Lily and contribute to the growing community of SparkleScript users.\n\nTogether, they worked tirelessly to improve and expand the capabilities of SparkleScript, pushing the boundaries of what was possible in programming. With each new update and feature, the language grew more powerful and versatile, opening up endless possibilities for innovation and expression.\n\nAnd so, Lily's passion for programming languages had not only brought joy and excitement to her own life but had also sparked a vibrant community of creators and dreamers, united by their love of crafting code and bringing their ideas to life. And in the end, they all learned that with a little imagination and a lot of hard work, programming languages truly are fun to create."
+

Teardown

PASSED test_streaming_uniterated 0:00:03.594798

Setup

Call

Captured stderr call
[2024-07-24T06:56:12Z INFO  baml_events] Function PromptTestStreaming:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 3584ms
+    ---PROMPT---
+    [chat] system: Tell me a short story about The color blue makes me sad
+    
+    ---LLM REPLY---
+    Once there lived a young girl named Lily who had always been mesmerized by the color blue. She found it calming and beautiful, like the clear sky on a sunny day or the gentle waves of the ocean. But as she grew older, Lily began to associate the color blue with sadness.
+    
+    It all started when her beloved grandmother passed away. The room where Lily had spent countless hours with her grandmother was painted a soft shade of blue, and every time she entered it, she couldn't help but feel a pang of grief in her heart. The color blue seemed to amplify her sadness, reminding her of the void left by her grandmother's absence.
+    
+    As time went on, Lily's sadness only seemed to deepen whenever she encountered the color blue. The sight of a bluebird flying overhead or a field of blue flowers would bring tears to her eyes, as memories of her grandmother flooded back to her. She tried to avoid anything blue, but it seemed to be everywhere she turned, a constant reminder of her loss.
+    
+    One day, feeling overwhelmed by her emotions, Lily decided to confront her sadness head-on. She took a paintbrush and dipped it in a vibrant shade of blue, letting her feelings flow onto the canvas. As she painted, she found a sense of release, as if the color was helping her to let go of her pain and sorrow.
+    
+    From that day on, Lily no longer felt consumed by sadness when she saw the color blue. Instead, she found solace in its beauty and the memories it held. She realized that sadness was a part of life, but it didn't have to define her. And so, she embraced the color blue once again, finding peace in its depths and the healing power it held within.
+    ---Parsed Response (string)---
+    "Once there lived a young girl named Lily who had always been mesmerized by the color blue. She found it calming and beautiful, like the clear sky on a sunny day or the gentle waves of the ocean. But as she grew older, Lily began to associate the color blue with sadness.\n\nIt all started when her beloved grandmother passed away. The room where Lily had spent countless hours with her grandmother was painted a soft shade of blue, and every time she entered it, she couldn't help but feel a pang of grief in her heart. The color blue seemed to amplify her sadness, reminding her of the void left by her grandmother's absence.\n\nAs time went on, Lily's sadness only seemed to deepen whenever she encountered the color blue. The sight of a bluebird flying overhead or a field of blue flowers would bring tears to her eyes, as memories of her grandmother flooded back to her. She tried to avoid anything blue, but it seemed to be everywhere she turned, a constant reminder of her loss.\n\nOne day, feeling overwhelmed by her emotions, Lily decided to confront her sadness head-on. She took a paintbrush and dipped it in a vibrant shade of blue, letting her feelings flow onto the canvas. As she painted, she found a sense of release, as if the color was helping her to let go of her pain and sorrow.\n\nFrom that day on, Lily no longer felt consumed by sadness when she saw the color blue. Instead, she found solace in its beauty and the memories it held. She realized that sadness was a part of life, but it didn't have to define her. And so, she embraced the color blue once again, finding peace in its depths and the healing power it held within."
+

Teardown

PASSED test_streaming_sync 0:00:03.500281

Setup

Call

Captured stderr call
[2024-07-24T06:56:15Z INFO  baml_events] Function PromptTestStreaming:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 3491ms
+    ---PROMPT---
+    [chat] system: Tell me a short story about Programming languages are fun to create
+    
+    ---LLM REPLY---
+    Once upon a time, a group of quirky and creative individuals got together with the ambitious idea of creating their very own programming language. They gathered in a small, cozy room filled with whiteboards and caffeine-fueled energy, ready to embark on a journey of coding magic.
+    
+    They brainstormed every aspect of their new language, from the syntax to the semantics, carefully crafting each rule and feature with precision and imagination. They debated the best ways to make their language user-friendly, powerful, and innovative, drawing inspiration from their favorite existing languages and adding their own unique twist to the mix.
+    
+    As they worked tirelessly day and night, lines of code began to take shape, forming the foundation of their dream language. They tested and debugged, laughed and celebrated small victories, all the while feeling a sense of wonder and satisfaction as their creation slowly came to life.
+    
+    Finally, after many long weeks of hard work and collaboration, they unveiled their masterpiece to the world. The programming language they had crafted was a work of art, a reflection of their passion for coding and their shared love of all things tech.
+    
+    Programmers from far and wide soon discovered this new language and embraced it with enthusiasm, marveling at its elegance and efficiency. It quickly gained popularity and became a favorite tool for developers looking to express themselves creatively and push the boundaries of what was possible in the world of coding.
+    
+    And so, the team of creators basked in the glow of their success, knowing that they had brought something truly special into the world. For them, creating a programming language had been not just a technical challenge, but a joyous journey of exploration, collaboration, and pure, unadulterated fun.
+    ---Parsed Response (string)---
+    "Once upon a time, a group of quirky and creative individuals got together with the ambitious idea of creating their very own programming language. They gathered in a small, cozy room filled with whiteboards and caffeine-fueled energy, ready to embark on a journey of coding magic.\n\nThey brainstormed every aspect of their new language, from the syntax to the semantics, carefully crafting each rule and feature with precision and imagination. They debated the best ways to make their language user-friendly, powerful, and innovative, drawing inspiration from their favorite existing languages and adding their own unique twist to the mix.\n\nAs they worked tirelessly day and night, lines of code began to take shape, forming the foundation of their dream language. They tested and debugged, laughed and celebrated small victories, all the while feeling a sense of wonder and satisfaction as their creation slowly came to life.\n\nFinally, after many long weeks of hard work and collaboration, they unveiled their masterpiece to the world. The programming language they had crafted was a work of art, a reflection of their passion for coding and their shared love of all things tech.\n\nProgrammers from far and wide soon discovered this new language and embraced it with enthusiasm, marveling at its elegance and efficiency. It quickly gained popularity and became a favorite tool for developers looking to express themselves creatively and push the boundaries of what was possible in the world of coding.\n\nAnd so, the team of creators basked in the glow of their success, knowing that they had brought something truly special into the world. For them, creating a programming language had been not just a technical challenge, but a joyous journey of exploration, collaboration, and pure, unadulterated fun."
+

Teardown

PASSED test_streaming_uniterated_sync 0:00:04.226122

Setup

Call

Captured stderr call
[2024-07-24T06:56:19Z INFO  baml_events] Function PromptTestStreaming:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 4218ms
+    ---PROMPT---
+    [chat] system: Tell me a short story about The color blue makes me sad
+    
+    ---LLM REPLY---
+    Once there was a boy named Charlie who discovered that the color blue made him feel incredibly sad. It all started when he visited the ocean for the first time and watched as the deep blue waves crashed against the shore, reminding him of the vastness and uncertainty of life. From that day on, every time he saw the color blue, whether it was in the sky, on a piece of clothing, or a painting, a wave of sadness washed over him.
+    
+    His friends couldn't understand why the color blue had such a profound effect on him, and they tried to cheer him up by avoiding the color as much as possible. But no matter how hard they tried, the sadness lingered in Charlie's heart.
+    
+    One day, as he sat by a tranquil lake, watching the reflection of the clear blue sky on the water, a little girl approached him and asked why he looked so sad. Charlie explained his feelings about the color blue, and the little girl listened intently. She then took out a paintbrush and a canvas and started painting a beautiful blue landscape.
+    
+    As she painted, she told Charlie stories of the beauty and wonder of the color blue, how it represented peace, calmness, and serenity. She showed him that the color blue was not just a reminder of sadness, but also a symbol of hope and tranquility.
+    
+    Slowly but surely, Charlie's sorrow began to lift, and he started to see the color blue in a different light. He realized that it was all about perspective and that he could choose to focus on the positive aspects of the color.
+    
+    From that day on, whenever he felt sad at the sight of blue, Charlie would remember the little girl's words and find comfort in the beauty of the color. It no longer made him feel desolate but rather brought a sense of peace and tranquility to his soul. And he learned that sometimes, it just takes a change in perspective to turn sadness into joy.
+    ---Parsed Response (string)---
+    "Once there was a boy named Charlie who discovered that the color blue made him feel incredibly sad. It all started when he visited the ocean for the first time and watched as the deep blue waves crashed against the shore, reminding him of the vastness and uncertainty of life. From that day on, every time he saw the color blue, whether it was in the sky, on a piece of clothing, or a painting, a wave of sadness washed over him.\n\nHis friends couldn't understand why the color blue had such a profound effect on him, and they tried to cheer him up by avoiding the color as much as possible. But no matter how hard they tried, the sadness lingered in Charlie's heart.\n\nOne day, as he sat by a tranquil lake, watching the reflection of the clear blue sky on the water, a little girl approached him and asked why he looked so sad. Charlie explained his feelings about the color blue, and the little girl listened intently. She then took out a paintbrush and a canvas and started painting a beautiful blue landscape.\n\nAs she painted, she told Charlie stories of the beauty and wonder of the color blue, how it represented peace, calmness, and serenity. She showed him that the color blue was not just a reminder of sadness, but also a symbol of hope and tranquility.\n\nSlowly but surely, Charlie's sorrow began to lift, and he started to see the color blue in a different light. He realized that it was all about perspective and that he could choose to focus on the positive aspects of the color.\n\nFrom that day on, whenever he felt sad at the sight of blue, Charlie would remember the little girl's words and find comfort in the beauty of the color. It no longer made him feel desolate but rather brought a sense of peace and tranquility to his soul. And he learned that sometimes, it just takes a change in perspective to turn sadness into joy."
+

Teardown

PASSED test_streaming_claude 0:00:00.577862

Setup

Call

Captured stdout call
msgs:
+Here's a haiku about Mount Rainier:
+
+Majestic Rainier
+Towering, snow-capped wonder
+Dominates the skies
+final:
+Here's a haiku about Mount Rainier:
+
+Majestic Rainier
+Towering, snow-capped wonder
+Dominates the skies
+
Captured stderr call
[2024-07-24T06:56:20Z INFO  baml_events] Function PromptTestClaude:
+    Client: Claude (claude-3-haiku-20240307) - 521ms
+    ---PROMPT---
+    [chat] user: Tell me a haiku about Mt Rainier is tall
+    
+    ---LLM REPLY---
+    Here's a haiku about Mount Rainier:
+    
+    Majestic Rainier
+    Towering, snow-capped wonder
+    Dominates the skies
+    ---Parsed Response (string)---
+    "Here's a haiku about Mount Rainier:\n\nMajestic Rainier\nTowering, snow-capped wonder\nDominates the skies"
+

Teardown

PASSED test_streaming_gemini 0:00:11.546600

Setup

Call

Captured stdout call
msgs:
+The old diner was quiet, the only sound the rhythmic whir of the ceiling fan pushing around the humid air.  Behind the counter, Clara polished a glass, her reflection a watery ghost in its curve.  She sighed, the familiar afternoon lull settling over her like a heavy shawl. 
+
+Suddenly, the bell above the door jangled, shattering the silence.  A man stepped inside, tall and broad-shouldered, his face hidden under a wide-brimmed hat.  He moved with a quiet grace that belied his size, taking a seat at the counter with a soft creak of leather. 
+
+"What can I get you, hon?" Clara asked, her voice tinged with curiosity.  
+
+The man tipped his hat back, revealing kind eyes and a tired smile. "Just a Dr. Pepper, ma'am.  The original kind." 
+
+Clara nodded, surprised.  Not many folks ordered Dr. Pepper anymore, especially not the original recipe.  She placed a frosty mug on the counter, the condensation clinging to the glass like teardrops.  "You're new in town," she stated, filling the mug with the dark, bubbling soda. 
+
+The man took a long sip, his eyes closing as if in reverie.  "You could say that," he said, his voice low and rumbling like distant thunder. "Passing through, mostly.  But this," he gestured to the Dr. Pepper, "this takes me back."
+
+He spent the next hour sharing snippets of his life: rodeos in dusty towns, sunsets blazing across endless highways, the comfort of a familiar diner after a long day.  He spoke of heartache and joy, each story seasoned with a touch of wistful nostalgia, all punctuated by sips of his Dr. Pepper. 
+
+As the sun dipped below the horizon, painting the sky in vibrant hues of orange and purple, the man rose to leave.  He placed a worn twenty dollar bill on the counter, far more than the drink cost. 
+
+"Thank you, ma'am," he said, his voice thick with emotion.  "That Dr. Pepper, it was just what I needed." 
+
+Clara watched him leave, the scent of leather and sandalwood lingering in the air long after he was gone.  She looked down at the twenty dollar bill, then at the untouched glass of water she'd placed beside his Dr. Pepper.  It struck her then, that sometimes the best comfort comes not from quenching a physical thirst, but from sharing a moment, a memory, a story – all bottled up in a simple drink with a unique history, just like Dr. Pepper itself. 
+
+final:
+The old diner was quiet, the only sound the rhythmic whir of the ceiling fan pushing around the humid air.  Behind the counter, Clara polished a glass, her reflection a watery ghost in its curve.  She sighed, the familiar afternoon lull settling over her like a heavy shawl. 
+
+Suddenly, the bell above the door jangled, shattering the silence.  A man stepped inside, tall and broad-shouldered, his face hidden under a wide-brimmed hat.  He moved with a quiet grace that belied his size, taking a seat at the counter with a soft creak of leather. 
+
+"What can I get you, hon?" Clara asked, her voice tinged with curiosity.  
+
+The man tipped his hat back, revealing kind eyes and a tired smile. "Just a Dr. Pepper, ma'am.  The original kind." 
+
+Clara nodded, surprised.  Not many folks ordered Dr. Pepper anymore, especially not the original recipe.  She placed a frosty mug on the counter, the condensation clinging to the glass like teardrops.  "You're new in town," she stated, filling the mug with the dark, bubbling soda. 
+
+The man took a long sip, his eyes closing as if in reverie.  "You could say that," he said, his voice low and rumbling like distant thunder. "Passing through, mostly.  But this," he gestured to the Dr. Pepper, "this takes me back."
+
+He spent the next hour sharing snippets of his life: rodeos in dusty towns, sunsets blazing across endless highways, the comfort of a familiar diner after a long day.  He spoke of heartache and joy, each story seasoned with a touch of wistful nostalgia, all punctuated by sips of his Dr. Pepper. 
+
+As the sun dipped below the horizon, painting the sky in vibrant hues of orange and purple, the man rose to leave.  He placed a worn twenty dollar bill on the counter, far more than the drink cost. 
+
+"Thank you, ma'am," he said, his voice thick with emotion.  "That Dr. Pepper, it was just what I needed." 
+
+Clara watched him leave, the scent of leather and sandalwood lingering in the air long after he was gone.  She looked down at the twenty dollar bill, then at the untouched glass of water she'd placed beside his Dr. Pepper.  It struck her then, that sometimes the best comfort comes not from quenching a physical thirst, but from sharing a moment, a memory, a story – all bottled up in a simple drink with a unique history, just like Dr. Pepper itself. 
+
+
Captured stderr call
[2024-07-24T06:56:32Z INFO  baml_events] Function TestGemini:
+    Client: Gemini (gemini-1.5-pro-001) - 11507ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about Dr.Pepper
+    
+    ---LLM REPLY---
+    The old diner was quiet, the only sound the rhythmic whir of the ceiling fan pushing around the humid air.  Behind the counter, Clara polished a glass, her reflection a watery ghost in its curve.  She sighed, the familiar afternoon lull settling over her like a heavy shawl. 
+    
+    Suddenly, the bell above the door jangled, shattering the silence.  A man stepped inside, tall and broad-shouldered, his face hidden under a wide-brimmed hat.  He moved with a quiet grace that belied his size, taking a seat at the counter with a soft creak of leather. 
+    
+    "What can I get you, hon?" Clara asked, her voice tinged with curiosity.  
+    
+    The man tipped his hat back, revealing kind eyes and a tired smile. "Just a Dr. Pepper, ma'am.  The original kind." 
+    
+    Clara nodded, surprised.  Not many folks ordered Dr. Pepper anymore, especially not the original recipe.  She placed a frosty mug on the counter, the condensation clinging to the glass like teardrops.  "You're new in town," she stated, filling the mug with the dark, bubbling soda. 
+    
+    The man took a long sip, his eyes closing as if in reverie.  "You could say that," he said, his voice low and rumbling like distant thunder. "Passing through, mostly.  But this," he gestured to the Dr. Pepper, "this takes me back."
+    
+    He spent the next hour sharing snippets of his life: rodeos in dusty towns, sunsets blazing across endless highways, the comfort of a familiar diner after a long day.  He spoke of heartache and joy, each story seasoned with a touch of wistful nostalgia, all punctuated by sips of his Dr. Pepper. 
+    
+    As the sun dipped below the horizon, painting the sky in vibrant hues of orange and purple, the man rose to leave.  He placed a worn twenty dollar bill on the counter, far more than the drink cost. 
+    
+    "Thank you, ma'am," he said, his voice thick with emotion.  "That Dr. Pepper, it was just what I needed." 
+    
+    Clara watched him leave, the scent of leather and sandalwood lingering in the air long after he was gone.  She looked down at the twenty dollar bill, then at the untouched glass of water she'd placed beside his Dr. Pepper.  It struck her then, that sometimes the best comfort comes not from quenching a physical thirst, but from sharing a moment, a memory, a story – all bottled up in a simple drink with a unique history, just like Dr. Pepper itself. 
+    
+    ---Parsed Response (string)---
+    "The old diner was quiet, the only sound the rhythmic whir of the ceiling fan pushing around the humid air.  Behind the counter, Clara polished a glass, her reflection a watery ghost in its curve.  She sighed, the familiar afternoon lull settling over her like a heavy shawl. \n\nSuddenly, the bell above the door jangled, shattering the silence.  A man stepped inside, tall and broad-shouldered, his face hidden under a wide-brimmed hat.  He moved with a quiet grace that belied his size, taking a seat at the counter with a soft creak of leather. \n\n\"What can I get you, hon?\" Clara asked, her voice tinged with curiosity.  \n\nThe man tipped his hat back, revealing kind eyes and a tired smile. \"Just a Dr. Pepper, ma'am.  The original kind.\" \n\nClara nodded, surprised.  Not many folks ordered Dr. Pepper anymore, especially not the original recipe.  She placed a frosty mug on the counter, the condensation clinging to the glass like teardrops.  \"You're new in town,\" she stated, filling the mug with the dark, bubbling soda. \n\nThe man took a long sip, his eyes closing as if in reverie.  \"You could say that,\" he said, his voice low and rumbling like distant thunder. \"Passing through, mostly.  But this,\" he gestured to the Dr. Pepper, \"this takes me back.\"\n\nHe spent the next hour sharing snippets of his life: rodeos in dusty towns, sunsets blazing across endless highways, the comfort of a familiar diner after a long day.  He spoke of heartache and joy, each story seasoned with a touch of wistful nostalgia, all punctuated by sips of his Dr. Pepper. \n\nAs the sun dipped below the horizon, painting the sky in vibrant hues of orange and purple, the man rose to leave.  He placed a worn twenty dollar bill on the counter, far more than the drink cost. \n\n\"Thank you, ma'am,\" he said, his voice thick with emotion.  \"That Dr. Pepper, it was just what I needed.\" \n\nClara watched him leave, the scent of leather and sandalwood lingering in the air long after he was gone.  She looked down at the twenty dollar bill, then at the untouched glass of water she'd placed beside his Dr. Pepper.  It struck her then, that sometimes the best comfort comes not from quenching a physical thirst, but from sharing a moment, a memory, a story – all bottled up in a simple drink with a unique history, just like Dr. Pepper itself. \n"
+

Teardown

PASSED test_tracing_async_only 0:00:05.723741

Setup

Call

Captured stdout call
STATS TraceStats(failed=0, started=15, finalized=15, submitted=15, sent=15, done=15)
+
Captured stderr call
[2024-07-24T06:56:32Z INFO  baml_events] Function FnOutputClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 729ms
+    ---PROMPT---
+    [chat] system: Return a JSON blob with this schema: 
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: int,
+    }
+    
+    For the prop2, always return a 540
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "Hello, JSON!",
+      "prop2": 540
+    }
+    ---Parsed Response (class TestOutputClass)---
+    {
+      "prop1": "Hello, JSON!",
+      "prop2": 540
+    }
+[2024-07-24T06:56:34Z INFO  baml_events] Function FnOutputClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 669ms
+    ---PROMPT---
+    [chat] system: Return a JSON blob with this schema: 
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: int,
+    }
+    
+    For the prop2, always return a 540
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "Hello, JSON!",
+      "prop2": 540
+    }
+    ---Parsed Response (class TestOutputClass)---
+    {
+      "prop1": "Hello, JSON!",
+      "prop2": 540
+    }
+[2024-07-24T06:56:35Z INFO  baml_events] Function FnOutputClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 715ms
+    ---PROMPT---
+    [chat] system: Return a JSON blob with this schema: 
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: int,
+    }
+    
+    For the prop2, always return a 540
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "Hello, World!",
+      "prop2": 540
+    }
+    ---Parsed Response (class TestOutputClass)---
+    {
+      "prop1": "Hello, World!",
+      "prop2": 540
+    }
+[2024-07-24T06:56:37Z INFO  baml_events] Function FnOutputClass:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 522ms
+    ---PROMPT---
+    [chat] system: Return a JSON blob with this schema: 
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: int,
+    }
+    
+    For the prop2, always return a 540
+    
+    JSON:
+    
+    ---LLM REPLY---
+    {
+      "prop1": "This is a sample string",
+      "prop2": 540
+    }
+    ---Parsed Response (class TestOutputClass)---
+    {
+      "prop1": "This is a sample string",
+      "prop2": 540
+    }
+

Teardown

PASSED test_tracing_sync 0:00:00.001120

Setup

Call

Teardown

PASSED test_tracing_thread_pool 0:00:01.356617

Setup

Call

Teardown

PASSED test_tracing_thread_pool_async 0:00:14.361779

Setup

Call

Teardown

PASSED test_tracing_async_gather 0:00:01.392946

Setup

Call

Teardown

PASSED test_tracing_async_gather_top_level 0:00:01.491203

Setup

Call

Teardown

PASSED test_dynamic 0:00:01.288215

Setup

Call

Captured stdout call
{'name': 'Harrison', 'hair_color': 'BLACK', 'last_name': [], 'height': 1.83, 'hobbies': ['SPORTS']}
+
Captured stderr call
[2024-07-24T06:56:57Z INFO  baml_events] Function ExtractPeople:
+    Client: GPT4 (gpt-4o-2024-05-13) - 1277ms
+    ---PROMPT---
+    [chat] system: You are an expert extraction algorithm. Only extract relevant information from the text. If you do not know the value of an attribute asked to extract, return null for the attribute's value.
+    
+    Answer with a JSON Array using this schema:
+    [
+      {
+        name: string or null,
+        hair_color: 'RED' or 'BLUE' or 'GREEN' or 'YELLOW' or 'BLACK' or 'WHITE' or null,
+        last_name: string[],
+        // Height in meters
+        height: float or null,
+        // Some suggested hobbies they might be good at
+        hobbies: [
+          'sports' or 'music' or 'reading' or 'chess'
+        ],
+      }
+    ]
+    user: My name is Harrison. My hair is black and I'm 6 feet tall. I'm pretty good around the hoop.
+    
+    ---LLM REPLY---
+    [
+      {
+        "name": "Harrison",
+        "hair_color": "BLACK",
+        "last_name": [],
+        "height": 1.83,
+        "hobbies": [
+          "sports"
+        ]
+      }
+    ]
+    ---Parsed Response (list<class Person>)---
+    [
+      {
+        "name": "Harrison",
+        "hair_color": "BLACK",
+        "last_name": [],
+        "height": 1.83,
+        "hobbies": [
+          "SPORTS"
+        ]
+      }
+    ]
+

Teardown

PASSED test_dynamic_class_output 0:00:00.922175

Setup

Call

Captured stdout call
[]
+{"hair_color":"black"}
+
Captured stderr call
[2024-07-24T06:56:58Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 489ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 6 feet tall.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+    }
+    
+    ---LLM REPLY---
+    {
+      "hair_color": "black"
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black"
+    }
+[2024-07-24T06:56:58Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 418ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 6 feet tall.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+    }
+    
+    ---LLM REPLY---
+    {
+      "hair_color": "black"
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black"
+    }
+

Teardown

PASSED test_dynamic_class_nested_output_no_stream 0:00:01.174174

Setup

Call

Captured stdout call
{"name":{"first_name":"Mark","last_name":"Gonzalez","middle_name":null},"address":null,"hair_color":"black","height":6.0}
+
Captured stderr call
[2024-07-24T06:56:59Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 1164ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Mark Gonzalez. My hair is black and I'm 6 feet tall.
+    
+    Answer in JSON using this schema:
+    {
+      name: {
+        first_name: string,
+        last_name: string or null,
+        middle_name: string or null,
+      } or null,
+      address: {
+      } or null,
+      hairColor: string,
+      height: float or null,
+    }
+    
+    ---LLM REPLY---
+    {
+      "name": {
+        "first_name": "Mark",
+        "last_name": "Gonzalez",
+        "middle_name": null
+      },
+      "address": null,
+      "hairColor": "black",
+      "height": 6.0
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "name": {
+        "first_name": "Mark",
+        "last_name": "Gonzalez",
+        "middle_name": null
+      },
+      "address": null,
+      "hair_color": "black",
+      "height": 6.0
+    }
+

Teardown

PASSED test_dynamic_class_nested_output_stream 0:00:00.657023

Setup

Call

Captured stdout call
streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name=None hair_color=None
+streamed  {'name': None, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': None, 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': None, 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': '', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': '', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': None} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': None}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': ''} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': ''}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'G'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'G'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonz'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonz'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=None
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': None}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color=''
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': ''}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color='black'
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': 'black'}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color='black'
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': 'black'}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color='black'
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': 'black'}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color='black'
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': 'black'}
+streamed  name={'first_name': 'Mark', 'last_name': 'Gonzalez'} hair_color='black'
+streamed  {'name': {'first_name': 'Mark', 'last_name': 'Gonzalez'}, 'hair_color': 'black'}
+{"name":{"first_name":"Mark","last_name":"Gonzalez"},"hair_color":"black"}
+
Captured stderr call
[2024-07-24T06:57:00Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 646ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Mark Gonzalez. My hair is black and I'm 6 feet tall.
+    
+    Answer in JSON using this schema:
+    {
+      name: {
+        first_name: string,
+        last_name: string or null,
+      } or null,
+      hair_color: string,
+    }
+    
+    ---LLM REPLY---
+    {
+      "name": {
+        "first_name": "Mark",
+        "last_name": "Gonzalez"
+      },
+      "hair_color": "black"
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "name": {
+        "first_name": "Mark",
+        "last_name": "Gonzalez"
+      },
+      "hair_color": "black"
+    }
+

Teardown

PASSED test_stream_dynamic_class_output 0:00:00.515988

Setup

Call

Captured stdout call
[]
+streamed  {'hair_color': None}
+streamed  {'hair_color': None}
+streamed  {'hair_color': None}
+streamed  {'hair_color': None}
+streamed  {'hair_color': None}
+streamed  {'hair_color': None}
+streamed  {'hair_color': ''}
+streamed  {'hair_color': 'black'}
+streamed  {'hair_color': 'black'}
+streamed  {'hair_color': 'black'}
+streamed  {'hair_color': 'black'}
+streamed  {'hair_color': 'black'}
+streamed  {'hair_color': 'black'}
+final  hair_color='black'
+final  {'hair_color': 'black'}
+final  {"hair_color":"black"}
+
Captured stderr call
[2024-07-24T06:57:00Z INFO  baml_events] Function MyFunc:
+    Client: MyClient (gpt-4o-mini-2024-07-18) - 505ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 6 feet tall.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+    }
+    
+    ---LLM REPLY---
+    ```json
+    {
+      "hair_color": "black"
+    }
+    ```
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black"
+    }
+

Teardown

PASSED test_dynamic_inputs_list2 0:00:01.086439

Setup

Call

Captured stderr call
[2024-07-24T06:57:01Z INFO  baml_events] Function DynamicListInputOutput:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 1077ms
+    ---PROMPT---
+    [chat] system: Here is some input data:
+    ----
+    [{"new_key": "hi1", "testKey": "myTest", "blah": {"nestedKey1": "nestedVal"}}, {"testKey": "myTest", "new_key": "hi", "blah": {"nestedKey1": "nestedVal"}}]
+    ----
+    
+    Extract the information.
+    Answer with a JSON Array using this schema:
+    [
+      {
+        testKey: string,
+        new_key: string or null,
+        blah: {
+          nestedKey1: string,
+        },
+      }
+    ]
+    
+    ---LLM REPLY---
+    [
+      {
+        "testKey": "myTest",
+        "new_key": "hi1",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      },
+      {
+        "testKey": "myTest",
+        "new_key": "hi",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      }
+    ]
+    ---Parsed Response (list<class DynInputOutput>)---
+    [
+      {
+        "testKey": "myTest",
+        "new_key": "hi1",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      },
+      {
+        "testKey": "myTest",
+        "new_key": "hi",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      }
+    ]
+

Teardown

PASSED test_dynamic_inputs_list 0:00:01.143243

Setup

Call

Captured stderr call
[2024-07-24T06:57:03Z INFO  baml_events] Function DynamicListInputOutput:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 1133ms
+    ---PROMPT---
+    [chat] system: Here is some input data:
+    ----
+    [{"testKey": "myTest", "new_key": "hi", "blah": {"nestedKey1": "nestedVal"}}, {"blah": {"nestedKey1": "nestedVal"}, "testKey": "myTest", "new_key": "hi"}]
+    ----
+    
+    Extract the information.
+    Answer with a JSON Array using this schema:
+    [
+      {
+        testKey: string,
+        new_key: string or null,
+        blah: {
+          nestedKey1: string,
+        },
+      }
+    ]
+    
+    ---LLM REPLY---
+    [
+        {
+          "testKey": "myTest",
+          "new_key": "hi",
+          "blah": {
+            "nestedKey1": "nestedVal"
+          }
+        },
+        {
+          "testKey": "myTest",
+          "new_key": "hi",
+          "blah": {
+            "nestedKey1": "nestedVal"
+          }
+        }
+    ]
+    ---Parsed Response (list<class DynInputOutput>)---
+    [
+      {
+        "testKey": "myTest",
+        "new_key": "hi",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      },
+      {
+        "testKey": "myTest",
+        "new_key": "hi",
+        "blah": {
+          "nestedKey1": "nestedVal"
+        }
+      }
+    ]
+

Teardown

PASSED test_dynamic_output_map 0:00:00.995963

Setup

Call

Captured stdout call
[]
+final  hair_color='black' attributes={'height': '6 feet', 'eye_color': 'blue', 'facial_hair': 'beard'}
+final  {'hair_color': 'black', 'attributes': {'height': '6 feet', 'eye_color': 'blue', 'facial_hair': 'beard'}}
+final  {"hair_color":"black","attributes":{"height":"6 feet","eye_color":"blue","facial_hair":"beard"}}
+
Captured stderr call
[2024-07-24T06:57:04Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 985ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+      // Things like 'eye_color' or 'facial_hair'
+      attributes: map<string, string>,
+    }
+    
+    ---LLM REPLY---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "height": "6 feet",
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      }
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "height": "6 feet",
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      }
+    }
+

Teardown

PASSED test_dynamic_output_union 0:00:01.855836

Setup

Call

Captured stdout call
[]
+final  hair_color='black' attributes={'eye_color': 'blue', 'facial_hair': 'beard'} height={'feet': 6.0, 'inches': None}
+final  {'hair_color': 'black', 'attributes': {'eye_color': 'blue', 'facial_hair': 'beard'}, 'height': {'feet': 6.0, 'inches': None}}
+final  {"hair_color":"black","attributes":{"eye_color":"blue","facial_hair":"beard"},"height":{"feet":6.0,"inches":null}}
+final  hair_color='black' attributes={'eye_color': 'blue', 'facial_hair': 'beard'} height={'meters': 1.8}
+final  {'hair_color': 'black', 'attributes': {'eye_color': 'blue', 'facial_hair': 'beard'}, 'height': {'meters': 1.8}}
+final  {"hair_color":"black","attributes":{"eye_color":"blue","facial_hair":"beard"},"height":{"meters":1.8}}
+
Captured stderr call
[2024-07-24T06:57:05Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 915ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard. I am 30 years old.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+      // Things like 'eye_color' or 'facial_hair'
+      attributes: map<string, string>,
+      height: {
+        meters: float,
+      } or {
+        feet: float,
+        inches: float or null,
+      },
+    }
+    
+    ---LLM REPLY---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      },
+      "height": {
+        "feet": 6,
+        "inches": null
+      }
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      },
+      "height": {
+        "feet": 6.0,
+        "inches": null
+      }
+    }
+[2024-07-24T06:57:05Z INFO  baml_events] Function MyFunc:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 918ms
+    ---PROMPT---
+    [chat] system: Given a string, extract info using the schema:
+    
+    My name is Harrison. My hair is black and I'm 1.8 meters tall. I have blue eyes and a beard. I am 30 years old.
+    
+    Answer in JSON using this schema:
+    {
+      hair_color: string,
+      // Things like 'eye_color' or 'facial_hair'
+      attributes: map<string, string>,
+      height: {
+        meters: float,
+      } or {
+        feet: float,
+        inches: float or null,
+      },
+    }
+    
+    ---LLM REPLY---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      },
+      "height": {
+        "meters": 1.8
+      }
+    }
+    ---Parsed Response (class DynamicOutput)---
+    {
+      "hair_color": "black",
+      "attributes": {
+        "eye_color": "blue",
+        "facial_hair": "beard"
+      },
+      "height": {
+        "meters": 1.8
+      }
+    }
+

Teardown

PASSED test_nested_class_streaming 0:00:04.648443

Setup

Call

Captured stdout call
streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': None, 'prop2': None}
+streamed  {'prop1': '', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': None}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': None, 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': '', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': None, 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': '', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': None}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': None, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 4, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': None}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.0}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.0}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.1}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+streamed  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+final  {'prop1': 'Hello', 'prop2': {'prop1': 'World', 'prop2': 'JSON', 'inner': {'prop2': 42, 'prop3': 3.14}}}
+
Captured stderr call
[2024-07-24T06:57:10Z INFO  baml_events] Function FnOutputClassNested:
+    Client: Ollama (llama2) - 4631ms
+    ---PROMPT---
+    [chat] system: Return a made up json blob that matches this schema:
+    Answer in JSON using this schema:
+    {
+      prop1: string,
+      prop2: {
+        prop1: string,
+        prop2: string,
+        inner: {
+          prop2: int,
+          prop3: float,
+        },
+      },
+    }
+    ---
+    
+    JSON:
+    
+    ---LLM REPLY---
+    Here is a made-up JSON blob that matches the provided schema:
+    ```json
+    {
+      "prop1": "Hello",
+      "prop2": {
+        "prop1": "World",
+        "prop2": "JSON",
+        "inner": {
+          "prop2": 42,
+          "prop3": 3.14
+        }
+      }
+    }
+    ```
+    Explanation:
+    
+    * The `prop1` field is a string with the value "Hello".
+    * The `prop2` field is an object with three fields: `prop1`, `prop2`, and `inner`. The `prop1` field within the `prop2` object is also a string with the value "World". The `prop2` field within the `prop2` object is a string with the value "JSON".
+    * The `inner` field within the `prop2` object is an object with two fields: `prop2` and `prop3`. The `prop2` field is an integer with the value 42, and the `prop3` field is a floating-point number with the value 3.14.
+    
+    I hope this helps! Let me know if you have any questions.
+    ---Parsed Response (class TestClassNested)---
+    {
+      "prop1": "Hello",
+      "prop2": {
+        "prop1": "World",
+        "prop2": "JSON",
+        "inner": {
+          "prop2": 42,
+          "prop3": 3.14
+        }
+      }
+    }
+

Teardown

PASSED test_dynamic_clients 0:00:00.589126

Setup

Call

Captured stderr call
[2024-07-24T06:57:11Z INFO  baml_events] Function ExpectFailure:
+    Client: MyClient (gpt-3.5-turbo-0125) - 581ms
+    ---PROMPT---
+    [chat] system: What is the capital of England?
+    
+    ---LLM REPLY---
+    The capital of England is London.
+    ---Parsed Response (string)---
+    "The capital of England is London."
+

Teardown

PASSED test_event_log_hook 0:00:01.256218

Setup

Call

Captured stdout call
Event log hook1: 
+Event log event  BamlLogEvent {
+    metadata: {
+        event_id: "9ad0314f-db6e-4b80-8675-20dc6750b95d",
+        parent_id: None,
+        root_event_id: "9ad0314f-db6e-4b80-8675-20dc6750b95d"
+    },
+    prompt: "[
+  {
+    "role": "system",
+    "content": [
+      {
+        "text": "Return this value back to me: [\"a\", \"b\", \"c\"]"
+      }
+    ]
+  }
+]",
+    raw_output: "["a", "b", "c"]",
+    parsed_output: "["a", "b", "c"]",
+    start_time: "2024-07-24T06:57:11.758Z"
+}
+
Captured stderr call
[2024-07-24T06:57:12Z INFO  baml_events] Function TestFnNamedArgsSingleStringList:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 522ms
+    ---PROMPT---
+    [chat] system: Return this value back to me: ["a", "b", "c"]
+    
+    ---LLM REPLY---
+    ["a", "b", "c"]
+    ---Parsed Response (string)---
+    "[\"a\", \"b\", \"c\"]"
+

Teardown

PASSED test_aws_bedrock 0:00:02.266159

Setup

Call

Captured stdout call
streamed  'Here'
+streamed  'Here is'
+streamed  'Here is a'
+streamed  'Here is a short'
+streamed  'Here is a short story'
+streamed  'Here is a short story about'
+streamed  'Here is a short story about lightning'
+streamed  'Here is a short story about lightning in'
+streamed  'Here is a short story about lightning in a'
+streamed  'Here is a short story about lightning in a rock'
+streamed  'Here is a short story about lightning in a rock:'
+streamed  'Here is a short story about lightning in a rock:\n\nThe'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of Creation'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob ha'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been'
+streamed  'Here is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking'
+streamed  're is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through'
+streamed  's a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the'
+streamed  ' short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the ru'
+streamed  'ort story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugge'
+streamed  'bout lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains'
+streamed  ' lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for'
+streamed  'ning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours'
+streamed  'ing in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours,'
+streamed  'a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking'
+streamed  'ock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in'
+streamed  '\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in the'
+streamed  'park of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in the breath'
+streamed  'ark of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in the breatht'
+streamed  'f Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in the breathtaking'
+streamed  'tion\n\nJacob had been hiking through the rugged mountains for hours, taking in the breathtaking views'
+streamed  'n\n\nJacob had been hiking through the rugged mountains for hours, taking in the breathtaking views an'
+streamed  'cob had been hiking through the rugged mountains for hours, taking in the breathtaking views and rev'
+streamed  'ad been hiking through the rugged mountains for hours, taking in the breathtaking views and reveling'
+streamed  'been hiking through the rugged mountains for hours, taking in the breathtaking views and reveling in'
+streamed  ' hiking through the rugged mountains for hours, taking in the breathtaking views and reveling in the'
+streamed  'ing through the rugged mountains for hours, taking in the breathtaking views and reveling in the sol'
+streamed  'hrough the rugged mountains for hours, taking in the breathtaking views and reveling in the solitude'
+streamed  'ugh the rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of'
+streamed  ' rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature'
+streamed  'rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature.'
+streamed  'ged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature. As'
+streamed  ' mountains for hours, taking in the breathtaking views and reveling in the solitude of nature. As he'
+streamed  'ins for hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounde'
+streamed  ' for hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a'
+streamed  ' hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a ben'
+streamed  'rs, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in'
+streamed  'taking in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the'
+streamed  ' in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the trail'
+streamed  'in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the trail,'
+streamed  'athtaking views and reveling in the solitude of nature. As he rounded a bend in the trail, something'
+streamed  'ng views and reveling in the solitude of nature. As he rounded a bend in the trail, something caught'
+streamed  'iews and reveling in the solitude of nature. As he rounded a bend in the trail, something caught his'
+streamed  ' and reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye'
+streamed  'nd reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye -'
+streamed  ' reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a'
+streamed  'veling in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a ja'
+streamed  'ing in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagge'
+streamed  'the solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece'
+streamed  ' solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of'
+streamed  'tude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock'
+streamed  'e of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock gl'
+streamed  'ature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting'
+streamed  're. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in'
+streamed  'As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the'
+streamed  'he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the mi'
+streamed  'ounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday'
+streamed  'ed a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun'
+streamed  'd a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun.'
+streamed  ' in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious'
+streamed  'in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious,'
+streamed  'the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he'
+streamed  'trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he sto'
+streamed  'il, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stoope'
+streamed  'mething caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down'
+streamed  'hing caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to'
+streamed  'caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take'
+streamed  'ught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a'
+streamed  's eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer'
+streamed  ' - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look'
+streamed  '- a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.'
+streamed  'ged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he'
+streamed  'ece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picke'
+streamed  'of rock glinting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up'
+streamed  'ock glinting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the'
+streamed  'linting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock'
+streamed  'inting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock,'
+streamed  'ting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a'
+streamed  ' the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden'
+streamed  'he midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden j'
+streamed  'midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden jolt'
+streamed  'midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden jolt'
+streamed  'midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden jolt'
+streamed  'midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden jolt'
+streamed final Here is a short story about lightning in a rock:
+
+The Spark of Creation
+
+Jacob had been hiking through the rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.
+
+As he picked up the rock, a sudden jolt
+
Captured stderr call
[2024-07-24T06:57:14Z INFO  baml_events] Function TestAws:
+    Client: AwsBedrock (anthropic.claude-3-haiku-20240307-v1:0) - 2251ms
+    ---PROMPT---
+    [chat] user: Write a nice short story about lightning in a rock
+    
+    ---LLM REPLY---
+    Here is a short story about lightning in a rock:
+    
+    The Spark of Creation
+    
+    Jacob had been hiking through the rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.
+    
+    As he picked up the rock, a sudden jolt
+    ---Parsed Response (string)---
+    "Here is a short story about lightning in a rock:\n\nThe Spark of Creation\n\nJacob had been hiking through the rugged mountains for hours, taking in the breathtaking views and reveling in the solitude of nature. As he rounded a bend in the trail, something caught his eye - a jagged piece of rock glinting in the midday sun. Curious, he stooped down to take a closer look.\n\nAs he picked up the rock, a sudden jolt"
+

Teardown

PASSED test_serialization_exception 0:00:00.478442

Setup

Call

Captured stdout call
Exception message:  <ExceptionInfo BamlError('Client: GPT35 (gpt-3.5-turbo-0125) - 468ms\n---PROMPT---\n[chat] system: Say "hello there".\n\n---LLM REPLY...day?\n---Parsed Response---\nFailed to coerce value: Error parsing \'<root>\': Missing required fields: nonce, nonce2') tblen=2>
+
Captured stderr call
[2024-07-24T06:57:15Z WARN  baml_events] Function DummyOutputFunction:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 468ms
+    ---PROMPT---
+    [chat] system: Say "hello there".
+    
+    ---LLM REPLY---
+    Hello there! How can I assist you today?
+    ---Parsed Response---
+    Failed to coerce value: Error parsing '<root>': Missing required fields: nonce, nonce2
+

Teardown

PASSED test_stream_serialization_exception 0:00:00.721384

Setup

Call

Captured stdout call
streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+streamed  nonce=None nonce2=None
+Exception message:  <ExceptionInfo BamlError('Client: GPT35 (gpt-3.5-turbo-0125) - 711ms\n---PROMPT---\n[chat] system: Say "hello there".\n\n---LLM REPLY...day?\n---Parsed Response---\nFailed to coerce value: Error parsing \'<root>\': Missing required fields: nonce, nonce2') tblen=2>
+
Captured stderr call
[2024-07-24T06:57:15Z WARN  baml_events] Function DummyOutputFunction:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 711ms
+    ---PROMPT---
+    [chat] system: Say "hello there".
+    
+    ---LLM REPLY---
+    Hello there! How can I assist you today?
+    ---Parsed Response---
+    Failed to coerce value: Error parsing '<root>': Missing required fields: nonce, nonce2
+

Teardown

PASSED test_stream2_serialization_exception 0:00:00.404353

Setup

Call

Captured stdout call
streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+streamed  nonce=None nonce2=None nonce3=None
+Exception message:  <ExceptionInfo BamlError('Client: GPT35 (gpt-3.5-turbo-0125) - 396ms\n---PROMPT---\n[chat] system: Say "hello there".\n\n---LLM REPLY...-Parsed Response---\nFailed to coerce value: Error parsing \'<root>\': Missing required fields: nonce, nonce2, nonce3') tblen=2>
+
Captured stderr call
[2024-07-24T06:57:16Z WARN  baml_events] Function DummyOutputFunction:
+    Client: GPT35 (gpt-3.5-turbo-0125) - 396ms
+    ---PROMPT---
+    [chat] system: Say "hello there".
+    
+    ---LLM REPLY---
+    Hello there! How can I assist you today?
+    ---Parsed Response---
+    Failed to coerce value: Error parsing '<root>': Missing required fields: nonce, nonce2, nonce3
+

Teardown

\ No newline at end of file diff --git a/integ-tests/python/tests/test_functions.py b/integ-tests/python/tests/test_functions.py index b00cb9f66..14fe240bd 100644 --- a/integ-tests/python/tests/test_functions.py +++ b/integ-tests/python/tests/test_functions.py @@ -1,4 +1,5 @@ import time +from typing import List import pytest from assertpy import assert_that from dotenv import load_dotenv @@ -11,11 +12,12 @@ from ..baml_client.globals import ( DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME, ) +from ..baml_client import partial_types from ..baml_client.types import ( DynInputOutput, NamedArgsSingleEnumList, NamedArgsSingleClass, - StringToClassEntry, + StringToClassEntry, ) from ..baml_client.tracing import trace, set_tags, flush, on_log_event from ..baml_client.type_builder import TypeBuilder @@ -25,7 +27,6 @@ import random - def test_sync(): res = sync_b.TestFnNamedArgsSingleClass( myArg=NamedArgsSingleClass( @@ -39,7 +40,6 @@ def test_sync(): class TestAllInputs: - @pytest.mark.asyncio async def test_single_bool(self): res = await b.TestFnNamedArgsSingleBool(True) @@ -94,18 +94,22 @@ async def test_single_int(self): @pytest.mark.asyncio async def test_single_map_string_to_string(self): - res = await b.TestFnNamedArgsSingleMapStringToString({'lorem': 'ipsum', 'dolor': 'sit'}) - assert 'lorem' in res + res = await b.TestFnNamedArgsSingleMapStringToString( + {"lorem": "ipsum", "dolor": "sit"} + ) + assert "lorem" in res @pytest.mark.asyncio async def test_single_map_string_to_class(self): - res = await b.TestFnNamedArgsSingleMapStringToClass({'lorem': StringToClassEntry(word='ipsum')}) - assert res['lorem'].word == 'ipsum' + res = await b.TestFnNamedArgsSingleMapStringToClass( + {"lorem": StringToClassEntry(word="ipsum")} + ) + assert res["lorem"].word == "ipsum" @pytest.mark.asyncio async def test_single_map_string_to_map(self): - res = await b.TestFnNamedArgsSingleMapStringToMap({'lorem': {'word': 'ipsum'}}) - assert res['lorem']['word'] == 'ipsum' + res = await b.TestFnNamedArgsSingleMapStringToMap({"lorem": {"word": "ipsum"}}) + assert res["lorem"]["word"] == "ipsum" class MyCustomClass(NamedArgsSingleClass): @@ -157,6 +161,21 @@ async def test_should_work_with_image_url(): assert_that(res.lower()).matches(r"(green|yellow|shrek|ogre)") +@pytest.mark.asyncio +async def test_should_work_with_image_list(): + res = await b.TestImageListInput( + imgs=[ + baml_py.Image.from_url( + "https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png" + ), + baml_py.Image.from_url( + "https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png" + ), + ] + ) + assert_that(res.lower()).matches(r"(green|yellow)") + + @pytest.mark.asyncio async def test_should_work_with_vertex(): res = await b.TestVertex("donkey kong") @@ -261,11 +280,12 @@ async def test_streaming(): assert len(final) > 0, "Expected non-empty final but got empty." assert len(msgs) > 0, "Expected at least one streamed response but got none." for prev_msg, msg in zip(msgs, msgs[1:]): - assert msg.startswith( - prev_msg - ), "Expected messages to be continuous, but prev was %r and next was %r" % ( - prev_msg, - msg, + assert msg.startswith(prev_msg), ( + "Expected messages to be continuous, but prev was %r and next was %r" + % ( + prev_msg, + msg, + ) ) assert msgs[-1] == final, "Expected last stream message to match final response." @@ -305,11 +325,12 @@ def test_streaming_sync(): assert len(final) > 0, "Expected non-empty final but got empty." assert len(msgs) > 0, "Expected at least one streamed response but got none." for prev_msg, msg in zip(msgs, msgs[1:]): - assert msg.startswith( - prev_msg - ), "Expected messages to be continuous, but prev was %r and next was %r" % ( - prev_msg, - msg, + assert msg.startswith(prev_msg), ( + "Expected messages to be continuous, but prev was %r and next was %r" + % ( + prev_msg, + msg, + ) ) assert msgs[-1] == final, "Expected last stream message to match final response." @@ -332,11 +353,12 @@ async def test_streaming_claude(): assert len(final) > 0, "Expected non-empty final but got empty." assert len(msgs) > 0, "Expected at least one streamed response but got none." for prev_msg, msg in zip(msgs, msgs[1:]): - assert msg.startswith( - prev_msg - ), "Expected messages to be continuous, but prev was %r and next was %r" % ( - prev_msg, - msg, + assert msg.startswith(prev_msg), ( + "Expected messages to be continuous, but prev was %r and next was %r" + % ( + prev_msg, + msg, + ) ) print("msgs:") print(msgs[-1]) @@ -357,11 +379,12 @@ async def test_streaming_gemini(): assert len(final) > 0, "Expected non-empty final but got empty." assert len(msgs) > 0, "Expected at least one streamed response but got none." for prev_msg, msg in zip(msgs, msgs[1:]): - assert msg.startswith( - prev_msg - ), "Expected messages to be continuous, but prev was %r and next was %r" % ( - prev_msg, - msg, + assert msg.startswith(prev_msg), ( + "Expected messages to be continuous, but prev was %r and next was %r" + % ( + prev_msg, + msg, + ) ) print("msgs:") print(msgs[-1]) @@ -372,7 +395,6 @@ async def test_streaming_gemini(): @pytest.mark.asyncio async def test_tracing_async_only(): - @trace async def top_level_async_tracing(): @trace @@ -418,7 +440,7 @@ async def dummy_fn(foo: str): def test_tracing_sync(): # res = parent_sync("first-arg-value") - res2 = sync_dummy_func("second-dummycall-arg") + _ = sync_dummy_func("second-dummycall-arg") def test_tracing_thread_pool(): @@ -491,7 +513,6 @@ def parent_sync(myStr: str): return "hello world parentsync" - @trace async def async_dummy_func(myArgggg: str): await asyncio.sleep(0.5 + random.random()) @@ -504,7 +525,7 @@ def sync_dummy_func(dummyFuncArg: str): @pytest.fixture(scope="session", autouse=True) -def cleanup(request): +def cleanup(): """Cleanup a testing directory once we are finished.""" flush() @@ -600,7 +621,7 @@ async def test_dynamic_class_nested_output_stream(): input="My name is Mark Gonzalez. My hair is black and I'm 6 feet tall.", baml_options={"tb": tb}, ) - msgs = [] + msgs: List[partial_types.DynamicOutput] = [] async for msg in stream: print("streamed ", msg) print("streamed ", msg.model_dump()) @@ -630,7 +651,7 @@ async def test_stream_dynamic_class_output(): input="My name is Harrison. My hair is black and I'm 6 feet tall.", baml_options={"tb": tb, "client_registry": cr}, ) - msgs = [] + msgs: List[partial_types.DynamicOutput] = [] async for msg in stream: print("streamed ", msg.model_dump()) msgs.append(msg) @@ -653,8 +674,8 @@ async def test_dynamic_inputs_list2(): res = await b.DynamicListInputOutput( [ - DynInputOutput( - **{ + DynInputOutput.model_validate( + { "new_key": "hi1", "testKey": "myTest", "blah": { @@ -662,13 +683,15 @@ async def test_dynamic_inputs_list2(): }, } ), - { - "new_key": "hi", - "testKey": "myTest", - "blah": { - "nestedKey1": "nestedVal", - }, - }, + DynInputOutput.model_validate( + { + "new_key": "hi", + "testKey": "myTest", + "blah": { + "nestedKey1": "nestedVal", + }, + } + ), ], {"tb": tb}, ) @@ -690,20 +713,24 @@ async def test_dynamic_inputs_list(): res = await b.DynamicListInputOutput( [ - { - "new_key": "hi", - "testKey": "myTest", - "blah": { - "nestedKey1": "nestedVal", - }, - }, - { - "new_key": "hi", - "testKey": "myTest", - "blah": { - "nestedKey1": "nestedVal", - }, - }, + DynInputOutput.model_validate( + { + "new_key": "hi", + "testKey": "myTest", + "blah": { + "nestedKey1": "nestedVal", + }, + } + ), + DynInputOutput.model_validate( + { + "new_key": "hi", + "testKey": "myTest", + "blah": { + "nestedKey1": "nestedVal", + }, + } + ), ], {"tb": tb}, ) @@ -715,12 +742,84 @@ async def test_dynamic_inputs_list(): assert res[1].blah["nestedKey1"] == "nestedVal" +@pytest.mark.asyncio +async def test_dynamic_output_map(): + tb = TypeBuilder() + tb.DynamicOutput.add_property("hair_color", tb.string()) + tb.DynamicOutput.add_property( + "attributes", tb.map(tb.string(), tb.string()) + ).description("Things like 'eye_color' or 'facial_hair'") + print(tb.DynamicOutput.list_properties()) + for prop, _ in tb.DynamicOutput.list_properties(): + print(f"Property: {prop}") + + res = await b.MyFunc( + input="My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard.", + baml_options={"tb": tb}, + ) + + print("final ", res) + print("final ", res.model_dump()) + print("final ", res.model_dump_json()) + assert res.hair_color == "black" + assert res.attributes["eye_color"] == "blue" + assert res.attributes["facial_hair"] == "beard" + + +@pytest.mark.asyncio +async def test_dynamic_output_union(): + tb = TypeBuilder() + tb.DynamicOutput.add_property("hair_color", tb.string()) + tb.DynamicOutput.add_property( + "attributes", tb.map(tb.string(), tb.string()) + ).description("Things like 'eye_color' or 'facial_hair'") + # Define two classes + class1 = tb.add_class("Class1") + class1.add_property("meters", tb.float()) + + class2 = tb.add_class("Class2") + class2.add_property("feet", tb.float()) + class2.add_property("inches", tb.float().optional()) + + # Use the classes in a union property + tb.DynamicOutput.add_property("height", tb.union([class1.type(), class2.type()])) + print(tb.DynamicOutput.list_properties()) + for prop, _ in tb.DynamicOutput.list_properties(): + print(f"Property: {prop}") + + res = await b.MyFunc( + input="My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard. I am 30 years old.", + baml_options={"tb": tb}, + ) + + print("final ", res) + print("final ", res.model_dump()) + print("final ", res.model_dump_json()) + assert res.hair_color == "black" + assert res.attributes["eye_color"] == "blue" + assert res.attributes["facial_hair"] == "beard" + assert res.height["feet"] == 6 + + res = await b.MyFunc( + input="My name is Harrison. My hair is black and I'm 1.8 meters tall. I have blue eyes and a beard. I am 30 years old.", + baml_options={"tb": tb}, + ) + + print("final ", res) + print("final ", res.model_dump()) + print("final ", res.model_dump_json()) + assert res.hair_color == "black" + assert res.attributes["eye_color"] == "blue" + assert res.attributes["facial_hair"] == "beard" + assert res.height["meters"] == 1.8 + + @pytest.mark.asyncio async def test_nested_class_streaming(): stream = b.stream.FnOutputClassNested( input="My name is Harrison. My hair is black and I'm 6 feet tall." ) - msgs = [] + msgs: List[partial_types.TestClassNested] = [] async for msg in stream: print("streamed ", msg.model_dump(mode="json")) msgs.append(msg) @@ -736,11 +835,10 @@ async def test_dynamic_clients(): cb.add_llm_client("MyClient", "openai", {"model": "gpt-3.5-turbo"}) cb.set_primary("MyClient") - final = await b.TestOllama( - input="My name is Harrison. My hair is black and I'm 6 feet tall.", + capitol = await b.ExpectFailure( baml_options={"client_registry": cb}, ) - print("final ", final) + assert_that(capitol.lower()).contains("london") @pytest.mark.asyncio @@ -791,7 +889,7 @@ async def test_stream_serialization_exception(): async for msg in stream: print("streamed ", msg) - res = await stream.get_final_response() + _ = await stream.get_final_response() print("Exception message: ", excinfo) assert "Failed to coerce" in str(excinfo) @@ -807,7 +905,7 @@ async def stream_func(): async for msg in stream: print("streamed ", msg) - res = await stream.get_final_response() + _ = await stream.get_final_response() print("Exception message: ", excinfo) assert "Failed to coerce" in str(excinfo) diff --git a/integ-tests/ruby/Gemfile b/integ-tests/ruby/Gemfile index c24e9aac4..741fc3c89 100644 --- a/integ-tests/ruby/Gemfile +++ b/integ-tests/ruby/Gemfile @@ -2,9 +2,9 @@ source "https://rubygems.org" +gem "baml" gem "rake", "~> 13.0" gem "sorbet-runtime" -gem "sorbet-struct-comparable" group :test do gem "minitest-reporters" diff --git a/integ-tests/ruby/Gemfile.lock b/integ-tests/ruby/Gemfile.lock index f7d0cacd6..d3276af98 100644 --- a/integ-tests/ruby/Gemfile.lock +++ b/integ-tests/ruby/Gemfile.lock @@ -2,6 +2,7 @@ GEM remote: https://rubygems.org/ specs: ansi (1.5.0) + baml (0.52.2-arm64-darwin-23) builder (3.2.4) minitest (5.23.1) minitest-reporters (1.6.1) @@ -9,26 +10,19 @@ GEM builder minitest (>= 5.0) ruby-progressbar - polyfill (1.9.0) rake (13.2.1) ruby-progressbar (1.13.0) - safe_type (1.1.1) - sorbet-coerce (0.7.0) - polyfill (~> 1.8) - safe_type (~> 1.1, >= 1.1.1) - sorbet-runtime (>= 0.4.4704) - sorbet-runtime (0.5.11409) + sorbet-runtime (0.5.11500) sorbet-struct-comparable (1.3.0) sorbet-runtime (>= 0.5) PLATFORMS arm64-darwin-23 - ruby DEPENDENCIES + baml minitest-reporters rake (~> 13.0) - sorbet-coerce sorbet-runtime sorbet-struct-comparable diff --git a/integ-tests/ruby/Rakefile b/integ-tests/ruby/Rakefile index 13afb7d0d..aedb3eb15 100644 --- a/integ-tests/ruby/Rakefile +++ b/integ-tests/ruby/Rakefile @@ -10,6 +10,7 @@ end Rake::TestTask.new do |t| t.libs << "../../engine/language_client_ruby/lib" t.libs << "baml_client" + # t.test_files = FileList["test_filtered.rb"] t.test_files = FileList["test_*.rb"] t.options = '--verbose' end \ No newline at end of file diff --git a/integ-tests/ruby/baml_client/client.rb b/integ-tests/ruby/baml_client/client.rb index 4c7e0427c..870c20597 100644 --- a/integ-tests/ruby/baml_client/client.rb +++ b/integ-tests/ruby/baml_client/client.rb @@ -2,7 +2,7 @@ # # Welcome to Baml! To use this generated code, please run the following: # -# $ bundle add baml sorbet-runtime sorbet-struct-comparable +# $ bundle add baml sorbet-runtime # ############################################################################### @@ -19,6 +19,7 @@ require_relative "inlined" require_relative "partial-types" require_relative "types" +require_relative "type-registry" module Baml @instance = nil @@ -50,1355 +51,2241 @@ def self.from_directory(path) end sig { - params( + varargs: T.untyped, recipe: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Recipe) - } def AaaSamOutputFormat( - recipe: + *varargs, + recipe:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("AaaSamOutputFormat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "AaaSamOutputFormat", { - "recipe" => recipe, + recipe: recipe, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, aud: Baml::Audio, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def AudioInput( - aud: + *varargs, + aud:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("AudioInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "AudioInput", { - "aud" => aud, + aud: aud, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Category) - } def ClassifyMessage( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ClassifyMessage", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Category) - } def ClassifyMessage2( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ClassifyMessage2", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Category) - } def ClassifyMessage3( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage3 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ClassifyMessage3", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, img: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def DescribeImage( - img: + *varargs, + img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DescribeImage", { - "img" => img, + img: img, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def DescribeImage2( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DescribeImage2", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def DescribeImage3( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage3 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DescribeImage3", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def DescribeImage4( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage4 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DescribeImage4", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::DummyOutput) - } def DummyOutputFunction( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DummyOutputFunction may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DummyOutputFunction", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: Baml::Types::DynamicClassOne, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::DynamicClassTwo) - } def DynamicFunc( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicFunc may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DynamicFunc", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: Baml::Types::DynInputOutput, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::DynInputOutput) - } def DynamicInputOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicInputOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DynamicInputOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: T::Array[Baml::Types::DynInputOutput], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[Baml::Types::DynInputOutput]) - } def DynamicListInputOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicListInputOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "DynamicListInputOutput", { - "input" => input, + input: input, + }, + @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], + ) + (raw.parsed_using_types(Baml::Types)) + end + + sig { + params( + varargs: T.untyped, + + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(String) + } + def ExpectFailure( + *varargs, + + baml_options: {} + ) + if varargs.any? + + raise ArgumentError.new("ExpectFailure may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + + raw = @runtime.call_function( + "ExpectFailure", + { + }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[String]) - } def ExtractNames( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractNames may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ExtractNames", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, text: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[Baml::Types::Person]) - } def ExtractPeople( - text: + *varargs, + text:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractPeople may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ExtractPeople", { - "text" => text, + text: text, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, email: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::ReceiptInfo) - } def ExtractReceiptInfo( - email: + *varargs, + email:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractReceiptInfo may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ExtractReceiptInfo", { - "email" => email, + email: email, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, resume: String,img: T.nilable(Baml::Image), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Resume) - } def ExtractResume( - resume:,img: + *varargs, + resume:,img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractResume may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ExtractResume", { - "resume" => resume,"img" => img, + resume: resume,img: img, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, resume: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::Resume) - } def ExtractResume2( - resume: + *varargs, + resume:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractResume2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "ExtractResume2", { - "resume" => resume, + resume: resume, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T.nilable(Baml::Types::ClassOptionalOutput)) - } def FnClassOptionalOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnClassOptionalOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnClassOptionalOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T.nilable(Baml::Types::ClassOptionalOutput2)) - } def FnClassOptionalOutput2( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnClassOptionalOutput2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnClassOptionalOutput2", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[Baml::Types::EnumOutput]) - } def FnEnumListOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnEnumListOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnEnumListOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::EnumOutput) - } def FnEnumOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnEnumOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnEnumOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myString: T.nilable(String), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def FnNamedArgsSingleStringOptional( - myString: + *varargs, + myString:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnNamedArgsSingleStringOptional may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnNamedArgsSingleStringOptional", { - "myString" => myString, + myString: myString, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Boolean) - } def FnOutputBool( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputBool may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputBool", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::TestOutputClass) - } def FnOutputClass( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputClass", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[Baml::Types::TestOutputClass]) - } def FnOutputClassList( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputClassList", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::TestClassNested) - } def FnOutputClassNested( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassNested may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputClassNested", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::TestClassWithEnum) - } def FnOutputClassWithEnum( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassWithEnum may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputClassWithEnum", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[String]) - } def FnOutputStringList( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputStringList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnOutputStringList", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::TestEnum) - } def FnTestAliasedEnumOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestAliasedEnumOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnTestAliasedEnumOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::TestClassAlias) - } def FnTestClassAlias( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestClassAlias may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnTestClassAlias", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleEnum, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def FnTestNamedArgsSingleEnum( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestNamedArgsSingleEnum may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "FnTestNamedArgsSingleEnum", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, text: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::RaysData) - } def GetDataType( - text: + *varargs, + text:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetDataType may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "GetDataType", { - "text" => text, + text: text, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, email: Baml::Types::Email, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::OrderInfo) - } def GetOrderInfo( - email: + *varargs, + email:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetOrderInfo may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "GetOrderInfo", { - "email" => email, + email: email, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, query: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::SearchParams) - } def GetQuery( - query: + *varargs, + query:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetQuery may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "GetQuery", { - "query" => query, + query: query, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::DynamicOutput) - } def MyFunc( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("MyFunc may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "MyFunc", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Array[T.nilable(Baml::Types::OptionalTest_ReturnType)]) - } def OptionalTest_Function( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("OptionalTest_Function may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "OptionalTest_Function", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestClaude( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaude may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestClaude", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestClaudeChat( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaudeChat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestClaudeChat", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestClaudeChatNoSystem( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaudeChatNoSystem may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestClaudeChatNoSystem", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestOpenAI( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAI may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestOpenAI", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestOpenAIChat( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAIChat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestOpenAIChat", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestOpenAIChatNoSystem( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAIChatNoSystem may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestOpenAIChatNoSystem", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def PromptTestStreaming( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestStreaming may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "PromptTestStreaming", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestAnthropic( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAnthropic may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestAnthropic", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestAws( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAws may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestAws", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestAzure( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAzure may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestAzure", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - - returns(String) - + params( + varargs: T.untyped, + + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(String) } def TestFallbackClient( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFallbackClient may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFallbackClient", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myBool: T::Boolean, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleBool( - myBool: + *varargs, + myBool:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleBool may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleBool", { - "myBool" => myBool, + myBool: myBool, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleClass, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleClass( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleClass", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myArg: T::Array[Baml::Types::NamedArgsSingleEnumList], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleEnumList( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleEnumList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleEnumList", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myFloat: Float, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleFloat( - myFloat: + *varargs, + myFloat:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleFloat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleFloat", { - "myFloat" => myFloat, + myFloat: myFloat, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myInt: Integer, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleInt( - myInt: + *varargs, + myInt:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleInt may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleInt", { - "myInt" => myInt, + myInt: myInt, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myMap: T::Hash[String, Baml::Types::StringToClassEntry], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Hash[String, Baml::Types::StringToClassEntry]) - } def TestFnNamedArgsSingleMapStringToClass( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleMapStringToClass", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myMap: T::Hash[String, T::Hash[String, String]], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Hash[String, T::Hash[String, String]]) - } def TestFnNamedArgsSingleMapStringToMap( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToMap may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleMapStringToMap", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myMap: T::Hash[String, String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(T::Hash[String, String]) - } def TestFnNamedArgsSingleMapStringToString( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToString may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleMapStringToString", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myString: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleString( - myString: + *varargs, + myString:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleString may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleString", { - "myString" => myString, + myString: myString, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myStringArray: T::Array[String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleStringArray( - myStringArray: + *varargs, + myStringArray:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleStringArray may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleStringArray", { - "myStringArray" => myStringArray, + myStringArray: myStringArray, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myArg: T::Array[String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestFnNamedArgsSingleStringList( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleStringList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestFnNamedArgsSingleStringList", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestGemini( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestGemini may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestGemini", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, img: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestImageInput( - img: + *varargs, + img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestImageInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestImageInput", { - "img" => img, + img: img, + }, + @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], + ) + (raw.parsed_using_types(Baml::Types)) + end + + sig { + params( + varargs: T.untyped, + imgs: T::Array[Baml::Image], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(String) + } + def TestImageListInput( + *varargs, + imgs:, + baml_options: {} + ) + if varargs.any? + + raise ArgumentError.new("TestImageListInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + + raw = @runtime.call_function( + "TestImageListInput", + { + imgs: imgs, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleClass,myArg2: Baml::Types::NamedArgsSingleClass, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestMulticlassNamedArgs( - myArg:,myArg2: + *varargs, + myArg:,myArg2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestMulticlassNamedArgs may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestMulticlassNamedArgs", { - "myArg" => myArg,"myArg2" => myArg2, + myArg: myArg,myArg2: myArg2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestOllama( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestOllama may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestOllama", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestOpenAILegacyProvider( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestOpenAILegacyProvider may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestOpenAILegacyProvider", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - - returns(String) - + params( + varargs: T.untyped, + + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(String) } def TestRetryConstant( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestRetryConstant may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestRetryConstant", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - - returns(String) - + params( + varargs: T.untyped, + + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(String) } def TestRetryExponential( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestRetryExponential may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestRetryExponential", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(String) - } def TestVertex( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestVertex may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "TestVertex", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end sig { - params( + varargs: T.untyped, input: T.any(String, T::Boolean), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::Types::UnionTest_ReturnType) - } def UnionTest_Function( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("UnionTest_Function may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.call_function( "UnionTest_Function", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) (raw.parsed_using_types(Baml::Types)) end @@ -1418,18 +2305,32 @@ def initialize(runtime:, ctx_manager:) sig { params( + varargs: T.untyped, recipe: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Recipe]) } def AaaSamOutputFormat( - recipe: + *varargs, + recipe:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("AaaSamOutputFormat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "AaaSamOutputFormat", { - "recipe" => recipe, + recipe: recipe, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::Recipe, Baml::Types::Recipe].new( ffi_stream: raw, @@ -1439,18 +2340,32 @@ def AaaSamOutputFormat( sig { params( + varargs: T.untyped, aud: Baml::Audio, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def AudioInput( - aud: + *varargs, + aud:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("AudioInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "AudioInput", { - "aud" => aud, + aud: aud, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1460,18 +2375,32 @@ def AudioInput( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Category]) } def ClassifyMessage( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ClassifyMessage", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(Baml::Types::Category), Baml::Types::Category].new( ffi_stream: raw, @@ -1481,18 +2410,32 @@ def ClassifyMessage( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Category]) } def ClassifyMessage2( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ClassifyMessage2", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(Baml::Types::Category), Baml::Types::Category].new( ffi_stream: raw, @@ -1502,18 +2445,32 @@ def ClassifyMessage2( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Category]) } def ClassifyMessage3( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ClassifyMessage3 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ClassifyMessage3", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(Baml::Types::Category), Baml::Types::Category].new( ffi_stream: raw, @@ -1523,18 +2480,32 @@ def ClassifyMessage3( sig { params( + varargs: T.untyped, img: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def DescribeImage( - img: + *varargs, + img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DescribeImage", { - "img" => img, + img: img, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1544,18 +2515,32 @@ def DescribeImage( sig { params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def DescribeImage2( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DescribeImage2", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1565,18 +2550,32 @@ def DescribeImage2( sig { params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def DescribeImage3( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage3 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DescribeImage3", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1586,18 +2585,32 @@ def DescribeImage3( sig { params( + varargs: T.untyped, classWithImage: Baml::Types::ClassWithImage,img2: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def DescribeImage4( - classWithImage:,img2: + *varargs, + classWithImage:,img2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DescribeImage4 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DescribeImage4", { - "classWithImage" => classWithImage,"img2" => img2, + classWithImage: classWithImage,img2: img2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1607,18 +2620,32 @@ def DescribeImage4( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::DummyOutput]) } def DummyOutputFunction( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DummyOutputFunction may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DummyOutputFunction", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::DummyOutput, Baml::Types::DummyOutput].new( ffi_stream: raw, @@ -1628,18 +2655,32 @@ def DummyOutputFunction( sig { params( + varargs: T.untyped, input: Baml::Types::DynamicClassOne, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::DynamicClassTwo]) } def DynamicFunc( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicFunc may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DynamicFunc", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::DynamicClassTwo, Baml::Types::DynamicClassTwo].new( ffi_stream: raw, @@ -1649,18 +2690,32 @@ def DynamicFunc( sig { params( + varargs: T.untyped, input: Baml::Types::DynInputOutput, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::DynInputOutput]) } def DynamicInputOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicInputOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DynamicInputOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::DynInputOutput, Baml::Types::DynInputOutput].new( ffi_stream: raw, @@ -1670,18 +2725,32 @@ def DynamicInputOutput( sig { params( + varargs: T.untyped, input: T::Array[Baml::Types::DynInputOutput], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[Baml::Types::DynInputOutput]]) } def DynamicListInputOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("DynamicListInputOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "DynamicListInputOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[Baml::PartialTypes::DynInputOutput], T::Array[Baml::Types::DynInputOutput]].new( ffi_stream: raw, @@ -1691,18 +2760,67 @@ def DynamicListInputOutput( sig { params( + varargs: T.untyped, + + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(Baml::BamlStream[String]) + } + def ExpectFailure( + *varargs, + + baml_options: {} + ) + if varargs.any? + + raise ArgumentError.new("ExpectFailure may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + + raw = @runtime.stream_function( + "ExpectFailure", + { + + }, + @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], + ) + Baml::BamlStream[T.nilable(String), String].new( + ffi_stream: raw, + ctx_manager: @ctx_manager + ) + end + + sig { + params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[String]]) } def ExtractNames( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractNames may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ExtractNames", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[T.nilable(String)], T::Array[String]].new( ffi_stream: raw, @@ -1712,18 +2830,32 @@ def ExtractNames( sig { params( + varargs: T.untyped, text: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[Baml::Types::Person]]) } def ExtractPeople( - text: + *varargs, + text:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractPeople may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ExtractPeople", { - "text" => text, + text: text, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[Baml::PartialTypes::Person], T::Array[Baml::Types::Person]].new( ffi_stream: raw, @@ -1733,18 +2865,32 @@ def ExtractPeople( sig { params( + varargs: T.untyped, email: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::ReceiptInfo]) } def ExtractReceiptInfo( - email: + *varargs, + email:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractReceiptInfo may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ExtractReceiptInfo", { - "email" => email, + email: email, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::ReceiptInfo, Baml::Types::ReceiptInfo].new( ffi_stream: raw, @@ -1754,18 +2900,32 @@ def ExtractReceiptInfo( sig { params( + varargs: T.untyped, resume: String,img: T.nilable(Baml::Image), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Resume]) } def ExtractResume( - resume:,img: + *varargs, + resume:,img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractResume may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ExtractResume", { - "resume" => resume,"img" => img, + resume: resume,img: img, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::Resume, Baml::Types::Resume].new( ffi_stream: raw, @@ -1775,18 +2935,32 @@ def ExtractResume( sig { params( + varargs: T.untyped, resume: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::Resume]) } def ExtractResume2( - resume: + *varargs, + resume:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("ExtractResume2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "ExtractResume2", { - "resume" => resume, + resume: resume, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::Resume, Baml::Types::Resume].new( ffi_stream: raw, @@ -1796,18 +2970,32 @@ def ExtractResume2( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T.nilable(Baml::Types::ClassOptionalOutput)]) } def FnClassOptionalOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnClassOptionalOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnClassOptionalOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::ClassOptionalOutput, T.nilable(Baml::Types::ClassOptionalOutput)].new( ffi_stream: raw, @@ -1817,18 +3005,32 @@ def FnClassOptionalOutput( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T.nilable(Baml::Types::ClassOptionalOutput2)]) } def FnClassOptionalOutput2( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnClassOptionalOutput2 may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnClassOptionalOutput2", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::ClassOptionalOutput2, T.nilable(Baml::Types::ClassOptionalOutput2)].new( ffi_stream: raw, @@ -1838,18 +3040,32 @@ def FnClassOptionalOutput2( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[Baml::Types::EnumOutput]]) } def FnEnumListOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnEnumListOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnEnumListOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[T.nilable(Baml::Types::EnumOutput)], T::Array[Baml::Types::EnumOutput]].new( ffi_stream: raw, @@ -1859,18 +3075,32 @@ def FnEnumListOutput( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::EnumOutput]) } def FnEnumOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnEnumOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnEnumOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(Baml::Types::EnumOutput), Baml::Types::EnumOutput].new( ffi_stream: raw, @@ -1880,18 +3110,32 @@ def FnEnumOutput( sig { params( + varargs: T.untyped, myString: T.nilable(String), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def FnNamedArgsSingleStringOptional( - myString: + *varargs, + myString:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnNamedArgsSingleStringOptional may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnNamedArgsSingleStringOptional", { - "myString" => myString, + myString: myString, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -1901,18 +3145,32 @@ def FnNamedArgsSingleStringOptional( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Boolean]) } def FnOutputBool( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputBool may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputBool", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(T::Boolean), T::Boolean].new( ffi_stream: raw, @@ -1922,18 +3180,32 @@ def FnOutputBool( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::TestOutputClass]) } def FnOutputClass( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputClass", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::TestOutputClass, Baml::Types::TestOutputClass].new( ffi_stream: raw, @@ -1943,18 +3215,32 @@ def FnOutputClass( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[Baml::Types::TestOutputClass]]) } def FnOutputClassList( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputClassList", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[Baml::PartialTypes::TestOutputClass], T::Array[Baml::Types::TestOutputClass]].new( ffi_stream: raw, @@ -1964,18 +3250,32 @@ def FnOutputClassList( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::TestClassNested]) } def FnOutputClassNested( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassNested may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputClassNested", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::TestClassNested, Baml::Types::TestClassNested].new( ffi_stream: raw, @@ -1985,18 +3285,32 @@ def FnOutputClassNested( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::TestClassWithEnum]) } def FnOutputClassWithEnum( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputClassWithEnum may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputClassWithEnum", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::TestClassWithEnum, Baml::Types::TestClassWithEnum].new( ffi_stream: raw, @@ -2006,18 +3320,32 @@ def FnOutputClassWithEnum( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[String]]) } def FnOutputStringList( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnOutputStringList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnOutputStringList", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[T.nilable(String)], T::Array[String]].new( ffi_stream: raw, @@ -2027,18 +3355,32 @@ def FnOutputStringList( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::TestEnum]) } def FnTestAliasedEnumOutput( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestAliasedEnumOutput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnTestAliasedEnumOutput", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(Baml::Types::TestEnum), Baml::Types::TestEnum].new( ffi_stream: raw, @@ -2048,18 +3390,32 @@ def FnTestAliasedEnumOutput( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::TestClassAlias]) } def FnTestClassAlias( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestClassAlias may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnTestClassAlias", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::TestClassAlias, Baml::Types::TestClassAlias].new( ffi_stream: raw, @@ -2069,18 +3425,32 @@ def FnTestClassAlias( sig { params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleEnum, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def FnTestNamedArgsSingleEnum( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("FnTestNamedArgsSingleEnum may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "FnTestNamedArgsSingleEnum", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2090,18 +3460,32 @@ def FnTestNamedArgsSingleEnum( sig { params( + varargs: T.untyped, text: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::RaysData]) } def GetDataType( - text: + *varargs, + text:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetDataType may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "GetDataType", { - "text" => text, + text: text, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::RaysData, Baml::Types::RaysData].new( ffi_stream: raw, @@ -2111,18 +3495,32 @@ def GetDataType( sig { params( + varargs: T.untyped, email: Baml::Types::Email, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::OrderInfo]) } def GetOrderInfo( - email: + *varargs, + email:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetOrderInfo may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "GetOrderInfo", { - "email" => email, + email: email, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::OrderInfo, Baml::Types::OrderInfo].new( ffi_stream: raw, @@ -2132,18 +3530,32 @@ def GetOrderInfo( sig { params( + varargs: T.untyped, query: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::SearchParams]) } def GetQuery( - query: + *varargs, + query:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("GetQuery may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "GetQuery", { - "query" => query, + query: query, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::SearchParams, Baml::Types::SearchParams].new( ffi_stream: raw, @@ -2153,18 +3565,32 @@ def GetQuery( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::DynamicOutput]) } def MyFunc( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("MyFunc may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "MyFunc", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::DynamicOutput, Baml::Types::DynamicOutput].new( ffi_stream: raw, @@ -2174,18 +3600,32 @@ def MyFunc( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Array[T.nilable(Baml::Types::OptionalTest_ReturnType)]]) } def OptionalTest_Function( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("OptionalTest_Function may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "OptionalTest_Function", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Array[Baml::PartialTypes::OptionalTest_ReturnType], T::Array[T.nilable(Baml::Types::OptionalTest_ReturnType)]].new( ffi_stream: raw, @@ -2195,18 +3635,32 @@ def OptionalTest_Function( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestClaude( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaude may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestClaude", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2216,18 +3670,32 @@ def PromptTestClaude( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestClaudeChat( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaudeChat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestClaudeChat", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2237,18 +3705,32 @@ def PromptTestClaudeChat( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestClaudeChatNoSystem( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestClaudeChatNoSystem may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestClaudeChatNoSystem", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2258,18 +3740,32 @@ def PromptTestClaudeChatNoSystem( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestOpenAI( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAI may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestOpenAI", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2279,18 +3775,32 @@ def PromptTestOpenAI( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestOpenAIChat( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAIChat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestOpenAIChat", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2300,18 +3810,32 @@ def PromptTestOpenAIChat( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestOpenAIChatNoSystem( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestOpenAIChatNoSystem may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestOpenAIChatNoSystem", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2321,18 +3845,32 @@ def PromptTestOpenAIChatNoSystem( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def PromptTestStreaming( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("PromptTestStreaming may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "PromptTestStreaming", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2342,18 +3880,32 @@ def PromptTestStreaming( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestAnthropic( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAnthropic may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestAnthropic", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2363,18 +3915,32 @@ def TestAnthropic( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestAws( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAws may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestAws", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2384,18 +3950,32 @@ def TestAws( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestAzure( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestAzure may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestAzure", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2405,18 +3985,32 @@ def TestAzure( sig { params( + varargs: T.untyped, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFallbackClient( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFallbackClient may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFallbackClient", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2426,18 +4020,32 @@ def TestFallbackClient( sig { params( + varargs: T.untyped, myBool: T::Boolean, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleBool( - myBool: + *varargs, + myBool:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleBool may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleBool", { - "myBool" => myBool, + myBool: myBool, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2447,18 +4055,32 @@ def TestFnNamedArgsSingleBool( sig { params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleClass, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleClass( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleClass", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2468,18 +4090,32 @@ def TestFnNamedArgsSingleClass( sig { params( + varargs: T.untyped, myArg: T::Array[Baml::Types::NamedArgsSingleEnumList], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleEnumList( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleEnumList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleEnumList", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2489,18 +4125,32 @@ def TestFnNamedArgsSingleEnumList( sig { params( + varargs: T.untyped, myFloat: Float, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleFloat( - myFloat: + *varargs, + myFloat:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleFloat may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleFloat", { - "myFloat" => myFloat, + myFloat: myFloat, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2510,18 +4160,32 @@ def TestFnNamedArgsSingleFloat( sig { params( + varargs: T.untyped, myInt: Integer, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleInt( - myInt: + *varargs, + myInt:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleInt may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleInt", { - "myInt" => myInt, + myInt: myInt, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2531,18 +4195,32 @@ def TestFnNamedArgsSingleInt( sig { params( + varargs: T.untyped, myMap: T::Hash[String, Baml::Types::StringToClassEntry], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Hash[String, Baml::Types::StringToClassEntry]]) } def TestFnNamedArgsSingleMapStringToClass( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToClass may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleMapStringToClass", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Hash[String, Baml::PartialTypes::StringToClassEntry], T::Hash[String, Baml::Types::StringToClassEntry]].new( ffi_stream: raw, @@ -2552,18 +4230,32 @@ def TestFnNamedArgsSingleMapStringToClass( sig { params( + varargs: T.untyped, myMap: T::Hash[String, T::Hash[String, String]], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Hash[String, T::Hash[String, String]]]) } def TestFnNamedArgsSingleMapStringToMap( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToMap may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleMapStringToMap", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Hash[String, T::Hash[String, T.nilable(String)]], T::Hash[String, T::Hash[String, String]]].new( ffi_stream: raw, @@ -2573,18 +4265,32 @@ def TestFnNamedArgsSingleMapStringToMap( sig { params( + varargs: T.untyped, myMap: T::Hash[String, String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[T::Hash[String, String]]) } def TestFnNamedArgsSingleMapStringToString( - myMap: + *varargs, + myMap:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleMapStringToString may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleMapStringToString", { - "myMap" => myMap, + myMap: myMap, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T::Hash[String, T.nilable(String)], T::Hash[String, String]].new( ffi_stream: raw, @@ -2594,18 +4300,32 @@ def TestFnNamedArgsSingleMapStringToString( sig { params( + varargs: T.untyped, myString: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleString( - myString: + *varargs, + myString:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleString may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleString", { - "myString" => myString, + myString: myString, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2615,18 +4335,32 @@ def TestFnNamedArgsSingleString( sig { params( + varargs: T.untyped, myStringArray: T::Array[String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleStringArray( - myStringArray: + *varargs, + myStringArray:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleStringArray may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleStringArray", { - "myStringArray" => myStringArray, + myStringArray: myStringArray, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2636,18 +4370,32 @@ def TestFnNamedArgsSingleStringArray( sig { params( + varargs: T.untyped, myArg: T::Array[String], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestFnNamedArgsSingleStringList( - myArg: + *varargs, + myArg:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestFnNamedArgsSingleStringList may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestFnNamedArgsSingleStringList", { - "myArg" => myArg, + myArg: myArg, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2657,18 +4405,32 @@ def TestFnNamedArgsSingleStringList( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestGemini( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestGemini may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestGemini", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2678,18 +4440,67 @@ def TestGemini( sig { params( + varargs: T.untyped, img: Baml::Image, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestImageInput( - img: + *varargs, + img:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestImageInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestImageInput", { - "img" => img, + img: img, + }, + @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], + ) + Baml::BamlStream[T.nilable(String), String].new( + ffi_stream: raw, + ctx_manager: @ctx_manager + ) + end + + sig { + params( + varargs: T.untyped, + imgs: T::Array[Baml::Image], + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] + ).returns(Baml::BamlStream[String]) + } + def TestImageListInput( + *varargs, + imgs:, + baml_options: {} + ) + if varargs.any? + + raise ArgumentError.new("TestImageListInput may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + + raw = @runtime.stream_function( + "TestImageListInput", + { + imgs: imgs, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2699,18 +4510,32 @@ def TestImageInput( sig { params( + varargs: T.untyped, myArg: Baml::Types::NamedArgsSingleClass,myArg2: Baml::Types::NamedArgsSingleClass, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestMulticlassNamedArgs( - myArg:,myArg2: + *varargs, + myArg:,myArg2:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestMulticlassNamedArgs may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestMulticlassNamedArgs", { - "myArg" => myArg,"myArg2" => myArg2, + myArg: myArg,myArg2: myArg2, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2720,18 +4545,32 @@ def TestMulticlassNamedArgs( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestOllama( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestOllama may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestOllama", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2741,18 +4580,32 @@ def TestOllama( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestOpenAILegacyProvider( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestOpenAILegacyProvider may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestOpenAILegacyProvider", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2762,18 +4615,32 @@ def TestOpenAILegacyProvider( sig { params( + varargs: T.untyped, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestRetryConstant( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestRetryConstant may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestRetryConstant", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2783,18 +4650,32 @@ def TestRetryConstant( sig { params( + varargs: T.untyped, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestRetryExponential( + *varargs, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestRetryExponential may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestRetryExponential", { }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2804,18 +4685,32 @@ def TestRetryExponential( sig { params( + varargs: T.untyped, input: String, + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[String]) } def TestVertex( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("TestVertex may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "TestVertex", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[T.nilable(String), String].new( ffi_stream: raw, @@ -2825,18 +4720,32 @@ def TestVertex( sig { params( + varargs: T.untyped, input: T.any(String, T::Boolean), + baml_options: T::Hash[Symbol, T.any(Baml::TypeBuilder, Baml::ClientRegistry)] ).returns(Baml::BamlStream[Baml::Types::UnionTest_ReturnType]) } def UnionTest_Function( - input: + *varargs, + input:, + baml_options: {} ) + if varargs.any? + + raise ArgumentError.new("UnionTest_Function may only be called with keyword arguments") + end + if (baml_options.keys - [:client_registry, :tb]).any? + raise ArgumentError.new("Received unknown keys in baml_options (valid keys: :client_registry, :tb): #{baml_options.keys - [:client_registry, :tb]}") + end + raw = @runtime.stream_function( "UnionTest_Function", { - "input" => input, + input: input, }, @ctx_manager, + baml_options[:tb]&.instance_variable_get(:@registry), + baml_options[:client_registry], ) Baml::BamlStream[Baml::PartialTypes::UnionTest_ReturnType, Baml::Types::UnionTest_ReturnType].new( ffi_stream: raw, diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index 0249069af..410f60a1c 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -2,7 +2,7 @@ # # Welcome to Baml! To use this generated code, please run the following: # -# $ bundle add baml sorbet-runtime sorbet-struct-comparable +# $ bundle add baml sorbet-runtime # ############################################################################### @@ -24,10 +24,11 @@ module Inlined "fiddle-examples/extract-receipt-info.baml" => "class ReceiptItem {\n name string\n description string?\n quantity int\n price float\n}\n\nclass ReceiptInfo {\n items ReceiptItem[]\n total_cost float?\n}\n\nfunction ExtractReceiptInfo(email: string) -> ReceiptInfo {\n client GPT4o\n prompt #\"\n Given the receipt below:\n\n ```\n {{email}}\n ```\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "fiddle-examples/images/image.baml" => "function DescribeImage(img: image) -> string {\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n\n Describe the image below in 20 words:\n {{ img }}\n \"#\n\n}\n\nclass FakeImage {\n url string\n}\n\nclass ClassWithImage {\n myImage image\n param2 string\n fake_image FakeImage\n}\n\n// chat role user present\nfunction DescribeImage2(classWithImage: ClassWithImage, img2: image) -> string { \n client GPT4Turbo\n prompt #\"\n {{ _.role(\"user\") }}\n You should return 2 answers that answer the following commands.\n\n 1. Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n 2. Also tell me what's happening here in one sentence:\n {{ img2 }}\n \"#\n}\n\n// no chat role\nfunction DescribeImage3(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\n\n// system prompt and chat prompt\nfunction DescribeImage4(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n {{ _.role(\"system\")}}\n\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\ntest TestName {\n functions [DescribeImage]\n args {\n img { url \"https://imgs.xkcd.com/comics/standards.png\"}\n }\n}\n", "fiddle-examples/symbol-tuning.baml" => "enum Category3 {\n Refund @alias(\"k1\")\n @description(\"Customer wants to refund a product\")\n\n CancelOrder @alias(\"k2\")\n @description(\"Customer wants to cancel an order\")\n\n TechnicalSupport @alias(\"k3\")\n @description(\"Customer needs help with a technical issue unrelated to account creation or login\")\n\n AccountIssue @alias(\"k4\")\n @description(\"Specifically relates to account-login or account-creation\")\n\n Question @alias(\"k5\")\n @description(\"Customer has a question\")\n}\n\nfunction ClassifyMessage3(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", - "main.baml" => "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.51.0\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.51.0\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.51.0\"\n}\n", + "main.baml" => "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.52.1\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.52.1\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.52.1\"\n}\n", "test-files/aliases/classes.baml" => "class TestClassAlias {\n key string @alias(\"key-dash\") @description(#\"\n This is a description for key\n af asdf\n \"#)\n key2 string @alias(\"key21\")\n key3 string @alias(\"key with space\")\n key4 string //unaliased\n key5 string @alias(\"key.with.punctuation/123\")\n}\n\nfunction FnTestClassAlias(input: string) -> TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml" => "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml" => "// add some functions, classes, enums etc with comments all over.", + "test-files/dynamic/client-registry.baml" => "// Intentionally use a bad key\nclient BadClient {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key \"sk-invalid\"\n }\n}\n\nfunction ExpectFailure() -> string {\n client BadClient\n\n prompt #\"\n What is the capital of England?\n \"#\n}\n", "test-files/dynamic/dynamic.baml" => "class DynamicClassOne {\n @@dynamic\n}\n\nenum DynEnumOne {\n @@dynamic\n}\n\nenum DynEnumTwo {\n @@dynamic\n}\n\nclass SomeClassNestedDynamic {\n hi string\n @@dynamic\n\n}\n\nclass DynamicClassTwo {\n hi string\n some_class SomeClassNestedDynamic\n status DynEnumOne\n @@dynamic\n}\n\nfunction DynamicFunc(input: DynamicClassOne) -> DynamicClassTwo {\n client GPT35\n prompt #\"\n Please extract the schema from \n {{ input }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass DynInputOutput {\n testKey string\n @@dynamic\n}\n\nfunction DynamicInputOutput(input: DynInputOutput) -> DynInputOutput {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\nfunction DynamicListInputOutput(input: DynInputOutput[]) -> DynInputOutput[] {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\n\n\nclass DynamicOutput {\n @@dynamic\n}\n \nfunction MyFunc(input: string) -> DynamicOutput {\n client GPT35\n prompt #\"\n Given a string, extract info using the schema:\n\n {{ input}}\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "test-files/functions/input/named-args/single/named-audio.baml" => "function AudioInput(aud: audio) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Does this sound like a roar? Yes or no? One word no other characters.\n \n {{ aud }}\n \"#\n}\n\n\ntest TestURLAudioInput{\n functions [AudioInput]\n args {\n aud{ \n url https://actions.google.com/sounds/v1/emergency/beeper_emergency_call.ogg\n }\n } \n}\n\n\n", "test-files/functions/input/named-args/single/named-boolean.baml" => "\n\nfunction TestFnNamedArgsSingleBool(myBool: bool) -> string{\n client Vertex\n prompt #\"\n Return this value back to me: {{myBool}}\n \"#\n}\n\ntest TestFnNamedArgsSingleBool {\n functions [TestFnNamedArgsSingleBool]\n args {\n myBool true\n }\n}", @@ -36,10 +37,11 @@ module Inlined "test-files/functions/input/named-args/single/named-enum-list.baml" => "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml" => "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml" => "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", + "test-files/functions/input/named-args/single/named-image-list.baml" => "function TestImageListInput(imgs: image[]) -> string{\n client GPT4o\n prompt #\"\n {{ _.role(\"user\") }}\n\n What colors do these have in common? {{imgs}}\n \"#\n}\n\ntest TestImageListInput {\n functions [TestImageListInput]\n args {\n imgs [\n {\n media_type \"image/png\"\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n },\n {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n ]\n }\n}\n", "test-files/functions/input/named-args/single/named-image.baml" => "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n media_type \"image/png\"\n // url gs://cloud-samples-data/vertex-ai/llm/prompts/landmark1.png\n\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n \n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml" => "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-map-string-to-class.baml" => "class StringToClassEntry {\n word string\n}\n// test string\nfunction TestFnNamedArgsSingleMapStringToClass(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToClass {\n functions [TestFnNamedArgsSingleMapStringToClass]\n args {\n myMap {\n \"key\" {\n word \"lorem ipsum\"\n }\n }\n }\n}\n", - "test-files/functions/input/named-args/single/named-map-string-to-map.baml" => "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}\n", + "test-files/functions/input/named-args/single/named-map-string-to-map.baml" => "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}", "test-files/functions/input/named-args/single/named-map-string-to-string.baml" => "// test string\nfunction TestFnNamedArgsSingleMapStringToString(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToString {\n functions [TestFnNamedArgsSingleMapStringToString]\n args {\n myMap {\n \"key\" \"example string\"\n }\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml" => "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml" => "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", @@ -64,7 +66,7 @@ module Inlined "test-files/functions/prompts/no-chat-messages.baml" => "\n\nfunction PromptTestClaude(input: string) -> string {\n client Claude\n prompt #\"\n Tell me a haiku about {{ input }}\n \"#\n}\n\n\nfunction PromptTestStreaming(input: string) -> string {\n client GPT35\n prompt #\"\n Tell me a short story about {{ input }}\n \"#\n}\n\ntest TestName {\n functions [PromptTestStreaming]\n args {\n input #\"\n hello world\n \"#\n }\n}\n", "test-files/functions/prompts/with-chat-messages.baml" => "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml" => "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", - "test-files/providers/providers.baml" => "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", + "test-files/providers/providers.baml" => "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, PromptTestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n\n", "test-files/strategies/fallback.baml" => "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", "test-files/strategies/retry.baml" => "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", "test-files/strategies/roundrobin.baml" => "", diff --git a/integ-tests/ruby/baml_client/partial-types.rb b/integ-tests/ruby/baml_client/partial-types.rb index 8e9c1c954..0419b6430 100644 --- a/integ-tests/ruby/baml_client/partial-types.rb +++ b/integ-tests/ruby/baml_client/partial-types.rb @@ -2,7 +2,7 @@ # # Welcome to Baml! To use this generated code, please run the following: # -# $ bundle add baml sorbet-runtime sorbet-struct-comparable +# $ bundle add baml sorbet-runtime # ############################################################################### @@ -14,7 +14,6 @@ # formatter:off # typed: false require "sorbet-runtime" -require "sorbet-struct-comparable" require_relative "types" @@ -57,196 +56,528 @@ class TestOutputClass < T::Struct; end class UnionTest_ReturnType < T::Struct; end class WithReasoning < T::Struct; end class Blah < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop4, T.nilable(String) + + def initialize(props) + super( + prop4: props[:prop4], + ) + + @props = props + end end class ClassOptionalOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(String) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class ClassOptionalOutput2 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(String) const :prop3, Baml::PartialTypes::Blah + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class ClassWithImage < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :myImage, T.nilable(Baml::Image) const :param2, T.nilable(String) const :fake_image, Baml::PartialTypes::FakeImage + + def initialize(props) + super( + myImage: props[:myImage], + param2: props[:param2], + fake_image: props[:fake_image], + ) + + @props = props + end end class DummyOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :nonce, T.nilable(String) const :nonce2, T.nilable(String) + + def initialize(props) + super( + nonce: props[:nonce], + nonce2: props[:nonce2], + ) + + @props = props + end end class DynInputOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :testKey, T.nilable(String) + + def initialize(props) + super( + testKey: props[:testKey], + ) + + @props = props + end end class DynamicClassOne < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct + + def initialize(props) + super( + ) + + @props = props + end end class DynamicClassTwo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :hi, T.nilable(String) const :some_class, Baml::PartialTypes::SomeClassNestedDynamic const :status, T.nilable(Baml::Types::DynEnumOne) + + def initialize(props) + super( + hi: props[:hi], + some_class: props[:some_class], + status: props[:status], + ) + + @props = props + end end class DynamicOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct + + def initialize(props) + super( + ) + + @props = props + end end class Education < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :institution, T.nilable(String) const :location, T.nilable(String) const :degree, T.nilable(String) const :major, T::Array[T.nilable(String)] const :graduation_date, T.nilable(String) + + def initialize(props) + super( + institution: props[:institution], + location: props[:location], + degree: props[:degree], + major: props[:major], + graduation_date: props[:graduation_date], + ) + + @props = props + end end class Email < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :subject, T.nilable(String) const :body, T.nilable(String) const :from_address, T.nilable(String) + + def initialize(props) + super( + subject: props[:subject], + body: props[:body], + from_address: props[:from_address], + ) + + @props = props + end end class Event < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :title, T.nilable(String) const :date, T.nilable(String) const :location, T.nilable(String) const :description, T.nilable(String) + + def initialize(props) + super( + title: props[:title], + date: props[:date], + location: props[:location], + description: props[:description], + ) + + @props = props + end end class FakeImage < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :url, T.nilable(String) + + def initialize(props) + super( + url: props[:url], + ) + + @props = props + end end class InnerClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(String) const :inner, Baml::PartialTypes::InnerClass2 + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + inner: props[:inner], + ) + + @props = props + end end class InnerClass2 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop2, T.nilable(Integer) const :prop3, T.nilable(Float) + + def initialize(props) + super( + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class NamedArgsSingleClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :key, T.nilable(String) const :key_two, T.nilable(T::Boolean) const :key_three, T.nilable(Integer) + + def initialize(props) + super( + key: props[:key], + key_two: props[:key_two], + key_three: props[:key_three], + ) + + @props = props + end end class OptionalTest_Prop1 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :omega_a, T.nilable(String) const :omega_b, T.nilable(Integer) + + def initialize(props) + super( + omega_a: props[:omega_a], + omega_b: props[:omega_b], + ) + + @props = props + end end class OptionalTest_ReturnType < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :omega_1, Baml::PartialTypes::OptionalTest_Prop1 const :omega_2, T.nilable(String) const :omega_3, T::Array[T.nilable(Baml::Types::OptionalTest_CategoryType)] + + def initialize(props) + super( + omega_1: props[:omega_1], + omega_2: props[:omega_2], + omega_3: props[:omega_3], + ) + + @props = props + end end class OrderInfo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :order_status, T.nilable(Baml::Types::OrderStatus) const :tracking_number, T.nilable(String) const :estimated_arrival_date, T.nilable(String) + + def initialize(props) + super( + order_status: props[:order_status], + tracking_number: props[:tracking_number], + estimated_arrival_date: props[:estimated_arrival_date], + ) + + @props = props + end end class Person < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, T.nilable(String) const :hair_color, T.nilable(Baml::Types::Color) + + def initialize(props) + super( + name: props[:name], + hair_color: props[:hair_color], + ) + + @props = props + end end class Quantity < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :amount, T.nilable(T.any(T.nilable(Integer), T.nilable(Float))) const :unit, T.nilable(String) + + def initialize(props) + super( + amount: props[:amount], + unit: props[:unit], + ) + + @props = props + end end class RaysData < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :dataType, T.nilable(Baml::Types::DataType) const :value, T.nilable(T.any(Baml::PartialTypes::Resume, Baml::PartialTypes::Event)) + + def initialize(props) + super( + dataType: props[:dataType], + value: props[:value], + ) + + @props = props + end end class ReceiptInfo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :items, T::Array[Baml::PartialTypes::ReceiptItem] const :total_cost, T.nilable(Float) + + def initialize(props) + super( + items: props[:items], + total_cost: props[:total_cost], + ) + + @props = props + end end class ReceiptItem < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, T.nilable(String) const :description, T.nilable(String) const :quantity, T.nilable(Integer) const :price, T.nilable(Float) + + def initialize(props) + super( + name: props[:name], + description: props[:description], + quantity: props[:quantity], + price: props[:price], + ) + + @props = props + end end class Recipe < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :ingredients, T::Hash[String, Baml::PartialTypes::Quantity] + + def initialize(props) + super( + ingredients: props[:ingredients], + ) + + @props = props + end end class Resume < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, T.nilable(String) const :email, T.nilable(String) const :phone, T.nilable(String) const :experience, T::Array[Baml::PartialTypes::Education] const :education, T::Array[T.nilable(String)] const :skills, T::Array[T.nilable(String)] + + def initialize(props) + super( + name: props[:name], + email: props[:email], + phone: props[:phone], + experience: props[:experience], + education: props[:education], + skills: props[:skills], + ) + + @props = props + end end class SearchParams < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :dateRange, T.nilable(Integer) const :location, T::Array[T.nilable(String)] const :jobTitle, Baml::PartialTypes::WithReasoning const :company, Baml::PartialTypes::WithReasoning const :description, T::Array[Baml::PartialTypes::WithReasoning] const :tags, T::Array[T.nilable(T.any(T.nilable(Baml::Types::Tag), T.nilable(String)))] + + def initialize(props) + super( + dateRange: props[:dateRange], + location: props[:location], + jobTitle: props[:jobTitle], + company: props[:company], + description: props[:description], + tags: props[:tags], + ) + + @props = props + end end class SomeClassNestedDynamic < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :hi, T.nilable(String) + + def initialize(props) + super( + hi: props[:hi], + ) + + @props = props + end end class StringToClassEntry < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :word, T.nilable(String) + + def initialize(props) + super( + word: props[:word], + ) + + @props = props + end end class TestClassAlias < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :key, T.nilable(String) const :key2, T.nilable(String) const :key3, T.nilable(String) const :key4, T.nilable(String) const :key5, T.nilable(String) + + def initialize(props) + super( + key: props[:key], + key2: props[:key2], + key3: props[:key3], + key4: props[:key4], + key5: props[:key5], + ) + + @props = props + end end class TestClassNested < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, Baml::PartialTypes::InnerClass + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class TestClassWithEnum < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(Baml::Types::EnumInClass) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class TestOutputClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(Integer) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class UnionTest_ReturnType < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(T.any(T.nilable(String), T.nilable(T::Boolean))) const :prop2, T::Array[T.nilable(T.any(T.nilable(Float), T.nilable(T::Boolean)))] const :prop3, T.nilable(T.any(T::Array[T.nilable(T::Boolean)], T::Array[T.nilable(Integer)])) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class WithReasoning < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :value, T.nilable(String) const :reasoning, T.nilable(String) + + def initialize(props) + super( + value: props[:value], + reasoning: props[:reasoning], + ) + + @props = props + end end end end \ No newline at end of file diff --git a/integ-tests/ruby/baml_client/type-registry.rb b/integ-tests/ruby/baml_client/type-registry.rb new file mode 100644 index 000000000..9894eb08b --- /dev/null +++ b/integ-tests/ruby/baml_client/type-registry.rb @@ -0,0 +1,165 @@ +############################################################################### +# +# Welcome to Baml! To use this generated code, please run the following: +# +# $ bundle add baml sorbet-runtime +# +############################################################################### + +# This file was generated by BAML: please do not edit it. Instead, edit the +# BAML files and re-generate this code. +# +# frozen_string_literal: true +# rubocop: disable +# formatter:off +require 'set' + +module Baml + class TypeBuilder + def initialize + @registry = Baml::Ffi::TypeBuilder.new + @classes = Set[ "Blah", "ClassOptionalOutput", "ClassOptionalOutput2", "ClassWithImage", "DummyOutput", "DynInputOutput", "DynamicClassOne", "DynamicClassTwo", "DynamicOutput", "Education", "Email", "Event", "FakeImage", "InnerClass", "InnerClass2", "NamedArgsSingleClass", "OptionalTest_Prop1", "OptionalTest_ReturnType", "OrderInfo", "Person", "Quantity", "RaysData", "ReceiptInfo", "ReceiptItem", "Recipe", "Resume", "SearchParams", "SomeClassNestedDynamic", "StringToClassEntry", "TestClassAlias", "TestClassNested", "TestClassWithEnum", "TestOutputClass", "UnionTest_ReturnType", "WithReasoning", ] + @enums = Set[ "Category", "Category2", "Category3", "Color", "DataType", "DynEnumOne", "DynEnumTwo", "EnumInClass", "EnumOutput", "Hobby", "NamedArgsSingleEnum", "NamedArgsSingleEnumList", "OptionalTest_CategoryType", "OrderStatus", "Tag", "TestEnum", ] + end + + def string + @registry.string + end + + def int + @registry.int + end + + def float + @registry.float + end + + def bool + @registry.bool + end + + def list(inner_type) + @registry.list(inner_type) + end + + def null + @registry.null + end + + def map(key_type, value_type) + @registry.map(key_type, value_type) + end + + def union(*types) + @registry.union(*types) + end + + def add_class(name) + if @classes.include?(name) + raise "Class with name #{name} already exists." + end + if @enums.include?(name) + raise "Enum with name #{name} already exists." + end + @classes.add(name) + ClassBuilder.new(@registry, name) + end + + def add_enum(name) + if @classes.include?(name) + raise "Class with name #{name} already exists." + end + if @enums.include?(name) + raise "Enum with name #{name} already exists." + end + @enums.add(name) + EnumBuilder.new(@registry, name) + end + + class ClassBuilder + def initialize(registry, name, properties = nil) + @builder = registry.class_(name) + @properties = properties == nil ? Set.new : properties + end + + def type + @builder.field + end + + def add_property(name, type) + if @properties.include?(name) + raise "Property #{name} already exists." + end + @properties.add(name) + @builder.property(name).type(type) + end + end + + class EnumBuilder + def initialize(registry, name, values = nil) + @builder = registry.enum(name) + @values = values == nil ? Set.new : values + end + + def type + @builder.field + end + + def add_value(name) + if @values.include?(name) + raise "Value #{name} already exists." + end + @values.add(name) + @builder.value(name) + end + end + + + def DummyOutput + ClassBuilder.new(@registry, "DummyOutput", Set[ "nonce", "nonce2", ]) + end + + def DynInputOutput + ClassBuilder.new(@registry, "DynInputOutput", Set[ "testKey", ]) + end + + def DynamicClassOne + ClassBuilder.new(@registry, "DynamicClassOne", Set[]) + end + + def DynamicClassTwo + ClassBuilder.new(@registry, "DynamicClassTwo", Set[ "hi", "some_class", "status", ]) + end + + def DynamicOutput + ClassBuilder.new(@registry, "DynamicOutput", Set[]) + end + + def Person + ClassBuilder.new(@registry, "Person", Set[ "name", "hair_color", ]) + end + + def SomeClassNestedDynamic + ClassBuilder.new(@registry, "SomeClassNestedDynamic", Set[ "hi", ]) + end + + + + def Color + EnumBuilder.new(@registry, "Color", Set[ "RED", "BLUE", "GREEN", "YELLOW", "BLACK", "WHITE", ]) + end + + def DynEnumOne + EnumBuilder.new(@registry, "DynEnumOne", Set[]) + end + + def DynEnumTwo + EnumBuilder.new(@registry, "DynEnumTwo", Set[]) + end + + def Hobby + EnumBuilder.new(@registry, "Hobby", Set[ "SPORTS", "MUSIC", "READING", ]) + end + + end +end \ No newline at end of file diff --git a/integ-tests/ruby/baml_client/types.rb b/integ-tests/ruby/baml_client/types.rb index 537b3ccbe..fe91917b1 100644 --- a/integ-tests/ruby/baml_client/types.rb +++ b/integ-tests/ruby/baml_client/types.rb @@ -2,7 +2,7 @@ # # Welcome to Baml! To use this generated code, please run the following: # -# $ bundle add baml sorbet-runtime sorbet-struct-comparable +# $ bundle add baml sorbet-runtime # ############################################################################### @@ -14,7 +14,6 @@ # formatter:off # typed: false require "sorbet-runtime" -require "sorbet-struct-comparable" module Baml @@ -167,196 +166,528 @@ class TestOutputClass < T::Struct; end class UnionTest_ReturnType < T::Struct; end class WithReasoning < T::Struct; end class Blah < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop4, T.nilable(String) + + def initialize(props) + super( + prop4: props[:prop4], + ) + + @props = props + end end class ClassOptionalOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, String const :prop2, String + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class ClassOptionalOutput2 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.nilable(String) const :prop2, T.nilable(String) const :prop3, T.nilable(Baml::Types::Blah) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class ClassWithImage < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :myImage, Baml::Image const :param2, String const :fake_image, Baml::Types::FakeImage + + def initialize(props) + super( + myImage: props[:myImage], + param2: props[:param2], + fake_image: props[:fake_image], + ) + + @props = props + end end class DummyOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :nonce, String const :nonce2, String + + def initialize(props) + super( + nonce: props[:nonce], + nonce2: props[:nonce2], + ) + + @props = props + end end class DynInputOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :testKey, String + + def initialize(props) + super( + testKey: props[:testKey], + ) + + @props = props + end end class DynamicClassOne < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct + + def initialize(props) + super( + ) + + @props = props + end end class DynamicClassTwo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :hi, String const :some_class, Baml::Types::SomeClassNestedDynamic const :status, Baml::Types::DynEnumOne + + def initialize(props) + super( + hi: props[:hi], + some_class: props[:some_class], + status: props[:status], + ) + + @props = props + end end class DynamicOutput < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct + + def initialize(props) + super( + ) + + @props = props + end end class Education < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :institution, String const :location, String const :degree, String const :major, T::Array[String] const :graduation_date, T.nilable(String) + + def initialize(props) + super( + institution: props[:institution], + location: props[:location], + degree: props[:degree], + major: props[:major], + graduation_date: props[:graduation_date], + ) + + @props = props + end end class Email < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :subject, String const :body, String const :from_address, String + + def initialize(props) + super( + subject: props[:subject], + body: props[:body], + from_address: props[:from_address], + ) + + @props = props + end end class Event < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :title, String const :date, String const :location, String const :description, String + + def initialize(props) + super( + title: props[:title], + date: props[:date], + location: props[:location], + description: props[:description], + ) + + @props = props + end end class FakeImage < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :url, String + + def initialize(props) + super( + url: props[:url], + ) + + @props = props + end end class InnerClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, String const :prop2, String const :inner, Baml::Types::InnerClass2 + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + inner: props[:inner], + ) + + @props = props + end end class InnerClass2 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop2, Integer const :prop3, Float + + def initialize(props) + super( + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class NamedArgsSingleClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :key, String const :key_two, T::Boolean const :key_three, Integer + + def initialize(props) + super( + key: props[:key], + key_two: props[:key_two], + key_three: props[:key_three], + ) + + @props = props + end end class OptionalTest_Prop1 < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :omega_a, String const :omega_b, Integer + + def initialize(props) + super( + omega_a: props[:omega_a], + omega_b: props[:omega_b], + ) + + @props = props + end end class OptionalTest_ReturnType < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :omega_1, T.nilable(Baml::Types::OptionalTest_Prop1) const :omega_2, T.nilable(String) const :omega_3, T::Array[T.nilable(Baml::Types::OptionalTest_CategoryType)] + + def initialize(props) + super( + omega_1: props[:omega_1], + omega_2: props[:omega_2], + omega_3: props[:omega_3], + ) + + @props = props + end end class OrderInfo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :order_status, Baml::Types::OrderStatus const :tracking_number, T.nilable(String) const :estimated_arrival_date, T.nilable(String) + + def initialize(props) + super( + order_status: props[:order_status], + tracking_number: props[:tracking_number], + estimated_arrival_date: props[:estimated_arrival_date], + ) + + @props = props + end end class Person < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, T.nilable(String) const :hair_color, T.nilable(Baml::Types::Color) + + def initialize(props) + super( + name: props[:name], + hair_color: props[:hair_color], + ) + + @props = props + end end class Quantity < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :amount, T.any(Integer, Float) const :unit, T.nilable(String) + + def initialize(props) + super( + amount: props[:amount], + unit: props[:unit], + ) + + @props = props + end end class RaysData < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :dataType, Baml::Types::DataType const :value, T.any(Baml::Types::Resume, Baml::Types::Event) + + def initialize(props) + super( + dataType: props[:dataType], + value: props[:value], + ) + + @props = props + end end class ReceiptInfo < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :items, T::Array[Baml::Types::ReceiptItem] const :total_cost, T.nilable(Float) + + def initialize(props) + super( + items: props[:items], + total_cost: props[:total_cost], + ) + + @props = props + end end class ReceiptItem < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, String const :description, T.nilable(String) const :quantity, Integer const :price, Float + + def initialize(props) + super( + name: props[:name], + description: props[:description], + quantity: props[:quantity], + price: props[:price], + ) + + @props = props + end end class Recipe < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :ingredients, T::Hash[String, Baml::Types::Quantity] + + def initialize(props) + super( + ingredients: props[:ingredients], + ) + + @props = props + end end class Resume < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :name, String const :email, String const :phone, String const :experience, T::Array[Baml::Types::Education] const :education, T::Array[String] const :skills, T::Array[String] + + def initialize(props) + super( + name: props[:name], + email: props[:email], + phone: props[:phone], + experience: props[:experience], + education: props[:education], + skills: props[:skills], + ) + + @props = props + end end class SearchParams < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :dateRange, T.nilable(Integer) const :location, T::Array[String] const :jobTitle, T.nilable(Baml::Types::WithReasoning) const :company, T.nilable(Baml::Types::WithReasoning) const :description, T::Array[Baml::Types::WithReasoning] const :tags, T::Array[T.any(Baml::Types::Tag, String)] + + def initialize(props) + super( + dateRange: props[:dateRange], + location: props[:location], + jobTitle: props[:jobTitle], + company: props[:company], + description: props[:description], + tags: props[:tags], + ) + + @props = props + end end class SomeClassNestedDynamic < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :hi, String + + def initialize(props) + super( + hi: props[:hi], + ) + + @props = props + end end class StringToClassEntry < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :word, String + + def initialize(props) + super( + word: props[:word], + ) + + @props = props + end end class TestClassAlias < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :key, String const :key2, String const :key3, String const :key4, String const :key5, String + + def initialize(props) + super( + key: props[:key], + key2: props[:key2], + key3: props[:key3], + key4: props[:key4], + key5: props[:key5], + ) + + @props = props + end end class TestClassNested < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, String const :prop2, Baml::Types::InnerClass + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class TestClassWithEnum < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, String const :prop2, Baml::Types::EnumInClass + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class TestOutputClass < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, String const :prop2, Integer + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + ) + + @props = props + end end class UnionTest_ReturnType < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :prop1, T.any(String, T::Boolean) const :prop2, T::Array[T.any(Float, T::Boolean)] const :prop3, T.any(T::Array[T::Boolean], T::Array[Integer]) + + def initialize(props) + super( + prop1: props[:prop1], + prop2: props[:prop2], + prop3: props[:prop3], + ) + + @props = props + end end class WithReasoning < T::Struct - include T::Struct::ActsAsComparable + include Baml::Sorbet::Struct const :value, String const :reasoning, String + + def initialize(props) + super( + value: props[:value], + reasoning: props[:reasoning], + ) + + @props = props + end end end end \ No newline at end of file diff --git a/integ-tests/ruby/test_filtered.rb b/integ-tests/ruby/test_filtered.rb new file mode 100644 index 000000000..203ce9652 --- /dev/null +++ b/integ-tests/ruby/test_filtered.rb @@ -0,0 +1,12 @@ +require 'json' +require 'minitest/autorun' +require 'minitest/reporters' + +require_relative "baml_client/client" + + +b = Baml.Client + +describe "ruby<->baml integration tests (filtered)" do + +end \ No newline at end of file diff --git a/integ-tests/ruby/test_functions.rb b/integ-tests/ruby/test_functions.rb index 1ff8c7fba..784c77953 100644 --- a/integ-tests/ruby/test_functions.rb +++ b/integ-tests/ruby/test_functions.rb @@ -1,3 +1,4 @@ +require 'json' require 'minitest/autorun' require 'minitest/reporters' @@ -86,12 +87,19 @@ refute_nil myEnum end - #it "should work with image" do - # res = b.TestImageInput( - # img: Baml::Image.from_url("https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png") - # ) - # assert_includes res.downcase, "green" - #end + it "should work with image" do + res = b.TestImageInput( + img: Baml::Image.from_url("https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png") + ) + assert_includes res.downcase, "green" + end + + it "should work with audio" do + # from URL + res = b.AudioInput( + aud: Baml::Audio.from_url("https://actions.google.com/sounds/v1/emergency/beeper_emergency_call.ogg") + ) + end it "works with unions" do res = b.UnionTest_Function(input: "a") @@ -169,4 +177,114 @@ assert msgs.size > 0, "Expected at least one streamed response but got none." assert msgs.last == final, "Expected last stream message to match final response." end + + it "tests dynamic" do + t = Baml::TypeBuilder.new + t.Person.add_property("last_name", t.string.list) + t.Person.add_property("height", t.float.optional).description("Height in meters") + + t.Hobby.add_value("chess") + # TODO: figure out a non-naive impl of #list_values in Ruby + # t.Hobby.list_values.each do |name, val| + # val.alias(name.downcase) + # end + + t.Person.add_property("hobbies", t.Hobby.type.list).description( + "Some suggested hobbies they might be good at" + ) + + t_res = b.ExtractPeople( + text: "My name is Harrison. My hair is black and I'm 6 feet tall. I'm pretty good on a chessboard.", + baml_options: {tb: t} + ) + + refute_empty(t_res, "Expected non-empty result but got empty.") + + t_res.each do |r| + puts r.inspect + assert_kind_of(Float, r['height']) + assert_kind_of(Float, r[:height]) + end + end + + it "tests dynamic class output" do + t = Baml::TypeBuilder.new + t.DynamicOutput.add_property("hair_color", t.string) + # TODO: figure out a non-naive impl of #list_properties in Ruby + # puts t.DynamicOutput.list_properties + # t.DynamicOutput.list_properties.each do |prop| + # puts "Property: #{prop}" + # end + + output = b.MyFunc( + input: "My name is Harrison. My hair is black and I'm 6 feet tall.", + baml_options: {tb: t} + ) + puts output.inspect + assert_equal("black", output.hair_color) + end + + it "tests dynamic class nested output no stream" do + t = Baml::TypeBuilder.new + nested_class = t.add_class("Name") + nested_class.add_property("first_name", t.string) + nested_class.add_property("last_name", t.string.optional) + nested_class.add_property("middle_name", t.string.optional) + + other_nested_class = t.add_class("Address") + + t.DynamicOutput.add_property("name", nested_class.type.optional) + t.DynamicOutput.add_property("address", other_nested_class.type.optional) + t.DynamicOutput.add_property("hair_color", t.string).alias("hairColor") + t.DynamicOutput.add_property("height", t.float.optional) + + output = b.MyFunc( + input: "My name is Mark Gonzalez. My hair is black and I'm 6 feet tall.", + baml_options: {tb: t} + ) + puts output.inspect + assert_equal( + '{"name":{"first_name":"Mark","last_name":"Gonzalez","middle_name":null},"address":null,"hair_color":"black","height":6.0}', + output.to_json + ) + end + + it "tests dynamic class nested output stream" do + t = Baml::TypeBuilder.new + nested_class = t.add_class("Name") + nested_class.add_property("first_name", t.string) + nested_class.add_property("last_name", t.string.optional) + + t.DynamicOutput.add_property("name", nested_class.type.optional) + t.DynamicOutput.add_property("hair_color", t.string) + + stream = b.stream.MyFunc( + input: "My name is Mark Gonzalez. My hair is black and I'm 6 feet tall.", + baml_options: {tb: t} + ) + msgs = [] + stream.each do |msg| + puts "streamed #{msg}" + puts "streamed #{msg.model_dump}" + msgs << msg + end + output = stream.get_final_response + + puts output.inspect + assert_equal( + '{"name":{"first_name":"Mark","last_name":"Gonzalez"},"hair_color":"black"}', + output.to_json + ) + end + + it "tests dynamic clients" do + cb = Baml::Ffi::ClientRegistry.new + cb.add_llm_client("MyClient", "openai", { model: "gpt-3.5-turbo" }) + cb.set_primary("MyClient") + + capitol = b.ExpectFailure( + baml_options: { client_registry: cb } + ) + assert_match(/london/, capitol.downcase) + end end diff --git a/integ-tests/ruby/tracing-demo1.rb b/integ-tests/ruby/tracing-demo1.rb new file mode 100644 index 000000000..1244bc24f --- /dev/null +++ b/integ-tests/ruby/tracing-demo1.rb @@ -0,0 +1,117 @@ +# see notes in https://www.notion.so/gloochat/Ruby-tracing-8a8ec84e52364fa785e2b379ec4f8194?pvs=4 + +module Baml + module Tracing1 + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def trace + @trace_next_method = true + end + + def method_added(method_name) + super + return unless @trace_next_method + + @trace_next_method = false + original_method = instance_method(method_name) + + define_method(method_name) do |*args, &block| + start_time = Time.now + result = original_method.bind(self).call(*args, &block) + end_time = Time.now + + duration = (end_time - start_time) * 1000 # Convert to milliseconds + puts "Method #{method_name} took #{duration.round(2)}ms to execute" + + result + end + end + end + end +end + +class MyController1 + include Baml::Tracing1 + + def show + puts "show" + end + + private + + trace + def authorize_user + puts "authorize_user" + end + + trace + def find_post + puts "find_post" + end +end + +c = MyController1.new +c.show +c.authorize_user +c.find_post + +module Baml + module Tracing2 + def self.included(base) + base.extend(ClassMethods) + end + + module ClassMethods + def trace(*method_names) + method_names.each do |method_name| + original_method = instance_method(method_name) + define_method(method_name) do |*args, &block| + start_time = Time.now + result = original_method.bind(self).call(*args, &block) + end_time = Time.now + + duration = (end_time - start_time) * 1000 # Convert to milliseconds + + log_trace(method_name, duration) + + result + end + end + end + end + + private + + def log_trace(method_name, duration) + puts "[TRACE] #{self.class}##{method_name} - #{duration.round(2)}ms" + end + end +end + +class MyController2 + include Baml::Tracing2 + + def show + puts "show" + end + + private + + trace + def authorize_user + puts "authorize_user" + end + + trace + def find_post + puts "find_post" + end +end + +c = MyController1.new +c.show +c.authorize_user +c.find_post \ No newline at end of file diff --git a/integ-tests/typescript/baml_client/async_client.ts b/integ-tests/typescript/baml_client/async_client.ts index 7c6fb8793..d6da99020 100644 --- a/integ-tests/typescript/baml_client/async_client.ts +++ b/integ-tests/typescript/baml_client/async_client.ts @@ -15,7 +15,7 @@ $ pnpm add @boundaryml/baml // @ts-nocheck // biome-ignore format: autogenerated code /* eslint-disable */ -import { BamlRuntime, FunctionResult, BamlCtxManager, BamlStream, Image, ClientBuilder } from "@boundaryml/baml" +import { BamlRuntime, FunctionResult, BamlCtxManager, BamlStream, Image, ClientRegistry } from "@boundaryml/baml" import {Blah, ClassOptionalOutput, ClassOptionalOutput2, ClassWithImage, DummyOutput, DynInputOutput, DynamicClassOne, DynamicClassTwo, DynamicOutput, Education, Email, Event, FakeImage, InnerClass, InnerClass2, NamedArgsSingleClass, OptionalTest_Prop1, OptionalTest_ReturnType, OrderInfo, Person, Quantity, RaysData, ReceiptInfo, ReceiptItem, Recipe, Resume, SearchParams, SomeClassNestedDynamic, StringToClassEntry, TestClassAlias, TestClassNested, TestClassWithEnum, TestOutputClass, UnionTest_ReturnType, WithReasoning, Category, Category2, Category3, Color, DataType, DynEnumOne, DynEnumTwo, EnumInClass, EnumOutput, Hobby, NamedArgsSingleEnum, NamedArgsSingleEnumList, OptionalTest_CategoryType, OrderStatus, Tag, TestEnum} from "./types" import TypeBuilder from "./type_builder" import { DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME } from "./globals" @@ -53,7 +53,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Recipe } @@ -69,7 +69,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -85,7 +85,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -101,7 +101,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -117,7 +117,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -133,7 +133,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -149,7 +149,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -165,7 +165,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -181,7 +181,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -197,7 +197,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DummyOutput } @@ -213,7 +213,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynamicClassTwo } @@ -229,7 +229,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynInputOutput } @@ -245,11 +245,27 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynInputOutput[] } + async ExpectFailure( + + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): Promise { + const raw = await this.runtime.callFunction( + "ExpectFailure", + { + + }, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, + ) + return raw.parsed() as string + } + async ExtractNames( input: string, __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } @@ -261,7 +277,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string[] } @@ -277,7 +293,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Person[] } @@ -293,7 +309,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ReceiptInfo } @@ -309,7 +325,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Resume } @@ -325,7 +341,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Resume } @@ -341,7 +357,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ClassOptionalOutput | null } @@ -357,7 +373,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ClassOptionalOutput2 | null } @@ -373,7 +389,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as EnumOutput[] } @@ -389,7 +405,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as EnumOutput } @@ -405,7 +421,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -421,7 +437,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as boolean } @@ -437,7 +453,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestOutputClass } @@ -453,7 +469,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestOutputClass[] } @@ -469,7 +485,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassNested } @@ -485,7 +501,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassWithEnum } @@ -501,7 +517,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string[] } @@ -517,7 +533,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestEnum } @@ -533,7 +549,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassAlias } @@ -549,7 +565,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -565,7 +581,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as RaysData } @@ -581,7 +597,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as OrderInfo } @@ -597,7 +613,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as SearchParams } @@ -613,7 +629,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynamicOutput } @@ -629,7 +645,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as (OptionalTest_ReturnType | null)[] } @@ -645,7 +661,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -661,7 +677,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -677,7 +693,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -693,7 +709,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -709,7 +725,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -725,7 +741,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -741,7 +757,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -757,7 +773,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -773,7 +789,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -789,7 +805,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -805,7 +821,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -821,7 +837,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -837,7 +853,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -853,7 +869,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -869,7 +885,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -885,7 +901,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -901,7 +917,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record } @@ -917,7 +933,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record> } @@ -933,7 +949,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record } @@ -949,7 +965,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -965,7 +981,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -981,7 +997,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -997,7 +1013,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1013,7 +1029,23 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, + ) + return raw.parsed() as string + } + + async TestImageListInput( + imgs: Image[], + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): Promise { + const raw = await this.runtime.callFunction( + "TestImageListInput", + { + "imgs": imgs + }, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1029,7 +1061,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1045,7 +1077,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1061,7 +1093,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1077,7 +1109,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1093,7 +1125,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1109,7 +1141,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1125,7 +1157,7 @@ export class BamlAsyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as UnionTest_ReturnType } @@ -1148,7 +1180,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Recipe>( raw, @@ -1171,7 +1203,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1194,7 +1226,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Category>( raw, @@ -1217,7 +1249,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Category>( raw, @@ -1240,7 +1272,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Category>( raw, @@ -1263,7 +1295,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1286,7 +1318,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1309,7 +1341,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1332,7 +1364,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1355,7 +1387,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, DummyOutput>( raw, @@ -1378,7 +1410,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, DynamicClassTwo>( raw, @@ -1401,7 +1433,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, DynInputOutput>( raw, @@ -1424,7 +1456,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, DynInputOutput[]>( raw, @@ -1435,6 +1467,29 @@ class BamlStreamClient { ) } + ExpectFailure( + + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): BamlStream, string> { + const raw = this.runtime.streamFunction( + "ExpectFailure", + { + + }, + undefined, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, + ) + return new BamlStream, string>( + raw, + (a): a is RecursivePartialNull => a, + (a): a is string => a, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + ) + } + ExtractNames( input: string, __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } @@ -1447,7 +1502,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string[]>( raw, @@ -1470,7 +1525,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Person[]>( raw, @@ -1493,7 +1548,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, ReceiptInfo>( raw, @@ -1516,7 +1571,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Resume>( raw, @@ -1539,7 +1594,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, Resume>( raw, @@ -1562,7 +1617,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, ClassOptionalOutput | null>( raw, @@ -1585,7 +1640,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, ClassOptionalOutput2 | null>( raw, @@ -1608,7 +1663,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, EnumOutput[]>( raw, @@ -1631,7 +1686,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, EnumOutput>( raw, @@ -1654,7 +1709,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1677,7 +1732,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, boolean>( raw, @@ -1700,7 +1755,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestOutputClass>( raw, @@ -1723,7 +1778,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestOutputClass[]>( raw, @@ -1746,7 +1801,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestClassNested>( raw, @@ -1769,7 +1824,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestClassWithEnum>( raw, @@ -1792,7 +1847,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string[]>( raw, @@ -1815,7 +1870,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestEnum>( raw, @@ -1838,7 +1893,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, TestClassAlias>( raw, @@ -1861,7 +1916,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -1884,7 +1939,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, RaysData>( raw, @@ -1907,7 +1962,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, OrderInfo>( raw, @@ -1930,7 +1985,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, SearchParams>( raw, @@ -1953,7 +2008,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, DynamicOutput>( raw, @@ -1976,7 +2031,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, (OptionalTest_ReturnType | null)[]>( raw, @@ -1999,7 +2054,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2022,7 +2077,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2045,7 +2100,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2068,7 +2123,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2091,7 +2146,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2114,7 +2169,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2137,7 +2192,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2160,7 +2215,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2183,7 +2238,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2206,7 +2261,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2229,7 +2284,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2252,7 +2307,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2275,7 +2330,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2298,7 +2353,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2321,7 +2376,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2344,7 +2399,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2367,7 +2422,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream>, Record>( raw, @@ -2390,7 +2445,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream>>, Record>>( raw, @@ -2413,7 +2468,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream>, Record>( raw, @@ -2436,7 +2491,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2459,7 +2514,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2482,7 +2537,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2505,7 +2560,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2528,7 +2583,30 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, + ) + return new BamlStream, string>( + raw, + (a): a is RecursivePartialNull => a, + (a): a is string => a, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + ) + } + + TestImageListInput( + imgs: Image[], + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): BamlStream, string> { + const raw = this.runtime.streamFunction( + "TestImageListInput", + { + "imgs": imgs + }, + undefined, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2551,7 +2629,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2574,7 +2652,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2597,7 +2675,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2620,7 +2698,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2643,7 +2721,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2666,7 +2744,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, string>( raw, @@ -2689,7 +2767,7 @@ class BamlStreamClient { undefined, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return new BamlStream, UnionTest_ReturnType>( raw, diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index 63de037d6..55ea8c997 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -25,10 +25,11 @@ const fileMap = { "fiddle-examples/extract-receipt-info.baml": "class ReceiptItem {\n name string\n description string?\n quantity int\n price float\n}\n\nclass ReceiptInfo {\n items ReceiptItem[]\n total_cost float?\n}\n\nfunction ExtractReceiptInfo(email: string) -> ReceiptInfo {\n client GPT4o\n prompt #\"\n Given the receipt below:\n\n ```\n {{email}}\n ```\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "fiddle-examples/images/image.baml": "function DescribeImage(img: image) -> string {\n client AwsBedrock\n prompt #\"\n {{ _.role(\"user\") }}\n\n\n Describe the image below in 20 words:\n {{ img }}\n \"#\n\n}\n\nclass FakeImage {\n url string\n}\n\nclass ClassWithImage {\n myImage image\n param2 string\n fake_image FakeImage\n}\n\n// chat role user present\nfunction DescribeImage2(classWithImage: ClassWithImage, img2: image) -> string { \n client GPT4Turbo\n prompt #\"\n {{ _.role(\"user\") }}\n You should return 2 answers that answer the following commands.\n\n 1. Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n 2. Also tell me what's happening here in one sentence:\n {{ img2 }}\n \"#\n}\n\n// no chat role\nfunction DescribeImage3(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\n\n// system prompt and chat prompt\nfunction DescribeImage4(classWithImage: ClassWithImage, img2: image) -> string {\n client GPT4Turbo\n prompt #\"\n {{ _.role(\"system\")}}\n\n Describe this in 5 words:\n {{ classWithImage.myImage }}\n\n Tell me also what's happening here in one sentence and relate it to the word {{ classWithImage.param2 }}:\n {{ img2 }}\n \"#\n}\n\ntest TestName {\n functions [DescribeImage]\n args {\n img { url \"https://imgs.xkcd.com/comics/standards.png\"}\n }\n}\n", "fiddle-examples/symbol-tuning.baml": "enum Category3 {\n Refund @alias(\"k1\")\n @description(\"Customer wants to refund a product\")\n\n CancelOrder @alias(\"k2\")\n @description(\"Customer wants to cancel an order\")\n\n TechnicalSupport @alias(\"k3\")\n @description(\"Customer needs help with a technical issue unrelated to account creation or login\")\n\n AccountIssue @alias(\"k4\")\n @description(\"Specifically relates to account-login or account-creation\")\n\n Question @alias(\"k5\")\n @description(\"Customer has a question\")\n}\n\nfunction ClassifyMessage3(input: string) -> Category {\n client GPT4\n\n prompt #\"\n Classify the following INPUT into ONE\n of the following categories:\n\n INPUT: {{ input }}\n\n {{ ctx.output_format }}\n\n Response:\n \"#\n}", - "main.baml": "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.51.0\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.51.0\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.51.0\"\n}\n", + "main.baml": "generator lang_python {\n output_type python/pydantic\n output_dir \"../python\"\n version \"0.52.1\"\n}\n\ngenerator lang_typescript {\n output_type typescript\n output_dir \"../typescript\"\n version \"0.52.1\"\n}\n\ngenerator lang_ruby {\n output_type ruby/sorbet\n output_dir \"../ruby\"\n version \"0.52.1\"\n}\n", "test-files/aliases/classes.baml": "class TestClassAlias {\n key string @alias(\"key-dash\") @description(#\"\n This is a description for key\n af asdf\n \"#)\n key2 string @alias(\"key21\")\n key3 string @alias(\"key with space\")\n key4 string //unaliased\n key5 string @alias(\"key.with.punctuation/123\")\n}\n\nfunction FnTestClassAlias(input: string) -> TestClassAlias {\n client GPT35\n prompt #\"\n {{ctx.output_format}}\n \"#\n}\n\ntest FnTestClassAlias {\n functions [FnTestClassAlias]\n args {\n input \"example input\"\n }\n}\n", "test-files/aliases/enums.baml": "enum TestEnum {\n A @alias(\"k1\") @description(#\"\n User is angry\n \"#)\n B @alias(\"k22\") @description(#\"\n User is happy\n \"#)\n // tests whether k1 doesnt incorrectly get matched with k11\n C @alias(\"k11\") @description(#\"\n User is sad\n \"#)\n D @alias(\"k44\") @description(\n User is confused\n )\n E @description(\n User is excited\n )\n F @alias(\"k5\") // only alias\n \n G @alias(\"k6\") @description(#\"\n User is bored\n With a long description\n \"#)\n \n @@alias(\"Category\")\n}\n\nfunction FnTestAliasedEnumOutput(input: string) -> TestEnum {\n client GPT35\n prompt #\"\n Classify the user input into the following category\n \n {{ ctx.output_format }}\n\n {{ _.role('user') }}\n {{input}}\n\n {{ _.role('assistant') }}\n Category ID:\n \"#\n}\n\ntest FnTestAliasedEnumOutput {\n functions [FnTestAliasedEnumOutput]\n args {\n input \"mehhhhh\"\n }\n}", "test-files/comments/comments.baml": "// add some functions, classes, enums etc with comments all over.", + "test-files/dynamic/client-registry.baml": "// Intentionally use a bad key\nclient BadClient {\n provider openai\n options {\n model \"gpt-3.5-turbo\"\n api_key \"sk-invalid\"\n }\n}\n\nfunction ExpectFailure() -> string {\n client BadClient\n\n prompt #\"\n What is the capital of England?\n \"#\n}\n", "test-files/dynamic/dynamic.baml": "class DynamicClassOne {\n @@dynamic\n}\n\nenum DynEnumOne {\n @@dynamic\n}\n\nenum DynEnumTwo {\n @@dynamic\n}\n\nclass SomeClassNestedDynamic {\n hi string\n @@dynamic\n\n}\n\nclass DynamicClassTwo {\n hi string\n some_class SomeClassNestedDynamic\n status DynEnumOne\n @@dynamic\n}\n\nfunction DynamicFunc(input: DynamicClassOne) -> DynamicClassTwo {\n client GPT35\n prompt #\"\n Please extract the schema from \n {{ input }}\n\n {{ ctx.output_format }}\n \"#\n}\n\nclass DynInputOutput {\n testKey string\n @@dynamic\n}\n\nfunction DynamicInputOutput(input: DynInputOutput) -> DynInputOutput {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\nfunction DynamicListInputOutput(input: DynInputOutput[]) -> DynInputOutput[] {\n client GPT35\n prompt #\"\n Here is some input data:\n ----\n {{ input }}\n ----\n\n Extract the information.\n {{ ctx.output_format }}\n \"#\n}\n\n\n\nclass DynamicOutput {\n @@dynamic\n}\n \nfunction MyFunc(input: string) -> DynamicOutput {\n client GPT35\n prompt #\"\n Given a string, extract info using the schema:\n\n {{ input}}\n\n {{ ctx.output_format }}\n \"#\n}\n\n", "test-files/functions/input/named-args/single/named-audio.baml": "function AudioInput(aud: audio) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Does this sound like a roar? Yes or no? One word no other characters.\n \n {{ aud }}\n \"#\n}\n\n\ntest TestURLAudioInput{\n functions [AudioInput]\n args {\n aud{ \n url https://actions.google.com/sounds/v1/emergency/beeper_emergency_call.ogg\n }\n } \n}\n\n\n", "test-files/functions/input/named-args/single/named-boolean.baml": "\n\nfunction TestFnNamedArgsSingleBool(myBool: bool) -> string{\n client Vertex\n prompt #\"\n Return this value back to me: {{myBool}}\n \"#\n}\n\ntest TestFnNamedArgsSingleBool {\n functions [TestFnNamedArgsSingleBool]\n args {\n myBool true\n }\n}", @@ -37,10 +38,11 @@ const fileMap = { "test-files/functions/input/named-args/single/named-enum-list.baml": "enum NamedArgsSingleEnumList {\n ONE\n TWO\n}\n\nfunction TestFnNamedArgsSingleEnumList(myArg: NamedArgsSingleEnumList[]) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest TestFnNamedArgsSingleEnumList {\n functions [TestFnNamedArgsSingleEnumList]\n args {\n myArg [ONE, TWO]\n }\n}", "test-files/functions/input/named-args/single/named-enum.baml": "enum NamedArgsSingleEnum {\n ONE\n TWO\n}\n\nfunction FnTestNamedArgsSingleEnum(myArg: NamedArgsSingleEnum) -> string {\n client GPT35\n prompt #\"\n Print these values back to me:\n {{myArg}}\n \"#\n}\n\ntest FnTestNamedArgsSingleEnum {\n functions [FnTestNamedArgsSingleEnum]\n args {\n myArg ONE\n }\n}", "test-files/functions/input/named-args/single/named-float.baml": "function TestFnNamedArgsSingleFloat(myFloat: float) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myFloat}}\n \"#\n}\n\ntest TestFnNamedArgsSingleFloat {\n functions [TestFnNamedArgsSingleFloat]\n args {\n myFloat 3.14\n }\n}\n", + "test-files/functions/input/named-args/single/named-image-list.baml": "function TestImageListInput(imgs: image[]) -> string{\n client GPT4o\n prompt #\"\n {{ _.role(\"user\") }}\n\n What colors do these have in common? {{imgs}}\n \"#\n}\n\ntest TestImageListInput {\n functions [TestImageListInput]\n args {\n imgs [\n {\n media_type \"image/png\"\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n },\n {\n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n ]\n }\n}\n", "test-files/functions/input/named-args/single/named-image.baml": "function TestImageInput(img: image) -> string{\n client Gemini\n prompt #\"\n {{ _.role(\"user\") }}\n\n Describe this in 4 words. One word must be the color {{img}}\n \"#\n}\n\ntest TestImageInput {\n functions [TestImageInput]\n args {\n img {\n media_type \"image/png\"\n // url gs://cloud-samples-data/vertex-ai/llm/prompts/landmark1.png\n\n url \"https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png\"\n }\n }\n}\n\ntest shrek {\n functions [TestImageInput]\n args {\n img {\n \n url \"https://upload.wikimedia.org/wikipedia/en/4/4d/Shrek_%28character%29.png\"\n }\n }\n}\n\n\n\n// double check this before adding it. Probably n ot right.\n// function TestImageInputAnthropic(img: image) -> string{\n// client GPT4o\n// prompt #\"\n// {{ _.role(\"user\") }}\n\n// Describe this in 4 words {{img}}\n// \"#\n// }\n\n// test TestImageInputAnthropic {\n// functions [TestImageInputAnthropic]\n// args {\n// img {\n// base64 iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAApgAAAKYB3X3/OAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANCSURBVEiJtZZPbBtFFMZ/M7ubXdtdb1xSFyeilBapySVU8h8OoFaooFSqiihIVIpQBKci6KEg9Q6H9kovIHoCIVQJJCKE1ENFjnAgcaSGC6rEnxBwA04Tx43t2FnvDAfjkNibxgHxnWb2e/u992bee7tCa00YFsffekFY+nUzFtjW0LrvjRXrCDIAaPLlW0nHL0SsZtVoaF98mLrx3pdhOqLtYPHChahZcYYO7KvPFxvRl5XPp1sN3adWiD1ZAqD6XYK1b/dvE5IWryTt2udLFedwc1+9kLp+vbbpoDh+6TklxBeAi9TL0taeWpdmZzQDry0AcO+jQ12RyohqqoYoo8RDwJrU+qXkjWtfi8Xxt58BdQuwQs9qC/afLwCw8tnQbqYAPsgxE1S6F3EAIXux2oQFKm0ihMsOF71dHYx+f3NND68ghCu1YIoePPQN1pGRABkJ6Bus96CutRZMydTl+TvuiRW1m3n0eDl0vRPcEysqdXn+jsQPsrHMquGeXEaY4Yk4wxWcY5V/9scqOMOVUFthatyTy8QyqwZ+kDURKoMWxNKr2EeqVKcTNOajqKoBgOE28U4tdQl5p5bwCw7BWquaZSzAPlwjlithJtp3pTImSqQRrb2Z8PHGigD4RZuNX6JYj6wj7O4TFLbCO/Mn/m8R+h6rYSUb3ekokRY6f/YukArN979jcW+V/S8g0eT/N3VN3kTqWbQ428m9/8k0P/1aIhF36PccEl6EhOcAUCrXKZXXWS3XKd2vc/TRBG9O5ELC17MmWubD2nKhUKZa26Ba2+D3P+4/MNCFwg59oWVeYhkzgN/JDR8deKBoD7Y+ljEjGZ0sosXVTvbc6RHirr2reNy1OXd6pJsQ+gqjk8VWFYmHrwBzW/n+uMPFiRwHB2I7ih8ciHFxIkd/3Omk5tCDV1t+2nNu5sxxpDFNx+huNhVT3/zMDz8usXC3ddaHBj1GHj/As08fwTS7Kt1HBTmyN29vdwAw+/wbwLVOJ3uAD1wi/dUH7Qei66PfyuRj4Ik9is+hglfbkbfR3cnZm7chlUWLdwmprtCohX4HUtlOcQjLYCu+fzGJH2QRKvP3UNz8bWk1qMxjGTOMThZ3kvgLI5AzFfo379UAAAAASUVORK5CYII=\n// media_type \"image/png\"\n// }\n// }\n// }", "test-files/functions/input/named-args/single/named-int.baml": "// test for int\nfunction TestFnNamedArgsSingleInt(myInt: int) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myInt}}\n \"#\n}\n\ntest TestFnNamedArgsSingleInt {\n functions [TestFnNamedArgsSingleInt]\n args {\n myInt 42\n }\n}\n", "test-files/functions/input/named-args/single/named-map-string-to-class.baml": "class StringToClassEntry {\n word string\n}\n// test string\nfunction TestFnNamedArgsSingleMapStringToClass(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToClass {\n functions [TestFnNamedArgsSingleMapStringToClass]\n args {\n myMap {\n \"key\" {\n word \"lorem ipsum\"\n }\n }\n }\n}\n", - "test-files/functions/input/named-args/single/named-map-string-to-map.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}\n", + "test-files/functions/input/named-args/single/named-map-string-to-map.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToMap(myMap: map>) -> map> {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToMap {\n functions [TestFnNamedArgsSingleMapStringToMap]\n args {\n myMap {\n \"outer-key\" {\n \"key\" \"example string\"\n }\n }\n }\n}", "test-files/functions/input/named-args/single/named-map-string-to-string.baml": "// test string\nfunction TestFnNamedArgsSingleMapStringToString(myMap: map) -> map {\n client GPT35\n prompt #\"\n Return this value back to me: {{myMap}}\n \"#\n}\n\ntest TestFnNamedArgsSingleMapStringToString {\n functions [TestFnNamedArgsSingleMapStringToString]\n args {\n myMap {\n \"key\" \"example string\"\n }\n }\n}\n", "test-files/functions/input/named-args/single/named-string-list.baml": "// string[]\nfunction TestFnNamedArgsSingleStringArray(myStringArray: string[]) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myStringArray}}\n \"#\n}\n\ntest TestFnNamedArgsSingleStringArray {\n functions [TestFnNamedArgsSingleStringArray]\n args {\n myStringArray [\"example1\", \"example2\", \"example3\"]\n }\n}\n", "test-files/functions/input/named-args/single/named-string-optional.baml": "\n\n // string[]\nfunction FnNamedArgsSingleStringOptional(myString: string?) -> string {\n client GPT35\n prompt #\"\n Return this value back to me: {{myString}}\n \"#\n}\n\ntest FnNamedArgsSingleStringOptional {\n functions [FnNamedArgsSingleStringOptional]\n args {\n myString \"example string\"\n }\n}\n\ntest FnNamedArgsSingleStringOptional2 {\n functions [FnNamedArgsSingleStringOptional]\n args {\n \n }\n}\n", @@ -65,7 +67,7 @@ const fileMap = { "test-files/functions/prompts/no-chat-messages.baml": "\n\nfunction PromptTestClaude(input: string) -> string {\n client Claude\n prompt #\"\n Tell me a haiku about {{ input }}\n \"#\n}\n\n\nfunction PromptTestStreaming(input: string) -> string {\n client GPT35\n prompt #\"\n Tell me a short story about {{ input }}\n \"#\n}\n\ntest TestName {\n functions [PromptTestStreaming]\n args {\n input #\"\n hello world\n \"#\n }\n}\n", "test-files/functions/prompts/with-chat-messages.baml": "\nfunction PromptTestOpenAIChat(input: string) -> string {\n client GPT35\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAIChatNoSystem(input: string) -> string {\n client GPT35\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChat(input: string) -> string {\n client Claude\n prompt #\"\n {{ _.role(\"system\") }}\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestClaudeChatNoSystem(input: string) -> string {\n client Claude\n prompt #\"\n You are an assistant that always responds in a very excited way with emojis and also outputs this word 4 times after giving a response: {{ input }}\n \n {{ _.role(\"user\") }}\n Tell me a haiku about {{ input }}\n \"#\n}\n\ntest TestSystemAndNonSystemChat1 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"cats\"\n }\n}\n\ntest TestSystemAndNonSystemChat2 {\n functions [PromptTestClaude, PromptTestOpenAI, PromptTestOpenAIChat, PromptTestOpenAIChatNoSystem, PromptTestClaudeChat, PromptTestClaudeChatNoSystem]\n args {\n input \"lion\"\n }\n}", "test-files/functions/v2/basic.baml": "\n\nfunction ExtractResume2(resume: string) -> Resume {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\n Extract the following information from the resume:\n\n Resume:\n <<<<\n {{ resume }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}\n\n\nclass WithReasoning {\n value string\n reasoning string @description(#\"\n Why the value is a good fit.\n \"#)\n}\n\n\nclass SearchParams {\n dateRange int? @description(#\"\n In ISO duration format, e.g. P1Y2M10D.\n \"#)\n location string[]\n jobTitle WithReasoning? @description(#\"\n An exact job title, not a general category.\n \"#)\n company WithReasoning? @description(#\"\n The exact name of the company, not a product or service.\n \"#)\n description WithReasoning[] @description(#\"\n Any specific projects or features the user is looking for.\n \"#)\n tags (Tag | string)[]\n}\n\nenum Tag {\n Security\n AI\n Blockchain\n}\n\nfunction GetQuery(query: string) -> SearchParams {\n client GPT4\n prompt #\"\n Extract the following information from the query:\n\n Query:\n <<<<\n {{ query }}\n <<<<\n\n OUTPUT_JSON_SCHEMA:\n {{ ctx.output_format }}\n\n Before OUTPUT_JSON_SCHEMA, list 5 intentions the user may have.\n --- EXAMPLES ---\n 1. \n 2. \n 3. \n 4. \n 5. \n\n {\n ... // OUTPUT_JSON_SCHEMA\n }\n \"#\n}\n\nclass RaysData {\n dataType DataType\n value Resume | Event\n}\n\nenum DataType {\n Resume\n Event\n}\n\nclass Event {\n title string\n date string\n location string\n description string\n}\n\nfunction GetDataType(text: string) -> RaysData {\n client GPT4\n prompt #\"\n Extract the relevant info.\n\n Text:\n <<<<\n {{ text }}\n <<<<\n\n Output JSON schema:\n {{ ctx.output_format }}\n\n JSON:\n \"#\n}", - "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, TestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n", + "test-files/providers/providers.baml": "function TestAnthropic(input: string) -> string {\n client Claude\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction PromptTestOpenAI(input: string) -> string {\n client GPT35\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOpenAILegacyProvider(input: string) -> string {\n client GPT35LegacyProvider\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestAzure(input: string) -> string {\n client GPT35Azure\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestOllama(input: string) -> string {\n client Ollama\n prompt #\"\n Write a nice haiku about {{ input }}\n \"#\n}\n\nfunction TestGemini(input: string) -> string {\n client Gemini\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\nfunction TestVertex(input: string) -> string {\n client Vertex\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n\n}\n\nfunction TestAws(input: string) -> string {\n client AwsBedrock\n prompt #\"\n Write a nice short story about {{ input }}\n \"#\n}\n\n\ntest TestProvider {\n functions [TestAnthropic, TestVertex, PromptTestOpenAI, TestAzure, TestOllama, TestGemini, TestAws]\n args {\n input \"Donkey kong and peanut butter\"\n }\n}\n\n\n\n", "test-files/strategies/fallback.baml": "\nclient FaultyClient {\n provider openai\n options {\n model unknown-model\n api_key env.OPENAI_API_KEY\n }\n}\n\n\nclient FallbackClient {\n provider fallback\n options {\n // first 2 clients are expected to fail.\n strategy [\n FaultyClient,\n RetryClientConstant,\n GPT35\n ]\n }\n}\n\nfunction TestFallbackClient() -> string {\n client FallbackClient\n // TODO make it return the client name instead\n prompt #\"\n Say a haiku about mexico.\n \"#\n}", "test-files/strategies/retry.baml": "\nretry_policy Exponential {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Constant {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient RetryClientConstant {\n provider openai\n retry_policy Constant\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blah\"\n }\n}\n\nclient RetryClientExponential {\n provider openai\n retry_policy Exponential\n options {\n model \"gpt-3.5-turbo\"\n api_key \"blahh\"\n }\n}\n\nfunction TestRetryConstant() -> string {\n client RetryClientConstant\n prompt #\"\n Say a haiku\n \"#\n}\n\nfunction TestRetryExponential() -> string {\n client RetryClientExponential\n prompt #\"\n Say a haiku\n \"#\n}\n", "test-files/strategies/roundrobin.baml": "", diff --git a/integ-tests/typescript/baml_client/sync_client.ts b/integ-tests/typescript/baml_client/sync_client.ts index 20018c7ad..294235cc9 100644 --- a/integ-tests/typescript/baml_client/sync_client.ts +++ b/integ-tests/typescript/baml_client/sync_client.ts @@ -15,7 +15,7 @@ $ pnpm add @boundaryml/baml // @ts-nocheck // biome-ignore format: autogenerated code /* eslint-disable */ -import { BamlRuntime, FunctionResult, BamlCtxManager, BamlSyncStream, Image, ClientBuilder } from "@boundaryml/baml" +import { BamlRuntime, FunctionResult, BamlCtxManager, BamlSyncStream, Image, ClientRegistry } from "@boundaryml/baml" import {Blah, ClassOptionalOutput, ClassOptionalOutput2, ClassWithImage, DummyOutput, DynInputOutput, DynamicClassOne, DynamicClassTwo, DynamicOutput, Education, Email, Event, FakeImage, InnerClass, InnerClass2, NamedArgsSingleClass, OptionalTest_Prop1, OptionalTest_ReturnType, OrderInfo, Person, Quantity, RaysData, ReceiptInfo, ReceiptItem, Recipe, Resume, SearchParams, SomeClassNestedDynamic, StringToClassEntry, TestClassAlias, TestClassNested, TestClassWithEnum, TestOutputClass, UnionTest_ReturnType, WithReasoning, Category, Category2, Category3, Color, DataType, DynEnumOne, DynEnumTwo, EnumInClass, EnumOutput, Hobby, NamedArgsSingleEnum, NamedArgsSingleEnumList, OptionalTest_CategoryType, OrderStatus, Tag, TestEnum} from "./types" import TypeBuilder from "./type_builder" import { DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX, DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_RUNTIME } from "./globals" @@ -53,7 +53,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Recipe } @@ -69,7 +69,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -85,7 +85,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -101,7 +101,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -117,7 +117,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Category } @@ -133,7 +133,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -149,7 +149,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -165,7 +165,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -181,7 +181,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -197,7 +197,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DummyOutput } @@ -213,7 +213,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynamicClassTwo } @@ -229,7 +229,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynInputOutput } @@ -245,11 +245,27 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynInputOutput[] } + ExpectFailure( + + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): string { + const raw = this.runtime.callFunctionSync( + "ExpectFailure", + { + + }, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, + ) + return raw.parsed() as string + } + ExtractNames( input: string, __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } @@ -261,7 +277,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string[] } @@ -277,7 +293,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Person[] } @@ -293,7 +309,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ReceiptInfo } @@ -309,7 +325,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Resume } @@ -325,7 +341,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Resume } @@ -341,7 +357,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ClassOptionalOutput | null } @@ -357,7 +373,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as ClassOptionalOutput2 | null } @@ -373,7 +389,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as EnumOutput[] } @@ -389,7 +405,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as EnumOutput } @@ -405,7 +421,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -421,7 +437,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as boolean } @@ -437,7 +453,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestOutputClass } @@ -453,7 +469,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestOutputClass[] } @@ -469,7 +485,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassNested } @@ -485,7 +501,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassWithEnum } @@ -501,7 +517,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string[] } @@ -517,7 +533,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestEnum } @@ -533,7 +549,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as TestClassAlias } @@ -549,7 +565,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -565,7 +581,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as RaysData } @@ -581,7 +597,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as OrderInfo } @@ -597,7 +613,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as SearchParams } @@ -613,7 +629,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as DynamicOutput } @@ -629,7 +645,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as (OptionalTest_ReturnType | null)[] } @@ -645,7 +661,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -661,7 +677,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -677,7 +693,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -693,7 +709,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -709,7 +725,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -725,7 +741,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -741,7 +757,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -757,7 +773,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -773,7 +789,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -789,7 +805,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -805,7 +821,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -821,7 +837,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -837,7 +853,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -853,7 +869,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -869,7 +885,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -885,7 +901,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -901,7 +917,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record } @@ -917,7 +933,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record> } @@ -933,7 +949,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as Record } @@ -949,7 +965,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -965,7 +981,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -981,7 +997,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -997,7 +1013,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1013,7 +1029,23 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, + ) + return raw.parsed() as string + } + + TestImageListInput( + imgs: Image[], + __baml_options__?: { tb?: TypeBuilder, clientRegistry?: ClientRegistry } + ): string { + const raw = this.runtime.callFunctionSync( + "TestImageListInput", + { + "imgs": imgs + }, + this.ctx_manager.cloneContext(), + __baml_options__?.tb?.__tb(), + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1029,7 +1061,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1045,7 +1077,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1061,7 +1093,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1077,7 +1109,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1093,7 +1125,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1109,7 +1141,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as string } @@ -1125,7 +1157,7 @@ export class BamlSyncClient { }, this.ctx_manager.cloneContext(), __baml_options__?.tb?.__tb(), - __baml_options__?.cr, + __baml_options__?.clientRegistry, ) return raw.parsed() as UnionTest_ReturnType } diff --git a/integ-tests/typescript/baml_client/tracing.ts b/integ-tests/typescript/baml_client/tracing.ts index db3cc2deb..df2682e13 100644 --- a/integ-tests/typescript/baml_client/tracing.ts +++ b/integ-tests/typescript/baml_client/tracing.ts @@ -27,7 +27,7 @@ DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX.upsertTags.bind(DO_NOT_ const flush = () => { DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX.flush.bind(DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX)() } -const onLogEvent = (callback: (event: BamlLogEvent) => void) => +const onLogEvent = (callback: undefined | ((event: BamlLogEvent) => void)) => DO_NOT_USE_DIRECTLY_UNLESS_YOU_KNOW_WHAT_YOURE_DOING_CTX.onLogEvent(callback) export { traceAsync, traceSync, setTags, flush, onLogEvent } \ No newline at end of file diff --git a/integ-tests/typescript/baml_client/type_builder.ts b/integ-tests/typescript/baml_client/type_builder.ts index aa1463576..680d13bc9 100644 --- a/integ-tests/typescript/baml_client/type_builder.ts +++ b/integ-tests/typescript/baml_client/type_builder.ts @@ -126,6 +126,18 @@ export default class TypeBuilder { return this.tb.list(type) } + null(): FieldType { + return this.tb.null() + } + + map(key: FieldType, value: FieldType): FieldType { + return this.tb.map(key, value) + } + + union(types: FieldType[]): FieldType { + return this.tb.union(types) + } + addClass(name: Name): ClassBuilder { return this.tb.addClass(name); } diff --git a/integ-tests/typescript/jest.config.js b/integ-tests/typescript/jest.config.js index 9a551cda4..6df98df18 100644 --- a/integ-tests/typescript/jest.config.js +++ b/integ-tests/typescript/jest.config.js @@ -1,5 +1,19 @@ -module.exports = { +/** @type {import('jest').Config} */ +const config = { transform: { '^.+\\.(t|j)sx?$': '@swc/jest', }, + reporters: [ + 'default', + [ + './node_modules/jest-html-reporter', + { + pageTitle: 'Test Report', + includeConsoleLog: true, + includeFailureMsg: true, + }, + ], + ], } + +module.exports = config diff --git a/integ-tests/typescript/package.json b/integ-tests/typescript/package.json index 87efc49e4..43e20add1 100644 --- a/integ-tests/typescript/package.json +++ b/integ-tests/typescript/package.json @@ -7,8 +7,9 @@ "test": "jest", "build:debug": "cd ../../engine/language_client_typescript && pnpm run build:debug && cd - && pnpm i", "build": "cd ../../engine/language_client_typescript && npm run build && cd - && pnpm i", - "integ-tests": "BAML_LOG=info infisical run --env=test -- pnpm test -- --silent false --testTimeout 30000", - "integ-tests:dotenv": "BAML_LOG=info dotenv -e ../.env -- pnpm test -- --silent false --testTimeout 30000", + "integ-tests:ci": "infisical run --env=test -- pnpm test -- --silent false --testTimeout 30000 --verbose=false", + "integ-tests": "infisical run --env=test -- pnpm test -- --silent false --testTimeout 30000", + "integ-tests:dotenv": "dotenv -e ../.env -- pnpm test -- --silent false --testTimeout 30000", "generate": "baml-cli generate --from ../baml_src" }, "keywords": [], @@ -21,6 +22,7 @@ "@types/node": "^20.11.27", "dotenv-cli": "^7.4.2", "jest": "^29.7.0", + "jest-html-reporter": "^3.10.2", "ts-jest": "^29.1.2", "ts-node": "^10.9.2", "ts-node-dev": "^2.0.0", diff --git a/integ-tests/typescript/pnpm-lock.yaml b/integ-tests/typescript/pnpm-lock.yaml index 55daee16e..b6177e9a5 100644 --- a/integ-tests/typescript/pnpm-lock.yaml +++ b/integ-tests/typescript/pnpm-lock.yaml @@ -1,75 +1,1485 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@boundaryml/baml': - specifier: link:../../engine/language_client_typescript - version: link:../../engine/language_client_typescript - dotenv: - specifier: ^16.4.5 - version: 16.4.5 - -devDependencies: - '@swc/core': - specifier: ^1.5.7 - version: 1.5.7 - '@swc/jest': - specifier: ^0.2.36 - version: 0.2.36(@swc/core@1.5.7) - '@types/jest': - specifier: ^29.5.12 - version: 29.5.12 - '@types/node': - specifier: ^20.11.27 - version: 20.11.30 - dotenv-cli: - specifier: ^7.4.2 - version: 7.4.2 - jest: - specifier: ^29.7.0 - version: 29.7.0(@types/node@20.11.30)(ts-node@10.9.2) - ts-jest: - specifier: ^29.1.2 - version: 29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3) - ts-node: - specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3) - ts-node-dev: - specifier: ^2.0.0 - version: 2.0.0(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3) - typescript: - specifier: ^5.4.2 - version: 5.4.3 +importers: + + .: + dependencies: + '@boundaryml/baml': + specifier: link:../../engine/language_client_typescript + version: link:../../engine/language_client_typescript + dotenv: + specifier: ^16.4.5 + version: 16.4.5 + devDependencies: + '@swc/core': + specifier: ^1.5.7 + version: 1.5.7 + '@swc/jest': + specifier: ^0.2.36 + version: 0.2.36(@swc/core@1.5.7) + '@types/jest': + specifier: ^29.5.12 + version: 29.5.12 + '@types/node': + specifier: ^20.11.27 + version: 20.11.30 + dotenv-cli: + specifier: ^7.4.2 + version: 7.4.2 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@20.11.30)(ts-node@10.9.2) + jest-html-reporter: + specifier: ^3.10.2 + version: 3.10.2(jest@29.7.0)(typescript@5.4.3) + ts-jest: + specifier: ^29.1.2 + version: 29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3) + ts-node-dev: + specifier: ^2.0.0 + version: 2.0.0(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3) + typescript: + specifier: ^5.4.2 + version: 5.4.3 packages: - /@ampproject/remapping@2.3.0: - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.24.2': + resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.24.1': + resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.24.3': + resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.24.1': + resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.23.6': + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-environment-visitor@7.22.20': + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-function-name@7.23.0': + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-hoist-variables@7.22.5': + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.24.3': + resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.23.3': + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.24.0': + resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-simple-access@7.22.5': + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-split-export-declaration@7.22.6': + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.24.1': + resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.22.20': + resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.23.5': + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.24.1': + resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} + engines: {node: '>=6.9.0'} + + '@babel/highlight@7.24.2': + resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.24.1': + resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.24.1': + resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.24.1': + resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.24.0': + resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.24.1': + resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.24.0': + resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/create-cache-key-function@29.7.0': + resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.5': + resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.4.15': + resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@swc/core-darwin-arm64@1.5.7': + resolution: {integrity: sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [darwin] + + '@swc/core-darwin-x64@1.5.7': + resolution: {integrity: sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==} + engines: {node: '>=10'} + cpu: [x64] + os: [darwin] + + '@swc/core-linux-arm-gnueabihf@1.5.7': + resolution: {integrity: sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==} + engines: {node: '>=10'} + cpu: [arm] + os: [linux] + + '@swc/core-linux-arm64-gnu@1.5.7': + resolution: {integrity: sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-arm64-musl@1.5.7': + resolution: {integrity: sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==} + engines: {node: '>=10'} + cpu: [arm64] + os: [linux] + + '@swc/core-linux-x64-gnu@1.5.7': + resolution: {integrity: sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-linux-x64-musl@1.5.7': + resolution: {integrity: sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==} + engines: {node: '>=10'} + cpu: [x64] + os: [linux] + + '@swc/core-win32-arm64-msvc@1.5.7': + resolution: {integrity: sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==} + engines: {node: '>=10'} + cpu: [arm64] + os: [win32] + + '@swc/core-win32-ia32-msvc@1.5.7': + resolution: {integrity: sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==} + engines: {node: '>=10'} + cpu: [ia32] + os: [win32] + + '@swc/core-win32-x64-msvc@1.5.7': + resolution: {integrity: sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==} + engines: {node: '>=10'} + cpu: [x64] + os: [win32] + + '@swc/core@1.5.7': + resolution: {integrity: sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==} + engines: {node: '>=10'} + peerDependencies: + '@swc/helpers': ^0.5.0 + peerDependenciesMeta: + '@swc/helpers': + optional: true + + '@swc/counter@0.1.3': + resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} + + '@swc/jest@0.2.36': + resolution: {integrity: sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==} + engines: {npm: '>= 7.0.0'} + peerDependencies: + '@swc/core': '*' + + '@swc/types@0.1.7': + resolution: {integrity: sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.6.8': + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.5': + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.12': + resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + + '@types/node@20.11.30': + resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/strip-bom@3.0.0': + resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==} + + '@types/strip-json-comments@0.0.30': + resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.32': + resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + + acorn-walk@8.3.2: + resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} + engines: {node: '>=0.4.0'} + + acorn@8.11.3: + resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.0.1: + resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + browserslist@4.23.0: + resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001600: + resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==} + + chalk@2.4.2: + resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.2.3: + resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + dateformat@3.0.2: + resolution: {integrity: sha512-EelsCzH0gMC2YmXuMeaZ3c6md1sUJQxyb1XXc4xaisi/K6qKukqZhKPrEQyRkdNIncgYyLoDTReq0nNyuKerTg==} + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.5.1: + resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dotenv-cli@7.4.2: + resolution: {integrity: sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==} + hasBin: true + + dotenv-expand@10.0.0: + resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} + engines: {node: '>=12'} + + dotenv@16.4.5: + resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} + engines: {node: '>=12'} + + dynamic-dedupe@0.3.0: + resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} + + electron-to-chromium@1.4.721: + resolution: {integrity: sha512-k1x2r6foI8iJOp+1qTxbbrrWMsOiHkzGBYwYigaq+apO1FSqtn44KTo3Sy69qt7CRr7149zTcsDvH7MUKsOuIQ==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + escalade@3.1.2: + resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} + engines: {node: '>=6'} + + escape-string-regexp@1.0.5: + resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} + engines: {node: '>=0.8.0'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + import-local@3.1.0: + resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-core-module@2.13.1: + resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.2: + resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-html-reporter@3.10.2: + resolution: {integrity: sha512-XRBa5ylHPUQoo8aJXEEdKsTruieTdlPbRktMx9WG9evMTxzJEKGFMaw5x+sQxJuClWdNR72GGwbOaz+6HIlksA==} + engines: {node: '>=4.8.3'} + peerDependencies: + jest: 19.x - 29.x + typescript: ^3.7.x || ^4.3.x || ^5.x + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonc-parser@3.2.1: + resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.14: + resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.0.0: + resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.6: + resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + react-is@18.2.0: + resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} + + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + + resolve@1.22.8: + resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} + hasBin: true + + rimraf@2.7.1: + resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} + hasBin: true + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-fast-properties@2.0.0: + resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-jest@29.1.2: + resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} + engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + ts-node-dev@2.0.0: + resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} + engines: {node: '>=0.8.0'} + hasBin: true + peerDependencies: + node-notifier: '*' + typescript: '*' + peerDependenciesMeta: + node-notifier: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + tsconfig@7.0.0: + resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + typescript@5.4.3: + resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + update-browserslist-db@1.0.13: + resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.2.0: + resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + xmlbuilder@15.0.0: + resolution: {integrity: sha512-KLu/G0DoWhkncQ9eHSI6s0/w+T4TM7rQaLhtCaL6tORv8jFlJPlnGumsgTcGfYeS1qZ/IHqrvDG7zJZ4d7e+nw==} + engines: {node: '>=8.0'} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - dev: true - /@babel/code-frame@7.24.2: - resolution: {integrity: sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==} - engines: {node: '>=6.9.0'} + '@babel/code-frame@7.24.2': dependencies: '@babel/highlight': 7.24.2 picocolors: 1.0.0 - dev: true - /@babel/compat-data@7.24.1: - resolution: {integrity: sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/compat-data@7.24.1': {} - /@babel/core@7.24.3: - resolution: {integrity: sha512-5FcvN1JHw2sHJChotgx8Ek0lyuh4kCKelgMTTqhYJJtloNvUfpAFMeNQUtdlIaktwrSV9LtCdqwk48wL2wBacQ==} - engines: {node: '>=6.9.0'} + '@babel/core@7.24.3': dependencies: '@ampproject/remapping': 2.3.0 '@babel/code-frame': 7.24.2 @@ -88,61 +1498,38 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /@babel/generator@7.24.1: - resolution: {integrity: sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==} - engines: {node: '>=6.9.0'} + '@babel/generator@7.24.1': dependencies: '@babel/types': 7.24.0 '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 jsesc: 2.5.2 - dev: true - /@babel/helper-compilation-targets@7.23.6: - resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} - engines: {node: '>=6.9.0'} + '@babel/helper-compilation-targets@7.23.6': dependencies: '@babel/compat-data': 7.24.1 '@babel/helper-validator-option': 7.23.5 browserslist: 4.23.0 lru-cache: 5.1.1 semver: 6.3.1 - dev: true - /@babel/helper-environment-visitor@7.22.20: - resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-environment-visitor@7.22.20': {} - /@babel/helper-function-name@7.23.0: - resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} - engines: {node: '>=6.9.0'} + '@babel/helper-function-name@7.23.0': dependencies: '@babel/template': 7.24.0 '@babel/types': 7.24.0 - dev: true - /@babel/helper-hoist-variables@7.22.5: - resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} - engines: {node: '>=6.9.0'} + '@babel/helper-hoist-variables@7.22.5': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-module-imports@7.24.3: - resolution: {integrity: sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==} - engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.24.3': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3): - resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 + '@babel/helper-module-transforms@7.23.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-environment-visitor': 7.22.20 @@ -150,212 +1537,119 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 - dev: true - /@babel/helper-plugin-utils@7.24.0: - resolution: {integrity: sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-plugin-utils@7.24.0': {} - /@babel/helper-simple-access@7.22.5: - resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} - engines: {node: '>=6.9.0'} + '@babel/helper-simple-access@7.22.5': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-split-export-declaration@7.22.6: - resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} - engines: {node: '>=6.9.0'} + '@babel/helper-split-export-declaration@7.22.6': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/helper-string-parser@7.24.1: - resolution: {integrity: sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-string-parser@7.24.1': {} - /@babel/helper-validator-identifier@7.22.20: - resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-identifier@7.22.20': {} - /@babel/helper-validator-option@7.23.5: - resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} - engines: {node: '>=6.9.0'} - dev: true + '@babel/helper-validator-option@7.23.5': {} - /@babel/helpers@7.24.1: - resolution: {integrity: sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==} - engines: {node: '>=6.9.0'} + '@babel/helpers@7.24.1': dependencies: '@babel/template': 7.24.0 '@babel/traverse': 7.24.1 '@babel/types': 7.24.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/highlight@7.24.2: - resolution: {integrity: sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==} - engines: {node: '>=6.9.0'} + '@babel/highlight@7.24.2': dependencies: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 picocolors: 1.0.0 - dev: true - /@babel/parser@7.24.1: - resolution: {integrity: sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==} - engines: {node: '>=6.0.0'} - hasBin: true + '@babel/parser@7.24.1': dependencies: '@babel/types': 7.24.0 - dev: true - /@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3): - resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3): - resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3): - resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-2eCtxZXf+kbkMIsXS4poTvT4Yu5rXiRa+9xGVT56raghjmBTKMpFNc9R4IDiB4emao9eO22Ox7CxuJG7BgExqA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-jsx@7.24.1(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3): - resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3): - resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3): - resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3): - resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3): - resolution: {integrity: sha512-Yhnmvy5HZEnHUty6i++gcfH1/l68AHnItFHnaCv6hn9dNh0hQvvQJsxpi4BMBFN5DLeHBuucT/0DgzXif/OyRw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@babel/plugin-syntax-typescript@7.24.1(@babel/core@7.24.3)': dependencies: '@babel/core': 7.24.3 '@babel/helper-plugin-utils': 7.24.0 - dev: true - /@babel/template@7.24.0: - resolution: {integrity: sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==} - engines: {node: '>=6.9.0'} + '@babel/template@7.24.0': dependencies: '@babel/code-frame': 7.24.2 '@babel/parser': 7.24.1 '@babel/types': 7.24.0 - dev: true - /@babel/traverse@7.24.1: - resolution: {integrity: sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==} - engines: {node: '>=6.9.0'} + '@babel/traverse@7.24.1': dependencies: '@babel/code-frame': 7.24.2 '@babel/generator': 7.24.1 @@ -369,47 +1663,30 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color - dev: true - /@babel/types@7.24.0: - resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==} - engines: {node: '>=6.9.0'} + '@babel/types@7.24.0': dependencies: '@babel/helper-string-parser': 7.24.1 '@babel/helper-validator-identifier': 7.22.20 to-fast-properties: 2.0.0 - dev: true - /@bcoe/v8-coverage@0.2.3: - resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} - dev: true + '@bcoe/v8-coverage@0.2.3': {} - /@cspotcode/source-map-support@0.8.1: - resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} - engines: {node: '>=12'} + '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - dev: true - /@istanbuljs/load-nyc-config@1.1.0: - resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} - engines: {node: '>=8'} + '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 js-yaml: 3.14.1 resolve-from: 5.0.0 - dev: true - /@istanbuljs/schema@0.1.3: - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} - engines: {node: '>=8'} - dev: true + '@istanbuljs/schema@0.1.3': {} - /@jest/console@29.7.0: - resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/console@29.7.0': dependencies: '@jest/types': 29.6.3 '@types/node': 20.11.30 @@ -417,16 +1694,8 @@ packages: jest-message-util: 29.7.0 jest-util: 29.7.0 slash: 3.0.0 - dev: true - /@jest/core@29.7.0(ts-node@10.9.2): - resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/core@29.7.0(ts-node@10.9.2)': dependencies: '@jest/console': 29.7.0 '@jest/reporters': 29.7.0 @@ -460,45 +1729,30 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /@jest/create-cache-key-function@29.7.0: - resolution: {integrity: sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/create-cache-key-function@29.7.0': dependencies: '@jest/types': 29.6.3 - dev: true - /@jest/environment@29.7.0: - resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/environment@29.7.0': dependencies: '@jest/fake-timers': 29.7.0 '@jest/types': 29.6.3 '@types/node': 20.11.30 jest-mock: 29.7.0 - dev: true - /@jest/expect-utils@29.7.0: - resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect-utils@29.7.0': dependencies: jest-get-type: 29.6.3 - dev: true - /@jest/expect@29.7.0: - resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/expect@29.7.0': dependencies: expect: 29.7.0 jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/fake-timers@29.7.0: - resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/fake-timers@29.7.0': dependencies: '@jest/types': 29.6.3 '@sinonjs/fake-timers': 10.3.0 @@ -506,11 +1760,8 @@ packages: jest-message-util: 29.7.0 jest-mock: 29.7.0 jest-util: 29.7.0 - dev: true - /@jest/globals@29.7.0: - resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/globals@29.7.0': dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -518,16 +1769,8 @@ packages: jest-mock: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/reporters@29.7.0: - resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + '@jest/reporters@29.7.0': dependencies: '@bcoe/v8-coverage': 0.2.3 '@jest/console': 29.7.0 @@ -555,47 +1798,32 @@ packages: v8-to-istanbul: 9.2.0 transitivePeerDependencies: - supports-color - dev: true - /@jest/schemas@29.6.3: - resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/schemas@29.6.3': dependencies: '@sinclair/typebox': 0.27.8 - dev: true - /@jest/source-map@29.6.3: - resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/source-map@29.6.3': dependencies: '@jridgewell/trace-mapping': 0.3.25 callsites: 3.1.0 graceful-fs: 4.2.11 - dev: true - /@jest/test-result@29.7.0: - resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-result@29.7.0': dependencies: '@jest/console': 29.7.0 '@jest/types': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 collect-v8-coverage: 1.0.2 - dev: true - /@jest/test-sequencer@29.7.0: - resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/test-sequencer@29.7.0': dependencies: '@jest/test-result': 29.7.0 graceful-fs: 4.2.11 jest-haste-map: 29.7.0 slash: 3.0.0 - dev: true - /@jest/transform@29.7.0: - resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/transform@29.7.0': dependencies: '@babel/core': 7.24.3 '@jest/types': 29.6.3 @@ -614,11 +1842,8 @@ packages: write-file-atomic: 4.0.2 transitivePeerDependencies: - supports-color - dev: true - /@jest/types@29.6.3: - resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jest/types@29.6.3': dependencies: '@jest/schemas': 29.6.3 '@types/istanbul-lib-coverage': 2.0.6 @@ -626,160 +1851,70 @@ packages: '@types/node': 20.11.30 '@types/yargs': 17.0.32 chalk: 4.1.2 - dev: true - /@jridgewell/gen-mapping@0.3.5: - resolution: {integrity: sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==} - engines: {node: '>=6.0.0'} + '@jridgewell/gen-mapping@0.3.5': dependencies: '@jridgewell/set-array': 1.2.1 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.25 - dev: true - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/resolve-uri@3.1.2': {} - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} - engines: {node: '>=6.0.0'} - dev: true + '@jridgewell/set-array@1.2.1': {} - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: true + '@jridgewell/sourcemap-codec@1.4.15': {} - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + '@jridgewell/trace-mapping@0.3.25': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@jridgewell/trace-mapping@0.3.9: - resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.4.15 - dev: true - /@sinclair/typebox@0.27.8: - resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} - dev: true + '@sinclair/typebox@0.27.8': {} - /@sinonjs/commons@3.0.1: - resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + '@sinonjs/commons@3.0.1': dependencies: type-detect: 4.0.8 - dev: true - /@sinonjs/fake-timers@10.3.0: - resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + '@sinonjs/fake-timers@10.3.0': dependencies: '@sinonjs/commons': 3.0.1 - dev: true - /@swc/core-darwin-arm64@1.5.7: - resolution: {integrity: sha512-bZLVHPTpH3h6yhwVl395k0Mtx8v6CGhq5r4KQdAoPbADU974Mauz1b6ViHAJ74O0IVE5vyy7tD3OpkQxL/vMDQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true + '@swc/core-darwin-arm64@1.5.7': optional: true - /@swc/core-darwin-x64@1.5.7: - resolution: {integrity: sha512-RpUyu2GsviwTc2qVajPL0l8nf2vKj5wzO3WkLSHAHEJbiUZk83NJrZd1RVbEknIMO7+Uyjh54hEh8R26jSByaw==} - engines: {node: '>=10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true + '@swc/core-darwin-x64@1.5.7': optional: true - /@swc/core-linux-arm-gnueabihf@1.5.7: - resolution: {integrity: sha512-cTZWTnCXLABOuvWiv6nQQM0hP6ZWEkzdgDvztgHI/+u/MvtzJBN5lBQ2lue/9sSFYLMqzqff5EHKlFtrJCA9dQ==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true + '@swc/core-linux-arm-gnueabihf@1.5.7': optional: true - /@swc/core-linux-arm64-gnu@1.5.7: - resolution: {integrity: sha512-hoeTJFBiE/IJP30Be7djWF8Q5KVgkbDtjySmvYLg9P94bHg9TJPSQoC72tXx/oXOgXvElDe/GMybru0UxhKx4g==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@swc/core-linux-arm64-gnu@1.5.7': optional: true - /@swc/core-linux-arm64-musl@1.5.7: - resolution: {integrity: sha512-+NDhK+IFTiVK1/o7EXdCeF2hEzCiaRSrb9zD7X2Z7inwWlxAntcSuzZW7Y6BRqGQH89KA91qYgwbnjgTQ22PiQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true + '@swc/core-linux-arm64-musl@1.5.7': optional: true - /@swc/core-linux-x64-gnu@1.5.7: - resolution: {integrity: sha512-25GXpJmeFxKB+7pbY7YQLhWWjkYlR+kHz5I3j9WRl3Lp4v4UD67OGXwPe+DIcHqcouA1fhLhsgHJWtsaNOMBNg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@swc/core-linux-x64-gnu@1.5.7': optional: true - /@swc/core-linux-x64-musl@1.5.7: - resolution: {integrity: sha512-0VN9Y5EAPBESmSPPsCJzplZHV26akC0sIgd3Hc/7S/1GkSMoeuVL+V9vt+F/cCuzr4VidzSkqftdP3qEIsXSpg==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true + '@swc/core-linux-x64-musl@1.5.7': optional: true - /@swc/core-win32-arm64-msvc@1.5.7: - resolution: {integrity: sha512-RtoNnstBwy5VloNCvmvYNApkTmuCe4sNcoYWpmY7C1+bPR+6SOo8im1G6/FpNem8AR5fcZCmXHWQ+EUmRWJyuA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true + '@swc/core-win32-arm64-msvc@1.5.7': optional: true - /@swc/core-win32-ia32-msvc@1.5.7: - resolution: {integrity: sha512-Xm0TfvcmmspvQg1s4+USL3x8D+YPAfX2JHygvxAnCJ0EHun8cm2zvfNBcsTlnwYb0ybFWXXY129aq1wgFC9TpQ==} - engines: {node: '>=10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true + '@swc/core-win32-ia32-msvc@1.5.7': optional: true - /@swc/core-win32-x64-msvc@1.5.7: - resolution: {integrity: sha512-tp43WfJLCsKLQKBmjmY/0vv1slVywR5Q4qKjF5OIY8QijaEW7/8VwPyUyVoJZEnDgv9jKtUTG5PzqtIYPZGnyg==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true + '@swc/core-win32-x64-msvc@1.5.7': optional: true - /@swc/core@1.5.7: - resolution: {integrity: sha512-U4qJRBefIJNJDRCCiVtkfa/hpiZ7w0R6kASea+/KLp+vkus3zcLSB8Ub8SvKgTIxjWpwsKcZlPf5nrv4ls46SQ==} - engines: {node: '>=10'} - requiresBuild: true - peerDependencies: - '@swc/helpers': ^0.5.0 - peerDependenciesMeta: - '@swc/helpers': - optional: true + '@swc/core@1.5.7': dependencies: '@swc/counter': 0.1.3 '@swc/types': 0.1.7 @@ -794,197 +1929,116 @@ packages: '@swc/core-win32-arm64-msvc': 1.5.7 '@swc/core-win32-ia32-msvc': 1.5.7 '@swc/core-win32-x64-msvc': 1.5.7 - dev: true - /@swc/counter@0.1.3: - resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==} - dev: true + '@swc/counter@0.1.3': {} - /@swc/jest@0.2.36(@swc/core@1.5.7): - resolution: {integrity: sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw==} - engines: {npm: '>= 7.0.0'} - peerDependencies: - '@swc/core': '*' + '@swc/jest@0.2.36(@swc/core@1.5.7)': dependencies: '@jest/create-cache-key-function': 29.7.0 '@swc/core': 1.5.7 '@swc/counter': 0.1.3 jsonc-parser: 3.2.1 - dev: true - /@swc/types@0.1.7: - resolution: {integrity: sha512-scHWahbHF0eyj3JsxG9CFJgFdFNaVQCNAimBlT6PzS3n/HptxqREjsm4OH6AN3lYcffZYSPxXW8ua2BEHp0lJQ==} + '@swc/types@0.1.7': dependencies: '@swc/counter': 0.1.3 - dev: true - /@tsconfig/node10@1.0.11: - resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} - dev: true + '@tsconfig/node10@1.0.11': {} - /@tsconfig/node12@1.0.11: - resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - dev: true + '@tsconfig/node12@1.0.11': {} - /@tsconfig/node14@1.0.3: - resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dev: true + '@tsconfig/node14@1.0.3': {} - /@tsconfig/node16@1.0.4: - resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - dev: true + '@tsconfig/node16@1.0.4': {} - /@types/babel__core@7.20.5: - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@types/babel__core@7.20.5': dependencies: '@babel/parser': 7.24.1 '@babel/types': 7.24.0 '@types/babel__generator': 7.6.8 '@types/babel__template': 7.4.4 '@types/babel__traverse': 7.20.5 - dev: true - /@types/babel__generator@7.6.8: - resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + '@types/babel__generator@7.6.8': dependencies: '@babel/types': 7.24.0 - dev: true - /@types/babel__template@7.4.4: - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@types/babel__template@7.4.4': dependencies: '@babel/parser': 7.24.1 '@babel/types': 7.24.0 - dev: true - /@types/babel__traverse@7.20.5: - resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + '@types/babel__traverse@7.20.5': dependencies: '@babel/types': 7.24.0 - dev: true - /@types/graceful-fs@4.1.9: - resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + '@types/graceful-fs@4.1.9': dependencies: '@types/node': 20.11.30 - dev: true - /@types/istanbul-lib-coverage@2.0.6: - resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - dev: true + '@types/istanbul-lib-coverage@2.0.6': {} - /@types/istanbul-lib-report@3.0.3: - resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + '@types/istanbul-lib-report@3.0.3': dependencies: '@types/istanbul-lib-coverage': 2.0.6 - dev: true - /@types/istanbul-reports@3.0.4: - resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/istanbul-reports@3.0.4': dependencies: '@types/istanbul-lib-report': 3.0.3 - dev: true - /@types/jest@29.5.12: - resolution: {integrity: sha512-eDC8bTvT/QhYdxJAulQikueigY5AsdBRH2yDKW3yveW7svY3+DzN84/2NUgkw10RTiJbWqZrTtoGVdYlvFJdLw==} + '@types/jest@29.5.12': dependencies: expect: 29.7.0 pretty-format: 29.7.0 - dev: true - /@types/node@20.11.30: - resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} + '@types/node@20.11.30': dependencies: undici-types: 5.26.5 - dev: true - /@types/stack-utils@2.0.3: - resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} - dev: true + '@types/stack-utils@2.0.3': {} - /@types/strip-bom@3.0.0: - resolution: {integrity: sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==} - dev: true + '@types/strip-bom@3.0.0': {} - /@types/strip-json-comments@0.0.30: - resolution: {integrity: sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==} - dev: true + '@types/strip-json-comments@0.0.30': {} - /@types/yargs-parser@21.0.3: - resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - dev: true + '@types/yargs-parser@21.0.3': {} - /@types/yargs@17.0.32: - resolution: {integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==} + '@types/yargs@17.0.32': dependencies: '@types/yargs-parser': 21.0.3 - dev: true - /acorn-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - dev: true + acorn-walk@8.3.2: {} - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@8.11.3: {} - /ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} + ansi-escapes@4.3.2: dependencies: type-fest: 0.21.3 - dev: true - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-styles@3.2.1: - resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} - engines: {node: '>=4'} + ansi-styles@3.2.1: dependencies: color-convert: 1.9.3 - dev: true - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - dev: true + ansi-styles@5.2.0: {} - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anymatch@3.1.3: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: true - /arg@4.1.3: - resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} - dev: true + arg@4.1.3: {} - /argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + argparse@1.0.10: dependencies: sprintf-js: 1.0.3 - dev: true - /babel-jest@29.7.0(@babel/core@7.24.3): - resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.8.0 + babel-jest@29.7.0(@babel/core@7.24.3): dependencies: '@babel/core': 7.24.3 '@jest/transform': 29.7.0 @@ -996,11 +2050,8 @@ packages: slash: 3.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-istanbul@6.1.1: - resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} - engines: {node: '>=8'} + babel-plugin-istanbul@6.1.1: dependencies: '@babel/helper-plugin-utils': 7.24.0 '@istanbuljs/load-nyc-config': 1.1.0 @@ -1009,22 +2060,15 @@ packages: test-exclude: 6.0.0 transitivePeerDependencies: - supports-color - dev: true - /babel-plugin-jest-hoist@29.6.3: - resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + babel-plugin-jest-hoist@29.6.3: dependencies: '@babel/template': 7.24.0 '@babel/types': 7.24.0 '@types/babel__core': 7.20.5 '@types/babel__traverse': 7.20.5 - dev: true - /babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3): - resolution: {integrity: sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-current-node-syntax@1.0.1(@babel/core@7.24.3): dependencies: '@babel/core': 7.24.3 '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.24.3) @@ -1039,114 +2083,65 @@ packages: '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.24.3) '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.24.3) '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.24.3) - dev: true - /babel-preset-jest@29.6.3(@babel/core@7.24.3): - resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@babel/core': ^7.0.0 + babel-preset-jest@29.6.3(@babel/core@7.24.3): dependencies: '@babel/core': 7.24.3 babel-plugin-jest-hoist: 29.6.3 babel-preset-current-node-syntax: 1.0.1(@babel/core@7.24.3) - dev: true - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - dev: true + binary-extensions@2.3.0: {} - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.2: dependencies: fill-range: 7.0.1 - dev: true - /browserslist@4.23.0: - resolution: {integrity: sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + browserslist@4.23.0: dependencies: caniuse-lite: 1.0.30001600 electron-to-chromium: 1.4.721 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.23.0) - dev: true - /bs-logger@0.2.6: - resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} - engines: {node: '>= 6'} + bs-logger@0.2.6: dependencies: fast-json-stable-stringify: 2.1.0 - dev: true - /bser@2.1.1: - resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + bser@2.1.1: dependencies: node-int64: 0.4.0 - dev: true - /buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - dev: true + buffer-from@1.1.2: {} - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - dev: true + camelcase@5.3.1: {} - /camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} - dev: true + camelcase@6.3.0: {} - /caniuse-lite@1.0.30001600: - resolution: {integrity: sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==} - dev: true + caniuse-lite@1.0.30001600: {} - /chalk@2.4.2: - resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} - engines: {node: '>=4'} + chalk@2.4.2: dependencies: ansi-styles: 3.2.1 escape-string-regexp: 1.0.5 supports-color: 5.5.0 - dev: true - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /char-regex@1.0.2: - resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} - engines: {node: '>=10'} - dev: true + char-regex@1.0.2: {} - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + chokidar@3.6.0: dependencies: anymatch: 3.1.3 braces: 3.0.2 @@ -1157,68 +2152,38 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: true - /ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - dev: true + ci-info@3.9.0: {} - /cjs-module-lexer@1.2.3: - resolution: {integrity: sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==} - dev: true + cjs-module-lexer@1.2.3: {} - /cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + cliui@8.0.1: dependencies: string-width: 4.2.3 strip-ansi: 6.0.1 wrap-ansi: 7.0.0 - dev: true - /co@4.6.0: - resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} - engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} - dev: true + co@4.6.0: {} - /collect-v8-coverage@1.0.2: - resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} - dev: true + collect-v8-coverage@1.0.2: {} - /color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@1.9.3: dependencies: color-name: 1.1.3 - dev: true - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - dev: true + color-name@1.1.3: {} - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true + convert-source-map@2.0.0: {} - /create-jest@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): - resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true + create-jest@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 @@ -1232,130 +2197,65 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /create-require@1.1.1: - resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - dev: true + create-require@1.1.1: {} - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + dateformat@3.0.2: {} + + debug@4.3.4: dependencies: ms: 2.1.2 - dev: true - /dedent@1.5.1: - resolution: {integrity: sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==} - peerDependencies: - babel-plugin-macros: ^3.1.0 - peerDependenciesMeta: - babel-plugin-macros: - optional: true - dev: true + dedent@1.5.1: {} - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - dev: true + deepmerge@4.3.1: {} - /detect-newline@3.1.0: - resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} - engines: {node: '>=8'} - dev: true + detect-newline@3.1.0: {} - /diff-sequences@29.6.3: - resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + diff-sequences@29.6.3: {} - /diff@4.0.2: - resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} - engines: {node: '>=0.3.1'} - dev: true + diff@4.0.2: {} - /dotenv-cli@7.4.2: - resolution: {integrity: sha512-SbUj8l61zIbzyhIbg0FwPJq6+wjbzdn9oEtozQpZ6kW2ihCcapKVZj49oCT3oPM+mgQm+itgvUQcG5szxVrZTA==} - hasBin: true + dotenv-cli@7.4.2: dependencies: cross-spawn: 7.0.3 dotenv: 16.4.5 dotenv-expand: 10.0.0 minimist: 1.2.8 - dev: true - /dotenv-expand@10.0.0: - resolution: {integrity: sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==} - engines: {node: '>=12'} - dev: true + dotenv-expand@10.0.0: {} - /dotenv@16.4.5: - resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==} - engines: {node: '>=12'} + dotenv@16.4.5: {} - /dynamic-dedupe@0.3.0: - resolution: {integrity: sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==} + dynamic-dedupe@0.3.0: dependencies: xtend: 4.0.2 - dev: true - /electron-to-chromium@1.4.721: - resolution: {integrity: sha512-k1x2r6foI8iJOp+1qTxbbrrWMsOiHkzGBYwYigaq+apO1FSqtn44KTo3Sy69qt7CRr7149zTcsDvH7MUKsOuIQ==} - dev: true + electron-to-chromium@1.4.721: {} - /emittery@0.13.1: - resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} - engines: {node: '>=12'} - dev: true + emittery@0.13.1: {} - /emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true + emoji-regex@8.0.0: {} - /error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-ex@1.3.2: dependencies: is-arrayish: 0.2.1 - dev: true - /escalade@3.1.2: - resolution: {integrity: sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==} - engines: {node: '>=6'} - dev: true + escalade@3.1.2: {} - /escape-string-regexp@1.0.5: - resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} - engines: {node: '>=0.8.0'} - dev: true + escape-string-regexp@1.0.5: {} - /escape-string-regexp@2.0.0: - resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} - engines: {node: '>=8'} - dev: true + escape-string-regexp@2.0.0: {} - /esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - dev: true + esprima@4.0.1: {} - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + execa@5.1.1: dependencies: cross-spawn: 7.0.3 get-stream: 6.0.1 @@ -1366,94 +2266,52 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: true - /exit@0.1.2: - resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} - engines: {node: '>= 0.8.0'} - dev: true + exit@0.1.2: {} - /expect@29.7.0: - resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + expect@29.7.0: dependencies: '@jest/expect-utils': 29.7.0 jest-get-type: 29.6.3 jest-matcher-utils: 29.7.0 jest-message-util: 29.7.0 jest-util: 29.7.0 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fb-watchman@2.0.2: - resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fb-watchman@2.0.2: dependencies: bser: 2.1.1 - dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + find-up@4.1.0: dependencies: locate-path: 5.0.0 path-exists: 4.0.0 - dev: true - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: true + fsevents@2.3.3: optional: true - /function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: true + function-bind@1.1.2: {} - /gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - dev: true + gensync@1.0.0-beta.2: {} - /get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - dev: true + get-caller-file@2.0.5: {} - /get-package-type@0.1.0: - resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} - engines: {node: '>=8.0.0'} - dev: true + get-package-type@0.1.0: {} - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true + get-stream@6.0.1: {} - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1461,129 +2319,66 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true + globals@11.12.0: {} - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true + graceful-fs@4.2.11: {} - /has-flag@3.0.0: - resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} - engines: {node: '>=4'} - dev: true + has-flag@3.0.0: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hasown@2.0.2: dependencies: function-bind: 1.1.2 - dev: true - /html-escaper@2.0.2: - resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - dev: true + html-escaper@2.0.2: {} - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true + human-signals@2.1.0: {} - /import-local@3.1.0: - resolution: {integrity: sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==} - engines: {node: '>=8'} - hasBin: true + import-local@3.1.0: dependencies: pkg-dir: 4.2.0 resolve-cwd: 3.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + inherits@2.0.4: {} - /is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - dev: true + is-arrayish@0.2.1: {} - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + is-binary-path@2.1.0: dependencies: binary-extensions: 2.3.0 - dev: true - /is-core-module@2.13.1: - resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} + is-core-module@2.13.1: dependencies: hasown: 2.0.2 - dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - dev: true + is-fullwidth-code-point@3.0.0: {} - /is-generator-fn@2.1.0: - resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} - engines: {node: '>=6'} - dev: true + is-generator-fn@2.1.0: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true + is-stream@2.0.1: {} - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /istanbul-lib-coverage@3.2.2: - resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} - engines: {node: '>=8'} - dev: true + istanbul-lib-coverage@3.2.2: {} - /istanbul-lib-instrument@5.2.1: - resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} - engines: {node: '>=8'} + istanbul-lib-instrument@5.2.1: dependencies: '@babel/core': 7.24.3 '@babel/parser': 7.24.1 @@ -1592,11 +2387,8 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-instrument@6.0.2: - resolution: {integrity: sha512-1WUsZ9R1lA0HtBSohTkm39WTPlNKSJ5iFk7UwqXkBLoHQT+hfqPsfsTDVuZdKGaBwn7din9bS7SsnoAr943hvw==} - engines: {node: '>=10'} + istanbul-lib-instrument@6.0.2: dependencies: '@babel/core': 7.24.3 '@babel/parser': 7.24.1 @@ -1605,48 +2397,33 @@ packages: semver: 7.6.0 transitivePeerDependencies: - supports-color - dev: true - /istanbul-lib-report@3.0.1: - resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} - engines: {node: '>=10'} + istanbul-lib-report@3.0.1: dependencies: istanbul-lib-coverage: 3.2.2 make-dir: 4.0.0 supports-color: 7.2.0 - dev: true - /istanbul-lib-source-maps@4.0.1: - resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} - engines: {node: '>=10'} + istanbul-lib-source-maps@4.0.1: dependencies: debug: 4.3.4 istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color - dev: true - /istanbul-reports@3.1.7: - resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} - engines: {node: '>=8'} + istanbul-reports@3.1.7: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - dev: true - /jest-changed-files@29.7.0: - resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-changed-files@29.7.0: dependencies: execa: 5.1.1 jest-util: 29.7.0 p-limit: 3.1.0 - dev: true - /jest-circus@29.7.0: - resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-circus@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/expect': 29.7.0 @@ -1671,17 +2448,8 @@ packages: transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-cli@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): - resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest-cli@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/test-result': 29.7.0 @@ -1699,19 +2467,8 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /jest-config@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): - resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - peerDependencies: - '@types/node': '*' - ts-node: '>=9.0.0' - peerDependenciesMeta: - '@types/node': - optional: true - ts-node: - optional: true + jest-config@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): dependencies: '@babel/core': 7.24.3 '@jest/test-sequencer': 29.7.0 @@ -1740,39 +2497,27 @@ packages: transitivePeerDependencies: - babel-plugin-macros - supports-color - dev: true - /jest-diff@29.7.0: - resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-diff@29.7.0: dependencies: chalk: 4.1.2 diff-sequences: 29.6.3 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-docblock@29.7.0: - resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-docblock@29.7.0: dependencies: detect-newline: 3.1.0 - dev: true - /jest-each@29.7.0: - resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-each@29.7.0: dependencies: '@jest/types': 29.6.3 chalk: 4.1.2 jest-get-type: 29.6.3 jest-util: 29.7.0 pretty-format: 29.7.0 - dev: true - /jest-environment-node@29.7.0: - resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-environment-node@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 @@ -1780,16 +2525,10 @@ packages: '@types/node': 20.11.30 jest-mock: 29.7.0 jest-util: 29.7.0 - dev: true - /jest-get-type@29.6.3: - resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-get-type@29.6.3: {} - /jest-haste-map@29.7.0: - resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-haste-map@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/graceful-fs': 4.1.9 @@ -1804,29 +2543,31 @@ packages: walker: 1.0.8 optionalDependencies: fsevents: 2.3.3 - dev: true - /jest-leak-detector@29.7.0: - resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-html-reporter@3.10.2(jest@29.7.0)(typescript@5.4.3): + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + dateformat: 3.0.2 + jest: 29.7.0(@types/node@20.11.30)(ts-node@10.9.2) + mkdirp: 1.0.4 + strip-ansi: 6.0.1 + typescript: 5.4.3 + xmlbuilder: 15.0.0 + + jest-leak-detector@29.7.0: dependencies: jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-matcher-utils@29.7.0: - resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-matcher-utils@29.7.0: dependencies: chalk: 4.1.2 jest-diff: 29.7.0 jest-get-type: 29.6.3 pretty-format: 29.7.0 - dev: true - /jest-message-util@29.7.0: - resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-message-util@29.7.0: dependencies: '@babel/code-frame': 7.24.2 '@jest/types': 29.6.3 @@ -1837,47 +2578,27 @@ packages: pretty-format: 29.7.0 slash: 3.0.0 stack-utils: 2.0.6 - dev: true - /jest-mock@29.7.0: - resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-mock@29.7.0: dependencies: - '@jest/types': 29.6.3 - '@types/node': 20.11.30 - jest-util: 29.7.0 - dev: true - - /jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): - resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} - engines: {node: '>=6'} - peerDependencies: - jest-resolve: '*' - peerDependenciesMeta: - jest-resolve: - optional: true + '@jest/types': 29.6.3 + '@types/node': 20.11.30 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): dependencies: jest-resolve: 29.7.0 - dev: true - /jest-regex-util@29.6.3: - resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - dev: true + jest-regex-util@29.6.3: {} - /jest-resolve-dependencies@29.7.0: - resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve-dependencies@29.7.0: dependencies: jest-regex-util: 29.6.3 jest-snapshot: 29.7.0 transitivePeerDependencies: - supports-color - dev: true - /jest-resolve@29.7.0: - resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-resolve@29.7.0: dependencies: chalk: 4.1.2 graceful-fs: 4.2.11 @@ -1888,11 +2609,8 @@ packages: resolve: 1.22.8 resolve.exports: 2.0.2 slash: 3.0.0 - dev: true - /jest-runner@29.7.0: - resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runner@29.7.0: dependencies: '@jest/console': 29.7.0 '@jest/environment': 29.7.0 @@ -1917,11 +2635,8 @@ packages: source-map-support: 0.5.13 transitivePeerDependencies: - supports-color - dev: true - /jest-runtime@29.7.0: - resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-runtime@29.7.0: dependencies: '@jest/environment': 29.7.0 '@jest/fake-timers': 29.7.0 @@ -1947,11 +2662,8 @@ packages: strip-bom: 4.0.0 transitivePeerDependencies: - supports-color - dev: true - /jest-snapshot@29.7.0: - resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-snapshot@29.7.0: dependencies: '@babel/core': 7.24.3 '@babel/generator': 7.24.1 @@ -1975,11 +2687,8 @@ packages: semver: 7.6.0 transitivePeerDependencies: - supports-color - dev: true - /jest-util@29.7.0: - resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-util@29.7.0: dependencies: '@jest/types': 29.6.3 '@types/node': 20.11.30 @@ -1987,11 +2696,8 @@ packages: ci-info: 3.9.0 graceful-fs: 4.2.11 picomatch: 2.3.1 - dev: true - /jest-validate@29.7.0: - resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-validate@29.7.0: dependencies: '@jest/types': 29.6.3 camelcase: 6.3.0 @@ -1999,11 +2705,8 @@ packages: jest-get-type: 29.6.3 leven: 3.1.0 pretty-format: 29.7.0 - dev: true - /jest-watcher@29.7.0: - resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-watcher@29.7.0: dependencies: '@jest/test-result': 29.7.0 '@jest/types': 29.6.3 @@ -2013,27 +2716,15 @@ packages: emittery: 0.13.1 jest-util: 29.7.0 string-length: 4.0.2 - dev: true - /jest-worker@29.7.0: - resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jest-worker@29.7.0: dependencies: '@types/node': 20.11.30 jest-util: 29.7.0 merge-stream: 2.0.0 supports-color: 8.1.1 - dev: true - /jest@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): - resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - hasBin: true - peerDependencies: - node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 - peerDependenciesMeta: - node-notifier: - optional: true + jest@29.7.0(@types/node@20.11.30)(ts-node@10.9.2): dependencies: '@jest/core': 29.7.0(ts-node@10.9.2) '@jest/types': 29.6.3 @@ -2044,508 +2735,261 @@ packages: - babel-plugin-macros - supports-color - ts-node - dev: true - /js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true + js-tokens@4.0.0: {} - /js-yaml@3.14.1: - resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} - hasBin: true + js-yaml@3.14.1: dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: true - /jsesc@2.5.2: - resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} - engines: {node: '>=4'} - hasBin: true - dev: true + jsesc@2.5.2: {} - /json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} - dev: true + json-parse-even-better-errors@2.3.1: {} - /json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - dev: true + json5@2.2.3: {} - /jsonc-parser@3.2.1: - resolution: {integrity: sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==} - dev: true + jsonc-parser@3.2.1: {} - /kleur@3.0.3: - resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} - engines: {node: '>=6'} - dev: true + kleur@3.0.3: {} - /leven@3.1.0: - resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} - engines: {node: '>=6'} - dev: true + leven@3.1.0: {} - /lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: true + lines-and-columns@1.2.4: {} - /locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + locate-path@5.0.0: dependencies: p-locate: 4.1.0 - dev: true - /lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - dev: true + lodash.memoize@4.1.2: {} - /lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 - dev: true - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - dev: true - /make-dir@4.0.0: - resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} - engines: {node: '>=10'} + make-dir@4.0.0: dependencies: semver: 7.6.0 - dev: true - /make-error@1.3.6: - resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - dev: true + make-error@1.3.6: {} - /makeerror@1.0.12: - resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + makeerror@1.0.12: dependencies: tmpl: 1.0.5 - dev: true - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true + merge-stream@2.0.0: {} - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.5: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true + mimic-fn@2.1.0: {} - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimist@1.2.8: {} - /mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - dev: true + mkdirp@1.0.4: {} - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true + ms@2.1.2: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /node-int64@0.4.0: - resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - dev: true + node-int64@0.4.0: {} - /node-releases@2.0.14: - resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true + node-releases@2.0.14: {} - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-path@3.0.0: {} - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + npm-run-path@4.0.1: dependencies: path-key: 3.1.1 - dev: true - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + onetime@5.1.2: dependencies: mimic-fn: 2.1.0 - dev: true - /p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + p-limit@2.3.0: dependencies: p-try: 2.2.0 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + p-locate@4.1.0: dependencies: p-limit: 2.3.0 - dev: true - /p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - dev: true + p-try@2.2.0: {} - /parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + parse-json@5.2.0: dependencies: '@babel/code-frame': 7.24.2 error-ex: 1.3.2 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 - dev: true - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: true + picocolors@1.0.0: {} - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /pirates@4.0.6: - resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} - engines: {node: '>= 6'} - dev: true + pirates@4.0.6: {} - /pkg-dir@4.2.0: - resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} - engines: {node: '>=8'} + pkg-dir@4.2.0: dependencies: find-up: 4.1.0 - dev: true - /pretty-format@29.7.0: - resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} - engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + pretty-format@29.7.0: dependencies: '@jest/schemas': 29.6.3 ansi-styles: 5.2.0 react-is: 18.2.0 - dev: true - /prompts@2.4.2: - resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} - engines: {node: '>= 6'} + prompts@2.4.2: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - dev: true - /pure-rand@6.1.0: - resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} - dev: true + pure-rand@6.1.0: {} - /react-is@18.2.0: - resolution: {integrity: sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==} - dev: true + react-is@18.2.0: {} - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + readdirp@3.6.0: dependencies: picomatch: 2.3.1 - dev: true - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /resolve-cwd@3.0.0: - resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} - engines: {node: '>=8'} + resolve-cwd@3.0.0: dependencies: resolve-from: 5.0.0 - dev: true - /resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} - dev: true + resolve-from@5.0.0: {} - /resolve.exports@2.0.2: - resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} - engines: {node: '>=10'} - dev: true + resolve.exports@2.0.2: {} - /resolve@1.22.8: - resolution: {integrity: sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==} - hasBin: true + resolve@1.22.8: dependencies: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true + rimraf@2.7.1: dependencies: glob: 7.2.3 - dev: true - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.6.0: - resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} - engines: {node: '>=10'} - hasBin: true + semver@7.6.0: dependencies: lru-cache: 6.0.0 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true + signal-exit@3.0.7: {} - /sisteransi@1.0.5: - resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true + sisteransi@1.0.5: {} - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /source-map-support@0.5.13: - resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + source-map-support@0.5.13: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map-support@0.5.21: dependencies: buffer-from: 1.1.2 source-map: 0.6.1 - dev: true - /source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - dev: true + source-map@0.6.1: {} - /sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - dev: true + sprintf-js@1.0.3: {} - /stack-utils@2.0.6: - resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} - engines: {node: '>=10'} + stack-utils@2.0.6: dependencies: escape-string-regexp: 2.0.0 - dev: true - /string-length@4.0.2: - resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} - engines: {node: '>=10'} + string-length@4.0.2: dependencies: char-regex: 1.0.2 strip-ansi: 6.0.1 - dev: true - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true + strip-bom@3.0.0: {} - /strip-bom@4.0.0: - resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} - engines: {node: '>=8'} - dev: true + strip-bom@4.0.0: {} - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true + strip-final-newline@2.0.0: {} - /strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - dev: true + strip-json-comments@2.0.1: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /supports-color@5.5.0: - resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} - engines: {node: '>=4'} + supports-color@5.5.0: dependencies: has-flag: 3.0.0 - dev: true - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@6.0.0: dependencies: '@istanbuljs/schema': 0.1.3 glob: 7.2.3 minimatch: 3.1.2 - dev: true - /tmpl@1.0.5: - resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - dev: true + tmpl@1.0.5: {} - /to-fast-properties@2.0.0: - resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} - engines: {node: '>=4'} - dev: true + to-fast-properties@2.0.0: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true + tree-kill@1.2.2: {} - /ts-jest@29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3): - resolution: {integrity: sha512-br6GJoH/WUX4pu7FbZXuWGKGNDuU7b8Uj77g/Sp7puZV6EXzuByl6JrECvm0MzVzSTkSHWTihsXt+5XYER5b+g==} - engines: {node: ^16.10.0 || ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@babel/core': '>=7.0.0-beta.0 <8' - '@jest/types': ^29.0.0 - babel-jest: ^29.0.0 - esbuild: '*' - jest: ^29.0.0 - typescript: '>=4.3 <6' - peerDependenciesMeta: - '@babel/core': - optional: true - '@jest/types': - optional: true - babel-jest: - optional: true - esbuild: - optional: true + ts-jest@29.1.2(@babel/core@7.24.3)(jest@29.7.0)(typescript@5.4.3): dependencies: '@babel/core': 7.24.3 bs-logger: 0.2.6 @@ -2558,18 +3002,8 @@ packages: semver: 7.6.0 typescript: 5.4.3 yargs-parser: 21.1.1 - dev: true - /ts-node-dev@2.0.0(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3): - resolution: {integrity: sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==} - engines: {node: '>=0.8.0'} - hasBin: true - peerDependencies: - node-notifier: '*' - typescript: '*' - peerDependenciesMeta: - node-notifier: - optional: true + ts-node-dev@2.0.0(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3): dependencies: chokidar: 3.6.0 dynamic-dedupe: 0.3.0 @@ -2586,21 +3020,8 @@ packages: - '@swc/core' - '@swc/wasm' - '@types/node' - dev: true - /ts-node@10.9.2(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3): - resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true + ts-node@10.9.2(@swc/core@1.5.7)(@types/node@20.11.30)(typescript@5.4.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@swc/core': 1.5.7 @@ -2618,122 +3039,70 @@ packages: typescript: 5.4.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: true - /tsconfig@7.0.0: - resolution: {integrity: sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==} + tsconfig@7.0.0: dependencies: '@types/strip-bom': 3.0.0 '@types/strip-json-comments': 0.0.30 strip-bom: 3.0.0 strip-json-comments: 2.0.1 - dev: true - /type-detect@4.0.8: - resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} - engines: {node: '>=4'} - dev: true + type-detect@4.0.8: {} - /type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - dev: true + type-fest@0.21.3: {} - /typescript@5.4.3: - resolution: {integrity: sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==} - engines: {node: '>=14.17'} - hasBin: true - dev: true + typescript@5.4.3: {} - /undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: true + undici-types@5.26.5: {} - /update-browserslist-db@1.0.13(browserslist@4.23.0): - resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.0.13(browserslist@4.23.0): dependencies: browserslist: 4.23.0 escalade: 3.1.2 picocolors: 1.0.0 - dev: true - /v8-compile-cache-lib@3.0.1: - resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - dev: true + v8-compile-cache-lib@3.0.1: {} - /v8-to-istanbul@9.2.0: - resolution: {integrity: sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA==} - engines: {node: '>=10.12.0'} + v8-to-istanbul@9.2.0: dependencies: '@jridgewell/trace-mapping': 0.3.25 '@types/istanbul-lib-coverage': 2.0.6 convert-source-map: 2.0.0 - dev: true - /walker@1.0.8: - resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + walker@1.0.8: dependencies: makeerror: 1.0.12 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /write-file-atomic@4.0.2: - resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + write-file-atomic@4.0.2: dependencies: imurmurhash: 0.1.4 signal-exit: 3.0.7 - dev: true - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: true + xmlbuilder@15.0.0: {} - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + xtend@4.0.2: {} - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true + y18n@5.0.8: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@3.1.1: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yallist@4.0.0: {} - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs-parser@21.1.1: {} + + yargs@17.7.2: dependencies: cliui: 8.0.1 escalade: 3.1.2 @@ -2742,14 +3111,7 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - /yn@3.1.1: - resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} - engines: {node: '>=6'} - dev: true + yn@3.1.1: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} diff --git a/integ-tests/typescript/test-report.html b/integ-tests/typescript/test-report.html new file mode 100644 index 000000000..885a7269d --- /dev/null +++ b/integ-tests/typescript/test-report.html @@ -0,0 +1,281 @@ +Test Report

Test Report

Started: 2024-07-24 09:24:04
Suites (1)
0 passed
1 failed
0 pending
Tests (39)
35 passed
4 failed
0 pending
Integ tests > should work for all inputs
single bool
failed
0.004s
Error: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Return this value back to me: true")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721838244, tv_nsec: 940582000 }, latency: 527.833µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+
+    at BamlAsyncClient.parsed [as TestFnNamedArgsSingleBool] (/Users/sam/baml3/integ-tests/typescript/baml_client/async_client.ts:842:16)
+    at Object.<anonymous> (/Users/sam/baml3/integ-tests/typescript/tests/integ-tests.test.ts:28:19)
Integ tests > should work for all inputs
single string list
passed
0.499s
Integ tests > should work for all inputs
single class
passed
0.425s
Integ tests > should work for all inputs
multiple classes
passed
0.536s
Integ tests > should work for all inputs
single enum list
passed
0.35s
Integ tests > should work for all inputs
single float
passed
0.482s
Integ tests > should work for all inputs
single int
passed
0.4s
Integ tests > should work for all inputs
single optional string
passed
0.328s
Integ tests > should work for all inputs
single map string to string
passed
0.582s
Integ tests > should work for all inputs
single map string to class
passed
0.559s
Integ tests > should work for all inputs
single map string to map
passed
0.58s
Integ tests
should work for all outputs
passed
3.29s
Integ tests
works with retries1
passed
0.688s
Integ tests
works with retries2
passed
1.802s
Integ tests
works with fallbacks
passed
1.5s
Integ tests
should work with image from url
failed
5.002s
Error: thrown: "Exceeded timeout of 5000 ms for a test.
+Add a timeout value to this test to increase the timeout, if this is a long-running test. See https://jestjs.io/docs/api#testname-fn-timeout."
+    at it (/Users/sam/baml3/integ-tests/typescript/tests/integ-tests.test.ts:150:3)
+    at _dispatchDescribe (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:91:26)
+    at describe (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/index.js:55:5)
+    at Object.describe (/Users/sam/baml3/integ-tests/typescript/tests/integ-tests.test.ts:25:1)
+    at Runtime._execModule (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1439:24)
+    at Runtime._loadModule (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:1022:12)
+    at Runtime.requireModule (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-runtime@29.7.0/node_modules/jest-runtime/build/index.js:882:12)
+    at jestAdapter (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-circus@29.7.0/node_modules/jest-circus/build/legacy-code-todo-rewrite/jestAdapter.js:77:13)
+    at processTicksAndRejections (node:internal/process/task_queues:95:5)
+    at runTestInternal (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:367:16)
+    at runTest (/Users/sam/baml3/integ-tests/typescript/node_modules/.pnpm/jest-runner@29.7.0/node_modules/jest-runner/build/runTest.js:444:34)
Integ tests
should work with image from base 64
passed
1.209s
Integ tests
should work with audio base 64
passed
0.879s
Integ tests
should work with audio from url
passed
0.941s
Integ tests
should support streaming in OpenAI
passed
3.237s
Integ tests
should support streaming in Gemini
passed
10.647s
Integ tests
should support AWS
passed
2.154s
Integ tests
should support streaming in AWS
passed
2.356s
Integ tests
should support streaming without iterating
passed
4.436s
Integ tests
should support streaming in Claude
passed
0.728s
Integ tests
should support vertex
failed
0.017s
Error: LLM call failed: LLMErrorResponse { client: "Vertex", model: None, prompt: Chat([RenderedChatMessage { role: "user", parts: [Text("Write a nice short story about Donkey Kong")] }]), request_options: {}, start_time: SystemTime { tv_sec: 1721838288, tv_nsec: 590382000 }, latency: 76.291µs, message: "Failed to build request\n\nCaused by:\n    Service account not found", code: Other(2) }
+
+    at BamlAsyncClient.parsed [as TestVertex] (/Users/sam/baml3/integ-tests/typescript/baml_client/async_client.ts:1130:16)
+    at Object.<anonymous> (/Users/sam/baml3/integ-tests/typescript/tests/integ-tests.test.ts:262:17)
Integ tests
supports tracing sync
passed
0.051s
Integ tests
supports tracing async
passed
3.72s
Integ tests
should work with dynamic types single
passed
1.207s
Integ tests
should work with dynamic types enum
passed
0.983s
Integ tests
should work with dynamic types class
passed
0.906s
Integ tests
should work with dynamic inputs class
passed
0.53s
Integ tests
should work with dynamic inputs list
passed
0.805s
Integ tests
should work with dynamic output map
passed
1.193s
Integ tests
should work with dynamic output union
passed
2.084s
Integ tests
should work with nested classes
failed
0.102s
Error: LLM call failed: LLMErrorResponse { client: "Ollama", model: None, prompt: Chat([RenderedChatMessage { role: "system", parts: [Text("Return a made up json blob that matches this schema:\nAnswer in JSON using this schema:\n{\n  prop1: string,\n  prop2: {\n    prop1: string,\n    prop2: string,\n    inner: {\n      prop2: int,\n      prop3: float,\n    },\n  },\n}\n---\n\nJSON:")] }]), request_options: {"model": String("llama2")}, start_time: SystemTime { tv_sec: 1721838300, tv_nsec: 80345000 }, latency: 2.701958ms, message: "reqwest::Error { kind: Request, url: Url { scheme: \"http\", cannot_be_a_base: false, username: \"\", password: None, host: Some(Domain(\"localhost\")), port: Some(11434), path: \"/v1/chat/completions\", query: None, fragment: None }, source: hyper_util::client::legacy::Error(Connect, ConnectError(\"tcp connect error\", Os { code: 61, kind: ConnectionRefused, message: \"Connection refused\" })) }", code: Other(2) }
+
+    at BamlStream.parsed [as getFinalResponse] (/Users/sam/baml3/engine/language_client_typescript/stream.js:58:39)
+    at Object.<anonymous> (/Users/sam/baml3/integ-tests/typescript/tests/integ-tests.test.ts:502:19)
Integ tests
should work with dynamic client
passed
0.488s
Integ tests
should work with 'onLogEvent'
passed
1.855s
Integ tests
should work with a sync client
passed
0.39s
\ No newline at end of file diff --git a/integ-tests/typescript/tests/integ-tests.test.ts b/integ-tests/typescript/tests/integ-tests.test.ts index bcc76d26c..4fb449b6a 100644 --- a/integ-tests/typescript/tests/integ-tests.test.ts +++ b/integ-tests/typescript/tests/integ-tests.test.ts @@ -421,6 +421,74 @@ describe('Integ tests', () => { expect(res[0]['testKey']).toEqual('myTest') }) + it('should work with dynamic output map', async () => { + let tb = new TypeBuilder() + tb.DynamicOutput.addProperty('hair_color', tb.string()) + tb.DynamicOutput.addProperty('attributes', tb.map(tb.string(), tb.string())).description( + "Things like 'eye_color' or 'facial_hair'", + ) + console.log(tb.DynamicOutput.listProperties()) + for (const [prop, _] of tb.DynamicOutput.listProperties()) { + console.log(`Property: ${prop}`) + } + + const res = await b.MyFunc( + "My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard.", + { tb }, + ) + + console.log('final ', res) + + expect(res.hair_color).toEqual('black') + expect(res.attributes['eye_color']).toEqual('blue') + expect(res.attributes['facial_hair']).toEqual('beard') + }) + + it('should work with dynamic output union', async () => { + let tb = new TypeBuilder() + tb.DynamicOutput.addProperty('hair_color', tb.string()) + tb.DynamicOutput.addProperty('attributes', tb.map(tb.string(), tb.string())).description( + "Things like 'eye_color' or 'facial_hair'", + ) + + // Define two classes + const class1 = tb.addClass('Class1') + class1.addProperty('meters', tb.float()) + + const class2 = tb.addClass('Class2') + class2.addProperty('feet', tb.float()) + class2.addProperty('inches', tb.float().optional()) + + // Use the classes in a union property + tb.DynamicOutput.addProperty('height', tb.union([class1.type(), class2.type()])) + console.log(tb.DynamicOutput.listProperties()) + for (const [prop, _] of tb.DynamicOutput.listProperties()) { + console.log(`Property: ${prop}`) + } + + let res = await b.MyFunc( + "My name is Harrison. My hair is black and I'm 6 feet tall. I have blue eyes and a beard. I am 30 years old.", + { tb }, + ) + + console.log('final ', res) + expect(res.hair_color).toEqual('black') + expect(res.attributes['eye_color']).toEqual('blue') + expect(res.attributes['facial_hair']).toEqual('beard') + expect(res.height['feet']).toEqual(6) + + res = await b.MyFunc( + "My name is Harrison. My hair is black and I'm 1.8 meters tall. I have blue eyes and a beard. I am 30 years old.", + { tb }, + ) + + console.log('final ', res) + expect(res.hair_color).toEqual('black') + expect(res.attributes['eye_color']).toEqual('blue') + expect(res.attributes['facial_hair']).toEqual('beard') + expect(res.height['meters']).toEqual(1.8) + }) + // test with extra list, boolean in the input as well. it('should work with nested classes', async () => { @@ -443,9 +511,10 @@ describe('Integ tests', () => { }) clientRegistry.setPrimary('myClient') - await b.TestOllama('hi', { + const capitol = await b.ExpectFailure({ clientRegistry, }) + expect(capitol.toLowerCase()).toContain('london') }) it("should work with 'onLogEvent'", async () => {