From 31e275eb961761f0dac23c27fe6f2ba12fbbb4c4 Mon Sep 17 00:00:00 2001 From: hellovai Date: Thu, 13 Jun 2024 17:26:13 -0700 Subject: [PATCH] Adding recursive defintions for nested classes (when streaming for partials). (#676) * Added some unit tests in all languages to ensure this continues to work --- .../src/python/generate_types.rs | 24 +- .../src/typescript/mod.rs | 90 ++--- .../src/typescript/templates/client.js.j2 | 12 +- integ-tests/baml_src/clients.baml | 1 - .../functions/output/class-nested.baml | 33 ++ .../test-files/functions/output/class.baml | 20 +- integ-tests/python/baml_client/client.py | 40 +- integ-tests/python/baml_client/inlinedbaml.py | 5 +- .../python/baml_client/partial_types.py | 36 +- .../python/baml_client/type_builder.py | 2 +- integ-tests/python/baml_client/types.py | 24 +- integ-tests/python/test_functions.py | 14 +- integ-tests/ruby/baml_client/client.rb | 28 +- integ-tests/ruby/baml_client/inlined.rb | 5 +- integ-tests/ruby/baml_client/partial-types.rb | 26 +- integ-tests/ruby/baml_client/types.rb | 26 +- integ-tests/ruby/test_functions.rb | 14 + integ-tests/typescript/baml_client/client.ts | 372 +++++++++--------- .../typescript/baml_client/inlinedbaml.ts | 5 +- .../typescript/baml_client/type_builder.ts | 2 +- integ-tests/typescript/baml_client/types.ts | 24 +- .../typescript/tests/integ-tests.test.ts | 16 +- 22 files changed, 477 insertions(+), 342 deletions(-) create mode 100644 integ-tests/baml_src/test-files/functions/output/class-nested.baml diff --git a/engine/language-client-codegen/src/python/generate_types.rs b/engine/language-client-codegen/src/python/generate_types.rs index 99bb0dba8..85877f381 100644 --- a/engine/language-client-codegen/src/python/generate_types.rs +++ b/engine/language-client-codegen/src/python/generate_types.rs @@ -140,7 +140,7 @@ impl<'ir> From> for PartialPythonClass<'ir> { f.elem.name.as_str(), add_default_value( &f.elem.r#type.elem, - &f.elem.r#type.elem.to_partial_type_ref(&c.db), + &f.elem.r#type.elem.to_partial_type_ref(&c.db, false), ), ) }) @@ -159,7 +159,7 @@ pub fn add_default_value(node: &FieldType, type_str: &String) -> String { trait ToTypeReferenceInTypeDefinition { fn to_type_ref(&self, ir: &IntermediateRepr) -> String; - fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String; + fn to_partial_type_ref(&self, ir: &IntermediateRepr, wrapped: bool) -> String; } impl ToTypeReferenceInTypeDefinition for FieldType { @@ -202,9 +202,15 @@ impl ToTypeReferenceInTypeDefinition for FieldType { } } - fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String { + fn to_partial_type_ref(&self, ir: &IntermediateRepr, wrapped: bool) -> String { match self { - FieldType::Class(name) => format!("\"{name}\""), + FieldType::Class(name) => { + if wrapped { + format!("\"{name}\"") + } else { + format!("Optional[\"{name}\"]") + } + } FieldType::Enum(name) => { if ir .find_enum(name) @@ -216,12 +222,12 @@ impl ToTypeReferenceInTypeDefinition for FieldType { format!("Optional[types.{name}]") } } - FieldType::List(inner) => format!("List[{}]", inner.to_partial_type_ref(ir)), + FieldType::List(inner) => format!("List[{}]", inner.to_partial_type_ref(ir, true)), FieldType::Map(key, value) => { format!( "Dict[{}, {}]", key.to_type_ref(ir), - value.to_partial_type_ref(ir) + value.to_partial_type_ref(ir, false) ) } FieldType::Primitive(r#type) => format!("Optional[{}]", r#type.to_python()), @@ -229,7 +235,7 @@ impl ToTypeReferenceInTypeDefinition for FieldType { "Optional[Union[{}]]", inner .iter() - .map(|t| t.to_partial_type_ref(ir)) + .map(|t| t.to_partial_type_ref(ir, true)) .collect::>() .join(", ") ), @@ -237,11 +243,11 @@ impl ToTypeReferenceInTypeDefinition for FieldType { "Optional[Tuple[{}]]", inner .iter() - .map(|t| t.to_partial_type_ref(ir)) + .map(|t| t.to_partial_type_ref(ir, false)) .collect::>() .join(", ") ), - FieldType::Optional(inner) => inner.to_partial_type_ref(ir), + FieldType::Optional(inner) => inner.to_partial_type_ref(ir, false), } } } diff --git a/engine/language-client-codegen/src/typescript/mod.rs b/engine/language-client-codegen/src/typescript/mod.rs index 5dc374351..64da56fa3 100644 --- a/engine/language-client-codegen/src/typescript/mod.rs +++ b/engine/language-client-codegen/src/typescript/mod.rs @@ -19,7 +19,7 @@ struct TypescriptClient { } struct TypescriptFunction { name: String, - partial_return_type: String, + // partial_return_type: String, return_type: String, args: Vec<(String, bool, String)>, } @@ -76,7 +76,7 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for TypescriptCli Ok(TypescriptFunction { 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), + // 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 @@ -144,52 +144,52 @@ impl TryFrom<(&'_ IntermediateRepr, &'_ crate::GeneratorArgs)> for TypescriptIni trait ToTypeReferenceInClientDefinition { fn to_type_ref(&self, ir: &IntermediateRepr) -> String; - fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String; + // fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String; } impl ToTypeReferenceInClientDefinition for FieldType { - fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String { - match self { - FieldType::Enum(name) => { - if ir - .find_enum(name) - .map(|e| e.item.attributes.get("dynamic_type").is_some()) - .unwrap_or(false) - { - format!("(string | {name} | null)") - } else { - format!("({name} | null)") - } - } - FieldType::Class(name) => format!("(Partial<{name}> | null)"), - FieldType::List(inner) => format!("{}[]", inner.to_partial_type_ref(ir)), - FieldType::Map(key, value) => { - format!( - "(Record<{}, {}> | null)", - key.to_type_ref(ir), - value.to_partial_type_ref(ir) - ) - } - FieldType::Primitive(r#type) => format!("({} | null)", r#type.to_typescript()), - FieldType::Union(inner) => format!( - "({} | null)", - inner - .iter() - .map(|t| t.to_partial_type_ref(ir)) - .collect::>() - .join(" | ") - ), - FieldType::Tuple(inner) => format!( - "([{}] | null)", - inner - .iter() - .map(|t| t.to_partial_type_ref(ir)) - .collect::>() - .join(", ") - ), - FieldType::Optional(inner) => format!("({} | null)", inner.to_partial_type_ref(ir)), - } - } + // fn to_partial_type_ref(&self, ir: &IntermediateRepr) -> String { + // match self { + // FieldType::Enum(name) => { + // if ir + // .find_enum(name) + // .map(|e| e.item.attributes.get("dynamic_type").is_some()) + // .unwrap_or(false) + // { + // format!("(string | {name} | null)") + // } else { + // format!("({name} | null)") + // } + // } + // FieldType::Class(name) => format!("(RecursivePartialNull<{name}>)"), + // FieldType::List(inner) => format!("{}[]", inner.to_partial_type_ref(ir)), + // FieldType::Map(key, value) => { + // format!( + // "(Record<{}, {}> | null)", + // key.to_type_ref(ir), + // value.to_partial_type_ref(ir) + // ) + // } + // FieldType::Primitive(r#type) => format!("({} | null)", r#type.to_typescript()), + // FieldType::Union(inner) => format!( + // "({} | null)", + // inner + // .iter() + // .map(|t| t.to_partial_type_ref(ir)) + // .collect::>() + // .join(" | ") + // ), + // FieldType::Tuple(inner) => format!( + // "([{}] | null)", + // inner + // .iter() + // .map(|t| t.to_partial_type_ref(ir)) + // .collect::>() + // .join(", ") + // ), + // FieldType::Optional(inner) => format!("({} | null)", inner.to_partial_type_ref(ir)), + // } + // } fn to_type_ref(&self, ir: &IntermediateRepr) -> String { match self { diff --git a/engine/language-client-codegen/src/typescript/templates/client.js.j2 b/engine/language-client-codegen/src/typescript/templates/client.js.j2 index 866a9bfbf..4982c5809 100644 --- a/engine/language-client-codegen/src/typescript/templates/client.js.j2 +++ b/engine/language-client-codegen/src/typescript/templates/client.js.j2 @@ -4,6 +4,12 @@ import { } from "./types" import TypeBuilder from "./type_builder" +export type RecursivePartialNull = T extends object + ? { + [P in keyof T]?: RecursivePartialNull; + } + : T | null; + export class BamlClient { private stream_client: BamlStreamClient @@ -46,7 +52,7 @@ class BamlStreamClient { {{name}}{% if optional %}?{% endif %}: {{type}}, {%- endfor %} __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<{{ fn.partial_return_type }}, {{ fn.return_type }}> { + ): BamlStream, {{ fn.return_type }}> { const raw = this.runtime.streamFunction( "{{fn.name}}", { @@ -58,9 +64,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<{{ fn.partial_return_type }}, {{ fn.return_type }}>( + return new BamlStream, {{ fn.return_type }}>( raw, - (a): a is {{ fn.partial_return_type }} => a, + (a): a is RecursivePartialNull<{{ fn.return_type }}> => a, (a): a is {{ fn.return_type }} => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), diff --git a/integ-tests/baml_src/clients.baml b/integ-tests/baml_src/clients.baml index 57e7c9eec..8a21b61a3 100644 --- a/integ-tests/baml_src/clients.baml +++ b/integ-tests/baml_src/clients.baml @@ -52,7 +52,6 @@ client Ollama { provider ollama options { model llama2 - api_key "" } } diff --git a/integ-tests/baml_src/test-files/functions/output/class-nested.baml b/integ-tests/baml_src/test-files/functions/output/class-nested.baml new file mode 100644 index 000000000..a88d9805e --- /dev/null +++ b/integ-tests/baml_src/test-files/functions/output/class-nested.baml @@ -0,0 +1,33 @@ +class TestClassNested { + prop1 string + prop2 InnerClass +} + +class InnerClass { + prop1 string + prop2 string + inner InnerClass2 +} + +class InnerClass2 { + prop2 int + prop3 float +} + +function FnOutputClassNested(input: string) -> TestClassNested { + client Ollama + prompt #" + Return a made up json blob that matches this schema: + {{ctx.output_format}} + --- + + JSON: + "# +} + +test FnOutputClassNested { + functions [FnOutputClassNested] + args { + input "example input" + } +} diff --git a/integ-tests/baml_src/test-files/functions/output/class.baml b/integ-tests/baml_src/test-files/functions/output/class.baml index edc3586ab..880325155 100644 --- a/integ-tests/baml_src/test-files/functions/output/class.baml +++ b/integ-tests/baml_src/test-files/functions/output/class.baml @@ -16,26 +16,8 @@ function FnOutputClass(input: string) -> TestOutputClass { } test TestClass { - functions [FnOutputClass, FnOutputNestedClass] + functions [FnOutputClass] args { input "example input" } } - - - -class TestOutputClassNested { - prop1 string - prop2 int - prop3 TestOutputClass -} - -function FnOutputNestedClass(input: string) -> TestOutputClassNested { - client GPT35 - prompt #" - Return a JSON blob with this schema: - {{ctx.output_format}} - - JSON: - "# -} \ No newline at end of file diff --git a/integ-tests/python/baml_client/client.py b/integ-tests/python/baml_client/client.py index c3aa4bb0a..1d5659e6a 100644 --- a/integ-tests/python/baml_client/client.py +++ b/integ-tests/python/baml_client/client.py @@ -495,11 +495,11 @@ async def FnOutputClassList( mdl = create_model("FnOutputClassListReturnType", inner=(List[types.TestOutputClass], ...)) return coerce(mdl, raw.parsed()) - async def FnOutputClassWithEnum( + async def FnOutputClassNested( self, input: str, baml_options: BamlCallOptions = {}, - ) -> types.TestClassWithEnum: + ) -> types.TestClassNested: __tb__ = baml_options.get("tb", None) if __tb__ is not None: tb = __tb__._tb @@ -507,21 +507,21 @@ async def FnOutputClassWithEnum( tb = None raw = await self.__runtime.call_function( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input": input, }, self.__ctx_manager.get(), tb, ) - mdl = create_model("FnOutputClassWithEnumReturnType", inner=(types.TestClassWithEnum, ...)) + mdl = create_model("FnOutputClassNestedReturnType", inner=(types.TestClassNested, ...)) return coerce(mdl, raw.parsed()) - async def FnOutputNestedClass( + async def FnOutputClassWithEnum( self, input: str, baml_options: BamlCallOptions = {}, - ) -> types.TestOutputClassNested: + ) -> types.TestClassWithEnum: __tb__ = baml_options.get("tb", None) if __tb__ is not None: tb = __tb__._tb @@ -529,14 +529,14 @@ async def FnOutputNestedClass( tb = None raw = await self.__runtime.call_function( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input": input, }, self.__ctx_manager.get(), tb, ) - mdl = create_model("FnOutputNestedClassReturnType", inner=(types.TestOutputClassNested, ...)) + mdl = create_model("FnOutputClassWithEnumReturnType", inner=(types.TestClassWithEnum, ...)) return coerce(mdl, raw.parsed()) async def FnOutputStringList( @@ -1941,11 +1941,11 @@ def FnOutputClassList( tb, ) - def FnOutputClassWithEnum( + def FnOutputClassNested( self, input: str, baml_options: BamlCallOptions = {}, - ) -> baml_py.BamlStream[partial_types.TestClassWithEnum, types.TestClassWithEnum]: + ) -> baml_py.BamlStream[partial_types.TestClassNested, types.TestClassNested]: __tb__ = baml_options.get("tb", None) if __tb__ is not None: tb = __tb__._tb @@ -1953,7 +1953,7 @@ def FnOutputClassWithEnum( tb = None raw = self.__runtime.stream_function( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input": input, }, @@ -1962,10 +1962,10 @@ def FnOutputClassWithEnum( tb, ) - mdl = create_model("FnOutputClassWithEnumReturnType", inner=(types.TestClassWithEnum, ...)) - partial_mdl = create_model("FnOutputClassWithEnumPartialReturnType", inner=(partial_types.TestClassWithEnum, ...)) + mdl = create_model("FnOutputClassNestedReturnType", inner=(types.TestClassNested, ...)) + partial_mdl = create_model("FnOutputClassNestedPartialReturnType", inner=(partial_types.TestClassNested, ...)) - return baml_py.BamlStream[partial_types.TestClassWithEnum, types.TestClassWithEnum]( + return baml_py.BamlStream[partial_types.TestClassNested, types.TestClassNested]( raw, lambda x: coerce(partial_mdl, x), lambda x: coerce(mdl, x), @@ -1973,11 +1973,11 @@ def FnOutputClassWithEnum( tb, ) - def FnOutputNestedClass( + def FnOutputClassWithEnum( self, input: str, baml_options: BamlCallOptions = {}, - ) -> baml_py.BamlStream[partial_types.TestOutputClassNested, types.TestOutputClassNested]: + ) -> baml_py.BamlStream[partial_types.TestClassWithEnum, types.TestClassWithEnum]: __tb__ = baml_options.get("tb", None) if __tb__ is not None: tb = __tb__._tb @@ -1985,7 +1985,7 @@ def FnOutputNestedClass( tb = None raw = self.__runtime.stream_function( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input": input, }, @@ -1994,10 +1994,10 @@ def FnOutputNestedClass( tb, ) - mdl = create_model("FnOutputNestedClassReturnType", inner=(types.TestOutputClassNested, ...)) - partial_mdl = create_model("FnOutputNestedClassPartialReturnType", inner=(partial_types.TestOutputClassNested, ...)) + mdl = create_model("FnOutputClassWithEnumReturnType", inner=(types.TestClassWithEnum, ...)) + partial_mdl = create_model("FnOutputClassWithEnumPartialReturnType", inner=(partial_types.TestClassWithEnum, ...)) - return baml_py.BamlStream[partial_types.TestOutputClassNested, types.TestOutputClassNested]( + return baml_py.BamlStream[partial_types.TestClassWithEnum, types.TestClassWithEnum]( raw, lambda x: coerce(partial_mdl, x), lambda x: coerce(mdl, x), diff --git a/integ-tests/python/baml_client/inlinedbaml.py b/integ-tests/python/baml_client/inlinedbaml.py index cbe698d0f..eb654c367 100644 --- a/integ-tests/python/baml_client/inlinedbaml.py +++ b/integ-tests/python/baml_client/inlinedbaml.py @@ -16,7 +16,7 @@ file_map = { - "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n api_key \"\"\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", "fiddle-examples/chain-of-thought.baml": "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(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}", @@ -43,8 +43,9 @@ "test-files/functions/output/boolean.baml": "function FnOutputBool(input: string) -> bool {\n client GPT35\n prompt #\"\n Return a true: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputBool {\n functions [FnOutputBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-dynamic.baml": "class Person {\n name string?\n hair_color Color?\n\n @@dynamic\n}\n\nenum Color {\n RED\n BLUE\n GREEN\n YELLOW\n BLACK\n WHITE\n\n @@dynamic\n}\n\nfunction ExtractPeople(text: string) -> Person[] {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\t\t 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.\n\t\t \n\t\t {# This is a special macro that prints out the output schema of the function #}\n\t\t {{ ctx.output_format }} \n\t\t \n\t\t {{ _.role('user') }}\n\t\t {{text}}\n \"#\n}\n\nenum Hobby {\n SPORTS\n MUSIC\n READING\n\n @@dynamic\n}\n", "test-files/functions/output/class-list.baml": "function FnOutputClassList(input: string) -> TestOutputClass[] {\n client GPT35\n prompt #\"\n Return a JSON array that follows this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}\n\ntest FnOutputClassList {\n functions [FnOutputClassList]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/class-nested.baml": "class TestClassNested {\n prop1 string\n prop2 InnerClass\n}\n\nclass InnerClass {\n prop1 string\n prop2 string\n inner InnerClass2\n}\n\nclass InnerClass2 {\n prop2 int\n prop3 float\n}\n\nfunction FnOutputClassNested(input: string) -> TestClassNested {\n client Ollama\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassNested {\n functions [FnOutputClassNested]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-with-enum.baml": "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass, FnOutputNestedClass]\n args {\n input \"example input\"\n }\n}\n\n \n\nclass TestOutputClassNested {\n prop1 string\n prop2 int\n prop3 TestOutputClass\n}\n\nfunction FnOutputNestedClass(input: string) -> TestOutputClassNested {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}", + "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml": "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum.baml": "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml": " ", diff --git a/integ-tests/python/baml_client/partial_types.py b/integ-tests/python/baml_client/partial_types.py index d965ab82a..b6f12e325 100644 --- a/integ-tests/python/baml_client/partial_types.py +++ b/integ-tests/python/baml_client/partial_types.py @@ -44,14 +44,14 @@ class ClassOptionalOutput2(BaseModel): prop1: Optional[str] = None prop2: Optional[str] = None - prop3: "Blah" + prop3: Optional["Blah"] = None class ClassWithImage(BaseModel): myImage: Optional[baml_py.Image] = None param2: Optional[str] = None - fake_image: "FakeImage" + fake_image: Optional["FakeImage"] = None class DynamicClassOne(BaseModel): @@ -63,7 +63,7 @@ class DynamicClassTwo(BaseModel): model_config = ConfigDict(extra='allow') hi: Optional[str] = None - some_class: "SomeClassNestedDynamic" + some_class: Optional["SomeClassNestedDynamic"] = None status: Optional[Union[types.DynEnumOne, str]] = None class DynamicOutput(BaseModel): @@ -100,6 +100,19 @@ class FakeImage(BaseModel): url: Optional[str] = None +class InnerClass(BaseModel): + + + prop1: Optional[str] = None + prop2: Optional[str] = None + inner: Optional["InnerClass2"] = None + +class InnerClass2(BaseModel): + + + prop2: Optional[int] = None + prop3: Optional[float] = None + class NamedArgsSingleClass(BaseModel): @@ -116,7 +129,7 @@ class OptionalTest_Prop1(BaseModel): class OptionalTest_ReturnType(BaseModel): - omega_1: "OptionalTest_Prop1" + omega_1: Optional["OptionalTest_Prop1"] = None omega_2: Optional[str] = None omega_3: List[Optional[types.OptionalTest_CategoryType]] @@ -155,8 +168,8 @@ class SearchParams(BaseModel): dateRange: Optional[int] = None location: List[Optional[str]] - jobTitle: "WithReasoning" - company: "WithReasoning" + jobTitle: Optional["WithReasoning"] = None + company: Optional["WithReasoning"] = None description: List["WithReasoning"] tags: List[Optional[Union[Optional[types.Tag], Optional[str]]]] @@ -175,24 +188,23 @@ class TestClassAlias(BaseModel): key4: Optional[str] = None key5: Optional[str] = None -class TestClassWithEnum(BaseModel): +class TestClassNested(BaseModel): prop1: Optional[str] = None - prop2: Optional[types.EnumInClass] = None + prop2: Optional["InnerClass"] = None -class TestOutputClass(BaseModel): +class TestClassWithEnum(BaseModel): prop1: Optional[str] = None - prop2: Optional[int] = None + prop2: Optional[types.EnumInClass] = None -class TestOutputClassNested(BaseModel): +class TestOutputClass(BaseModel): prop1: Optional[str] = None prop2: Optional[int] = None - prop3: "TestOutputClass" class UnionTest_ReturnType(BaseModel): diff --git a/integ-tests/python/baml_client/type_builder.py b/integ-tests/python/baml_client/type_builder.py index b07eea04f..189265dda 100644 --- a/integ-tests/python/baml_client/type_builder.py +++ b/integ-tests/python/baml_client/type_builder.py @@ -19,7 +19,7 @@ class TypeBuilder(_TypeBuilder): def __init__(self): super().__init__(classes=set( - ["Blah","ClassOptionalOutput","ClassOptionalOutput2","ClassWithImage","DynamicClassOne","DynamicClassTwo","DynamicOutput","Education","Email","Event","FakeImage","NamedArgsSingleClass","OptionalTest_Prop1","OptionalTest_ReturnType","OrderInfo","Person","RaysData","Resume","SearchParams","SomeClassNestedDynamic","TestClassAlias","TestClassWithEnum","TestOutputClass","TestOutputClassNested","UnionTest_ReturnType","WithReasoning",] + ["Blah","ClassOptionalOutput","ClassOptionalOutput2","ClassWithImage","DynamicClassOne","DynamicClassTwo","DynamicOutput","Education","Email","Event","FakeImage","InnerClass","InnerClass2","NamedArgsSingleClass","OptionalTest_Prop1","OptionalTest_ReturnType","OrderInfo","Person","RaysData","Resume","SearchParams","SomeClassNestedDynamic","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",] )) diff --git a/integ-tests/python/baml_client/types.py b/integ-tests/python/baml_client/types.py index 1be2600cc..00bdc6fec 100644 --- a/integ-tests/python/baml_client/types.py +++ b/integ-tests/python/baml_client/types.py @@ -191,6 +191,19 @@ class FakeImage(BaseModel): url: str +class InnerClass(BaseModel): + + + prop1: str + prop2: str + inner: "InnerClass2" + +class InnerClass2(BaseModel): + + + prop2: int + prop3: float + class NamedArgsSingleClass(BaseModel): @@ -266,24 +279,23 @@ class TestClassAlias(BaseModel): key4: str key5: str -class TestClassWithEnum(BaseModel): +class TestClassNested(BaseModel): prop1: str - prop2: "EnumInClass" + prop2: "InnerClass" -class TestOutputClass(BaseModel): +class TestClassWithEnum(BaseModel): prop1: str - prop2: int + prop2: "EnumInClass" -class TestOutputClassNested(BaseModel): +class TestOutputClass(BaseModel): prop1: str prop2: int - prop3: "TestOutputClass" class UnionTest_ReturnType(BaseModel): diff --git a/integ-tests/python/test_functions.py b/integ-tests/python/test_functions.py index ad78bb6aa..8e5840de4 100644 --- a/integ-tests/python/test_functions.py +++ b/integ-tests/python/test_functions.py @@ -371,4 +371,16 @@ async def test_stream_dynamic_class_output(): print("final ", final) print("final ", final.model_dump()) print("final ", final.model_dump_json()) - assert final.hair_color == "black" \ No newline at end of file + assert final.hair_color == "black" + +@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 = [] + async for msg in stream: + print("streamed ", msg.model_dump(mode='json')) + msgs.append(msg) + final = await stream.get_final_response() + + assert len(msgs) > 0, "Expected at least one streamed response but got none." + print("final ", final.model_dump(mode='json')) diff --git a/integ-tests/ruby/baml_client/client.rb b/integ-tests/ruby/baml_client/client.rb index 593d17a21..b08b95c10 100644 --- a/integ-tests/ruby/baml_client/client.rb +++ b/integ-tests/ruby/baml_client/client.rb @@ -453,14 +453,14 @@ def FnOutputClassList( params( input: String, - ).returns(Baml::Types::TestClassWithEnum) + ).returns(Baml::Types::TestClassNested) } - def FnOutputClassWithEnum( + def FnOutputClassNested( input: ) raw = @runtime.call_function( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input" => input, }, @@ -473,14 +473,14 @@ def FnOutputClassWithEnum( params( input: String, - ).returns(Baml::Types::TestOutputClassNested) + ).returns(Baml::Types::TestClassWithEnum) } - def FnOutputNestedClass( + def FnOutputClassWithEnum( input: ) raw = @runtime.call_function( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input" => input, }, @@ -1599,19 +1599,19 @@ def FnOutputClassList( sig { params( input: String, - ).returns(Baml::BamlStream[Baml::Types::TestClassWithEnum]) + ).returns(Baml::BamlStream[Baml::Types::TestClassNested]) } - def FnOutputClassWithEnum( + def FnOutputClassNested( input: ) raw = @runtime.stream_function( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input" => input, }, @ctx_manager, ) - Baml::BamlStream[Baml::PartialTypes::TestClassWithEnum, Baml::Types::TestClassWithEnum].new( + Baml::BamlStream[Baml::PartialTypes::TestClassNested, Baml::Types::TestClassNested].new( ffi_stream: raw, ctx_manager: @ctx_manager ) @@ -1620,19 +1620,19 @@ def FnOutputClassWithEnum( sig { params( input: String, - ).returns(Baml::BamlStream[Baml::Types::TestOutputClassNested]) + ).returns(Baml::BamlStream[Baml::Types::TestClassWithEnum]) } - def FnOutputNestedClass( + def FnOutputClassWithEnum( input: ) raw = @runtime.stream_function( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input" => input, }, @ctx_manager, ) - Baml::BamlStream[Baml::PartialTypes::TestOutputClassNested, Baml::Types::TestOutputClassNested].new( + Baml::BamlStream[Baml::PartialTypes::TestClassWithEnum, Baml::Types::TestClassWithEnum].new( ffi_stream: raw, ctx_manager: @ctx_manager ) diff --git a/integ-tests/ruby/baml_client/inlined.rb b/integ-tests/ruby/baml_client/inlined.rb index 81835a050..eb5619c00 100644 --- a/integ-tests/ruby/baml_client/inlined.rb +++ b/integ-tests/ruby/baml_client/inlined.rb @@ -16,7 +16,7 @@ module Baml module Inlined FILE_MAP = { - "clients.baml" => "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n api_key \"\"\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml" => "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", "fiddle-examples/chain-of-thought.baml" => "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml" => "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml" => "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(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}", @@ -43,8 +43,9 @@ module Inlined "test-files/functions/output/boolean.baml" => "function FnOutputBool(input: string) -> bool {\n client GPT35\n prompt #\"\n Return a true: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputBool {\n functions [FnOutputBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-dynamic.baml" => "class Person {\n name string?\n hair_color Color?\n\n @@dynamic\n}\n\nenum Color {\n RED\n BLUE\n GREEN\n YELLOW\n BLACK\n WHITE\n\n @@dynamic\n}\n\nfunction ExtractPeople(text: string) -> Person[] {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\t\t 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.\n\t\t \n\t\t {# This is a special macro that prints out the output schema of the function #}\n\t\t {{ ctx.output_format }} \n\t\t \n\t\t {{ _.role('user') }}\n\t\t {{text}}\n \"#\n}\n\nenum Hobby {\n SPORTS\n MUSIC\n READING\n\n @@dynamic\n}\n", "test-files/functions/output/class-list.baml" => "function FnOutputClassList(input: string) -> TestOutputClass[] {\n client GPT35\n prompt #\"\n Return a JSON array that follows this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}\n\ntest FnOutputClassList {\n functions [FnOutputClassList]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/class-nested.baml" => "class TestClassNested {\n prop1 string\n prop2 InnerClass\n}\n\nclass InnerClass {\n prop1 string\n prop2 string\n inner InnerClass2\n}\n\nclass InnerClass2 {\n prop2 int\n prop3 float\n}\n\nfunction FnOutputClassNested(input: string) -> TestClassNested {\n client Ollama\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassNested {\n functions [FnOutputClassNested]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-with-enum.baml" => "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/class.baml" => "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass, FnOutputNestedClass]\n args {\n input \"example input\"\n }\n}\n\n \n\nclass TestOutputClassNested {\n prop1 string\n prop2 int\n prop3 TestOutputClass\n}\n\nfunction FnOutputNestedClass(input: string) -> TestOutputClassNested {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}", + "test-files/functions/output/class.baml" => "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml" => "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum.baml" => "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml" => " ", diff --git a/integ-tests/ruby/baml_client/partial-types.rb b/integ-tests/ruby/baml_client/partial-types.rb index 90fdea5a2..1697d7c55 100644 --- a/integ-tests/ruby/baml_client/partial-types.rb +++ b/integ-tests/ruby/baml_client/partial-types.rb @@ -32,6 +32,8 @@ class Education < T::Struct; end class Email < T::Struct; end class Event < T::Struct; end class FakeImage < T::Struct; end + class InnerClass < T::Struct; end + class InnerClass2 < T::Struct; end class NamedArgsSingleClass < T::Struct; end class OptionalTest_Prop1 < T::Struct; end class OptionalTest_ReturnType < T::Struct; end @@ -42,9 +44,9 @@ class Resume < T::Struct; end class SearchParams < T::Struct; end class SomeClassNestedDynamic < T::Struct; end class TestClassAlias < T::Struct; end + class TestClassNested < T::Struct; end class TestClassWithEnum < T::Struct; end class TestOutputClass < T::Struct; end - class TestOutputClassNested < T::Struct; end class UnionTest_ReturnType < T::Struct; end class WithReasoning < T::Struct; end class Blah < T::Struct @@ -105,6 +107,17 @@ class FakeImage < T::Struct include T::Struct::ActsAsComparable const :url, T.nilable(String) end + class InnerClass < T::Struct + include T::Struct::ActsAsComparable + const :prop1, T.nilable(String) + const :prop2, T.nilable(String) + const :inner, Baml::PartialTypes::InnerClass2 + end + class InnerClass2 < T::Struct + include T::Struct::ActsAsComparable + const :prop2, T.nilable(Integer) + const :prop3, T.nilable(Float) + end class NamedArgsSingleClass < T::Struct include T::Struct::ActsAsComparable const :key, T.nilable(String) @@ -168,21 +181,20 @@ class TestClassAlias < T::Struct const :key4, T.nilable(String) const :key5, T.nilable(String) end - class TestClassWithEnum < T::Struct + class TestClassNested < T::Struct include T::Struct::ActsAsComparable const :prop1, T.nilable(String) - const :prop2, T.nilable(Baml::Types::EnumInClass) + const :prop2, Baml::PartialTypes::InnerClass end - class TestOutputClass < T::Struct + class TestClassWithEnum < T::Struct include T::Struct::ActsAsComparable const :prop1, T.nilable(String) - const :prop2, T.nilable(Integer) + const :prop2, T.nilable(Baml::Types::EnumInClass) end - class TestOutputClassNested < T::Struct + class TestOutputClass < T::Struct include T::Struct::ActsAsComparable const :prop1, T.nilable(String) const :prop2, T.nilable(Integer) - const :prop3, Baml::PartialTypes::TestOutputClass end class UnionTest_ReturnType < T::Struct include T::Struct::ActsAsComparable diff --git a/integ-tests/ruby/baml_client/types.rb b/integ-tests/ruby/baml_client/types.rb index 140092802..5b299b8ef 100644 --- a/integ-tests/ruby/baml_client/types.rb +++ b/integ-tests/ruby/baml_client/types.rb @@ -142,6 +142,8 @@ class Education < T::Struct; end class Email < T::Struct; end class Event < T::Struct; end class FakeImage < T::Struct; end + class InnerClass < T::Struct; end + class InnerClass2 < T::Struct; end class NamedArgsSingleClass < T::Struct; end class OptionalTest_Prop1 < T::Struct; end class OptionalTest_ReturnType < T::Struct; end @@ -152,9 +154,9 @@ class Resume < T::Struct; end class SearchParams < T::Struct; end class SomeClassNestedDynamic < T::Struct; end class TestClassAlias < T::Struct; end + class TestClassNested < T::Struct; end class TestClassWithEnum < T::Struct; end class TestOutputClass < T::Struct; end - class TestOutputClassNested < T::Struct; end class UnionTest_ReturnType < T::Struct; end class WithReasoning < T::Struct; end class Blah < T::Struct @@ -215,6 +217,17 @@ class FakeImage < T::Struct include T::Struct::ActsAsComparable const :url, String end + class InnerClass < T::Struct + include T::Struct::ActsAsComparable + const :prop1, String + const :prop2, String + const :inner, Baml::Types::InnerClass2 + end + class InnerClass2 < T::Struct + include T::Struct::ActsAsComparable + const :prop2, Integer + const :prop3, Float + end class NamedArgsSingleClass < T::Struct include T::Struct::ActsAsComparable const :key, String @@ -278,21 +291,20 @@ class TestClassAlias < T::Struct const :key4, String const :key5, String end - class TestClassWithEnum < T::Struct + class TestClassNested < T::Struct include T::Struct::ActsAsComparable const :prop1, String - const :prop2, Baml::Types::EnumInClass + const :prop2, Baml::Types::InnerClass end - class TestOutputClass < T::Struct + class TestClassWithEnum < T::Struct include T::Struct::ActsAsComparable const :prop1, String - const :prop2, Integer + const :prop2, Baml::Types::EnumInClass end - class TestOutputClassNested < T::Struct + class TestOutputClass < T::Struct include T::Struct::ActsAsComparable const :prop1, String const :prop2, Integer - const :prop3, Baml::Types::TestOutputClass end class UnionTest_ReturnType < T::Struct include T::Struct::ActsAsComparable diff --git a/integ-tests/ruby/test_functions.rb b/integ-tests/ruby/test_functions.rb index 23159d155..8ab86795c 100644 --- a/integ-tests/ruby/test_functions.rb +++ b/integ-tests/ruby/test_functions.rb @@ -146,4 +146,18 @@ end assert msgs.last == final, "Expected last stream message to match final response." end + + it "allows streaming of nested" do + stream = b.stream.FnOutputClassNested(input: "a") + msgs = [] + stream.each do |msg| + puts msg + msgs << msg + end + final = stream.get_final_response + + puts final + 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 end diff --git a/integ-tests/typescript/baml_client/client.ts b/integ-tests/typescript/baml_client/client.ts index 1c80bb183..1c86606d4 100644 --- a/integ-tests/typescript/baml_client/client.ts +++ b/integ-tests/typescript/baml_client/client.ts @@ -16,9 +16,15 @@ $ pnpm add @boundaryml/baml // biome-ignore format: autogenerated code /* eslint-disable */ import { BamlRuntime, FunctionResult, BamlCtxManager, BamlStream, Image } from "@boundaryml/baml" -import {Blah, ClassOptionalOutput, ClassOptionalOutput2, ClassWithImage, DynamicClassOne, DynamicClassTwo, DynamicOutput, Education, Email, Event, FakeImage, NamedArgsSingleClass, OptionalTest_Prop1, OptionalTest_ReturnType, OrderInfo, Person, RaysData, Resume, SearchParams, SomeClassNestedDynamic, TestClassAlias, TestClassWithEnum, TestOutputClass, TestOutputClassNested, UnionTest_ReturnType, WithReasoning, Category, Category2, Category3, Color, DataType, DynEnumOne, DynEnumTwo, EnumInClass, EnumOutput, Hobby, NamedArgsSingleEnum, NamedArgsSingleEnumList, OptionalTest_CategoryType, OrderStatus, Tag, TestEnum} from "./types" +import {Blah, ClassOptionalOutput, ClassOptionalOutput2, ClassWithImage, DynamicClassOne, DynamicClassTwo, DynamicOutput, Education, Email, Event, FakeImage, InnerClass, InnerClass2, NamedArgsSingleClass, OptionalTest_Prop1, OptionalTest_ReturnType, OrderInfo, Person, RaysData, Resume, SearchParams, SomeClassNestedDynamic, 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" +export type RecursivePartialNull = T extends object + ? { + [P in keyof T]?: RecursivePartialNull; + } + : T | null; + export class BamlClient { private stream_client: BamlStreamClient @@ -331,34 +337,34 @@ export class BamlClient { return raw.parsed() as TestOutputClass[] } - async FnOutputClassWithEnum( + async FnOutputClassNested( input: string, __baml_options__?: { tb?: TypeBuilder } - ): Promise { + ): Promise { const raw = await this.runtime.callFunction( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input": input }, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return raw.parsed() as TestClassWithEnum + return raw.parsed() as TestClassNested } - async FnOutputNestedClass( + async FnOutputClassWithEnum( input: string, __baml_options__?: { tb?: TypeBuilder } - ): Promise { + ): Promise { const raw = await this.runtime.callFunction( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input": input }, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return raw.parsed() as TestOutputClassNested + return raw.parsed() as TestClassWithEnum } async FnOutputStringList( @@ -880,7 +886,7 @@ class BamlStreamClient { ClassifyMessage( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Category | null), Category> { + ): BamlStream, Category> { const raw = this.runtime.streamFunction( "ClassifyMessage", { @@ -890,9 +896,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Category | null), Category>( + return new BamlStream, Category>( raw, - (a): a is (Category | null) => a, + (a): a is RecursivePartialNull => a, (a): a is Category => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -902,7 +908,7 @@ class BamlStreamClient { ClassifyMessage2( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Category | null), Category> { + ): BamlStream, Category> { const raw = this.runtime.streamFunction( "ClassifyMessage2", { @@ -912,9 +918,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Category | null), Category>( + return new BamlStream, Category>( raw, - (a): a is (Category | null) => a, + (a): a is RecursivePartialNull => a, (a): a is Category => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -924,7 +930,7 @@ class BamlStreamClient { ClassifyMessage3( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Category | null), Category> { + ): BamlStream, Category> { const raw = this.runtime.streamFunction( "ClassifyMessage3", { @@ -934,9 +940,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Category | null), Category>( + return new BamlStream, Category>( raw, - (a): a is (Category | null) => a, + (a): a is RecursivePartialNull => a, (a): a is Category => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -946,7 +952,7 @@ class BamlStreamClient { DescribeImage( img: Image, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "DescribeImage", { @@ -956,9 +962,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -968,7 +974,7 @@ class BamlStreamClient { DescribeImage2( classWithImage: ClassWithImage,img2: Image, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "DescribeImage2", { @@ -978,9 +984,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -990,7 +996,7 @@ class BamlStreamClient { DescribeImage3( classWithImage: ClassWithImage,img2: Image, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "DescribeImage3", { @@ -1000,9 +1006,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1012,7 +1018,7 @@ class BamlStreamClient { DescribeImage4( classWithImage: ClassWithImage,img2: Image, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "DescribeImage4", { @@ -1022,9 +1028,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1034,7 +1040,7 @@ class BamlStreamClient { DynamicFunc( input: DynamicClassOne, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), DynamicClassTwo> { + ): BamlStream, DynamicClassTwo> { const raw = this.runtime.streamFunction( "DynamicFunc", { @@ -1044,9 +1050,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), DynamicClassTwo>( + return new BamlStream, DynamicClassTwo>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is DynamicClassTwo => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1056,7 +1062,7 @@ class BamlStreamClient { ExtractNames( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null)[], string[]> { + ): BamlStream, string[]> { const raw = this.runtime.streamFunction( "ExtractNames", { @@ -1066,9 +1072,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null)[], string[]>( + return new BamlStream, string[]>( raw, - (a): a is (string | null)[] => a, + (a): a is RecursivePartialNull => a, (a): a is string[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1078,7 +1084,7 @@ class BamlStreamClient { ExtractPeople( text: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null)[], Person[]> { + ): BamlStream, Person[]> { const raw = this.runtime.streamFunction( "ExtractPeople", { @@ -1088,9 +1094,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null)[], Person[]>( + return new BamlStream, Person[]>( raw, - (a): a is (Partial | null)[] => a, + (a): a is RecursivePartialNull => a, (a): a is Person[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1100,7 +1106,7 @@ class BamlStreamClient { ExtractResume( resume: string,img?: Image | null, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), Resume> { + ): BamlStream, Resume> { const raw = this.runtime.streamFunction( "ExtractResume", { @@ -1110,9 +1116,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), Resume>( + return new BamlStream, Resume>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is Resume => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1122,7 +1128,7 @@ class BamlStreamClient { ExtractResume2( resume: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), Resume> { + ): BamlStream, Resume> { const raw = this.runtime.streamFunction( "ExtractResume2", { @@ -1132,9 +1138,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), Resume>( + return new BamlStream, Resume>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is Resume => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1144,7 +1150,7 @@ class BamlStreamClient { FnClassOptionalOutput( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<((Partial | null) | null), ClassOptionalOutput | null> { + ): BamlStream, ClassOptionalOutput | null> { const raw = this.runtime.streamFunction( "FnClassOptionalOutput", { @@ -1154,9 +1160,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<((Partial | null) | null), ClassOptionalOutput | null>( + return new BamlStream, ClassOptionalOutput | null>( raw, - (a): a is ((Partial | null) | null) => a, + (a): a is RecursivePartialNull => a, (a): a is ClassOptionalOutput | null => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1166,7 +1172,7 @@ class BamlStreamClient { FnClassOptionalOutput2( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<((Partial | null) | null), ClassOptionalOutput2 | null> { + ): BamlStream, ClassOptionalOutput2 | null> { const raw = this.runtime.streamFunction( "FnClassOptionalOutput2", { @@ -1176,9 +1182,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<((Partial | null) | null), ClassOptionalOutput2 | null>( + return new BamlStream, ClassOptionalOutput2 | null>( raw, - (a): a is ((Partial | null) | null) => a, + (a): a is RecursivePartialNull => a, (a): a is ClassOptionalOutput2 | null => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1188,7 +1194,7 @@ class BamlStreamClient { FnEnumListOutput( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(EnumOutput | null)[], EnumOutput[]> { + ): BamlStream, EnumOutput[]> { const raw = this.runtime.streamFunction( "FnEnumListOutput", { @@ -1198,9 +1204,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(EnumOutput | null)[], EnumOutput[]>( + return new BamlStream, EnumOutput[]>( raw, - (a): a is (EnumOutput | null)[] => a, + (a): a is RecursivePartialNull => a, (a): a is EnumOutput[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1210,7 +1216,7 @@ class BamlStreamClient { FnEnumOutput( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(EnumOutput | null), EnumOutput> { + ): BamlStream, EnumOutput> { const raw = this.runtime.streamFunction( "FnEnumOutput", { @@ -1220,9 +1226,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(EnumOutput | null), EnumOutput>( + return new BamlStream, EnumOutput>( raw, - (a): a is (EnumOutput | null) => a, + (a): a is RecursivePartialNull => a, (a): a is EnumOutput => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1232,7 +1238,7 @@ class BamlStreamClient { FnNamedArgsSingleStringOptional( myString?: string | null, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "FnNamedArgsSingleStringOptional", { @@ -1242,9 +1248,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1254,7 +1260,7 @@ class BamlStreamClient { FnOutputBool( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(boolean | null), boolean> { + ): BamlStream, boolean> { const raw = this.runtime.streamFunction( "FnOutputBool", { @@ -1264,9 +1270,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(boolean | null), boolean>( + return new BamlStream, boolean>( raw, - (a): a is (boolean | null) => a, + (a): a is RecursivePartialNull => a, (a): a is boolean => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1276,7 +1282,7 @@ class BamlStreamClient { FnOutputClass( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), TestOutputClass> { + ): BamlStream, TestOutputClass> { const raw = this.runtime.streamFunction( "FnOutputClass", { @@ -1286,9 +1292,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), TestOutputClass>( + return new BamlStream, TestOutputClass>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is TestOutputClass => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1298,7 +1304,7 @@ class BamlStreamClient { FnOutputClassList( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null)[], TestOutputClass[]> { + ): BamlStream, TestOutputClass[]> { const raw = this.runtime.streamFunction( "FnOutputClassList", { @@ -1308,21 +1314,21 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null)[], TestOutputClass[]>( + return new BamlStream, TestOutputClass[]>( raw, - (a): a is (Partial | null)[] => a, + (a): a is RecursivePartialNull => a, (a): a is TestOutputClass[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) } - FnOutputClassWithEnum( + FnOutputClassNested( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), TestClassWithEnum> { + ): BamlStream, TestClassNested> { const raw = this.runtime.streamFunction( - "FnOutputClassWithEnum", + "FnOutputClassNested", { "input": input }, @@ -1330,21 +1336,21 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), TestClassWithEnum>( + return new BamlStream, TestClassNested>( raw, - (a): a is (Partial | null) => a, - (a): a is TestClassWithEnum => a, + (a): a is RecursivePartialNull => a, + (a): a is TestClassNested => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) } - FnOutputNestedClass( + FnOutputClassWithEnum( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), TestOutputClassNested> { + ): BamlStream, TestClassWithEnum> { const raw = this.runtime.streamFunction( - "FnOutputNestedClass", + "FnOutputClassWithEnum", { "input": input }, @@ -1352,10 +1358,10 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), TestOutputClassNested>( + return new BamlStream, TestClassWithEnum>( raw, - (a): a is (Partial | null) => a, - (a): a is TestOutputClassNested => a, + (a): a is RecursivePartialNull => a, + (a): a is TestClassWithEnum => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) @@ -1364,7 +1370,7 @@ class BamlStreamClient { FnOutputStringList( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null)[], string[]> { + ): BamlStream, string[]> { const raw = this.runtime.streamFunction( "FnOutputStringList", { @@ -1374,9 +1380,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null)[], string[]>( + return new BamlStream, string[]>( raw, - (a): a is (string | null)[] => a, + (a): a is RecursivePartialNull => a, (a): a is string[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1386,7 +1392,7 @@ class BamlStreamClient { FnTestAliasedEnumOutput( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(TestEnum | null), TestEnum> { + ): BamlStream, TestEnum> { const raw = this.runtime.streamFunction( "FnTestAliasedEnumOutput", { @@ -1396,9 +1402,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(TestEnum | null), TestEnum>( + return new BamlStream, TestEnum>( raw, - (a): a is (TestEnum | null) => a, + (a): a is RecursivePartialNull => a, (a): a is TestEnum => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1408,7 +1414,7 @@ class BamlStreamClient { FnTestClassAlias( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), TestClassAlias> { + ): BamlStream, TestClassAlias> { const raw = this.runtime.streamFunction( "FnTestClassAlias", { @@ -1418,9 +1424,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), TestClassAlias>( + return new BamlStream, TestClassAlias>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is TestClassAlias => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1430,7 +1436,7 @@ class BamlStreamClient { FnTestNamedArgsSingleEnum( myArg: NamedArgsSingleEnum, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "FnTestNamedArgsSingleEnum", { @@ -1440,9 +1446,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1452,7 +1458,7 @@ class BamlStreamClient { GetDataType( text: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), RaysData> { + ): BamlStream, RaysData> { const raw = this.runtime.streamFunction( "GetDataType", { @@ -1462,9 +1468,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), RaysData>( + return new BamlStream, RaysData>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is RaysData => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1474,7 +1480,7 @@ class BamlStreamClient { GetOrderInfo( email: Email, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), OrderInfo> { + ): BamlStream, OrderInfo> { const raw = this.runtime.streamFunction( "GetOrderInfo", { @@ -1484,9 +1490,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), OrderInfo>( + return new BamlStream, OrderInfo>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is OrderInfo => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1496,7 +1502,7 @@ class BamlStreamClient { GetQuery( query: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), SearchParams> { + ): BamlStream, SearchParams> { const raw = this.runtime.streamFunction( "GetQuery", { @@ -1506,9 +1512,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), SearchParams>( + return new BamlStream, SearchParams>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is SearchParams => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1518,7 +1524,7 @@ class BamlStreamClient { MyFunc( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), DynamicOutput> { + ): BamlStream, DynamicOutput> { const raw = this.runtime.streamFunction( "MyFunc", { @@ -1528,9 +1534,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), DynamicOutput>( + return new BamlStream, DynamicOutput>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is DynamicOutput => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1540,7 +1546,7 @@ class BamlStreamClient { OptionalTest_Function( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<((Partial | null) | null)[], (OptionalTest_ReturnType | null)[]> { + ): BamlStream, (OptionalTest_ReturnType | null)[]> { const raw = this.runtime.streamFunction( "OptionalTest_Function", { @@ -1550,9 +1556,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<((Partial | null) | null)[], (OptionalTest_ReturnType | null)[]>( + return new BamlStream, (OptionalTest_ReturnType | null)[]>( raw, - (a): a is ((Partial | null) | null)[] => a, + (a): a is RecursivePartialNull<(OptionalTest_ReturnType | null)[]> => a, (a): a is (OptionalTest_ReturnType | null)[] => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1562,7 +1568,7 @@ class BamlStreamClient { PromptTestClaude( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestClaude", { @@ -1572,9 +1578,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1584,7 +1590,7 @@ class BamlStreamClient { PromptTestClaudeChat( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestClaudeChat", { @@ -1594,9 +1600,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1606,7 +1612,7 @@ class BamlStreamClient { PromptTestClaudeChatNoSystem( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestClaudeChatNoSystem", { @@ -1616,9 +1622,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1628,7 +1634,7 @@ class BamlStreamClient { PromptTestOpenAI( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestOpenAI", { @@ -1638,9 +1644,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1650,7 +1656,7 @@ class BamlStreamClient { PromptTestOpenAIChat( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestOpenAIChat", { @@ -1660,9 +1666,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1672,7 +1678,7 @@ class BamlStreamClient { PromptTestOpenAIChatNoSystem( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "PromptTestOpenAIChatNoSystem", { @@ -1682,9 +1688,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1694,7 +1700,7 @@ class BamlStreamClient { TestAnthropic( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestAnthropic", { @@ -1704,9 +1710,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1716,7 +1722,7 @@ class BamlStreamClient { TestAzure( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestAzure", { @@ -1726,9 +1732,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1738,7 +1744,7 @@ class BamlStreamClient { TestFallbackClient( __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFallbackClient", { @@ -1748,9 +1754,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1760,7 +1766,7 @@ class BamlStreamClient { TestFnNamedArgsSingleBool( myBool: boolean, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleBool", { @@ -1770,9 +1776,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1782,7 +1788,7 @@ class BamlStreamClient { TestFnNamedArgsSingleClass( myArg: NamedArgsSingleClass, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleClass", { @@ -1792,9 +1798,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1804,7 +1810,7 @@ class BamlStreamClient { TestFnNamedArgsSingleEnumList( myArg: NamedArgsSingleEnumList[], __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleEnumList", { @@ -1814,9 +1820,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1826,7 +1832,7 @@ class BamlStreamClient { TestFnNamedArgsSingleFloat( myFloat: number, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleFloat", { @@ -1836,9 +1842,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1848,7 +1854,7 @@ class BamlStreamClient { TestFnNamedArgsSingleInt( myInt: number, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleInt", { @@ -1858,9 +1864,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1870,7 +1876,7 @@ class BamlStreamClient { TestFnNamedArgsSingleString( myString: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleString", { @@ -1880,9 +1886,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1892,7 +1898,7 @@ class BamlStreamClient { TestFnNamedArgsSingleStringArray( myStringArray: string[], __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleStringArray", { @@ -1902,9 +1908,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1914,7 +1920,7 @@ class BamlStreamClient { TestFnNamedArgsSingleStringList( myArg: string[], __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestFnNamedArgsSingleStringList", { @@ -1924,9 +1930,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1936,7 +1942,7 @@ class BamlStreamClient { TestGemini( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestGemini", { @@ -1946,9 +1952,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1958,7 +1964,7 @@ class BamlStreamClient { TestImageInput( img: Image, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestImageInput", { @@ -1968,9 +1974,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -1980,7 +1986,7 @@ class BamlStreamClient { TestMulticlassNamedArgs( myArg: NamedArgsSingleClass,myArg2: NamedArgsSingleClass, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestMulticlassNamedArgs", { @@ -1990,9 +1996,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -2002,7 +2008,7 @@ class BamlStreamClient { TestOllama( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestOllama", { @@ -2012,9 +2018,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -2024,7 +2030,7 @@ class BamlStreamClient { TestOpenAI( input: string, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestOpenAI", { @@ -2034,9 +2040,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -2046,7 +2052,7 @@ class BamlStreamClient { TestRetryConstant( __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestRetryConstant", { @@ -2056,9 +2062,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -2068,7 +2074,7 @@ class BamlStreamClient { TestRetryExponential( __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(string | null), string> { + ): BamlStream, string> { const raw = this.runtime.streamFunction( "TestRetryExponential", { @@ -2078,9 +2084,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(string | null), string>( + return new BamlStream, string>( raw, - (a): a is (string | null) => a, + (a): a is RecursivePartialNull => a, (a): a is string => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), @@ -2090,7 +2096,7 @@ class BamlStreamClient { UnionTest_Function( input: string | boolean, __baml_options__?: { tb?: TypeBuilder } - ): BamlStream<(Partial | null), UnionTest_ReturnType> { + ): BamlStream, UnionTest_ReturnType> { const raw = this.runtime.streamFunction( "UnionTest_Function", { @@ -2100,9 +2106,9 @@ class BamlStreamClient { this.ctx_manager.get(), __baml_options__?.tb?.__tb(), ) - return new BamlStream<(Partial | null), UnionTest_ReturnType>( + return new BamlStream, UnionTest_ReturnType>( raw, - (a): a is (Partial | null) => a, + (a): a is RecursivePartialNull => a, (a): a is UnionTest_ReturnType => a, this.ctx_manager.get(), __baml_options__?.tb?.__tb(), diff --git a/integ-tests/typescript/baml_client/inlinedbaml.ts b/integ-tests/typescript/baml_client/inlinedbaml.ts index 3a0401b1f..dc0601810 100644 --- a/integ-tests/typescript/baml_client/inlinedbaml.ts +++ b/integ-tests/typescript/baml_client/inlinedbaml.ts @@ -17,7 +17,7 @@ $ pnpm add @boundaryml/baml /* eslint-disable */ const fileMap = { - "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n api_key \"\"\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", + "clients.baml": "retry_policy Bar {\n max_retries 3\n strategy {\n type exponential_backoff\n }\n}\n\nretry_policy Foo {\n max_retries 3\n strategy {\n type constant_delay\n delay_ms 100\n }\n}\n\nclient GPT4 {\n provider baml-openai-chat\n options {\n model gpt-4\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4o {\n provider baml-openai-chat\n options {\n model gpt-4o\n api_key env.OPENAI_API_KEY\n }\n} \n\n\nclient GPT4Turbo {\n retry_policy Bar\n provider baml-openai-chat\n options {\n model gpt-4-turbo\n api_key env.OPENAI_API_KEY\n }\n} \n\nclient GPT35 {\n provider baml-openai-chat\n options {\n model \"gpt-3.5-turbo\"\n api_key env.OPENAI_API_KEY\n }\n}\n\nclient Ollama {\n provider ollama\n options {\n model llama2\n }\n}\n\nclient GPT35Azure {\n provider azure-openai\n options {\n resource_name \"west-us-azure-baml\"\n deployment_id \"gpt-35-turbo-default\"\n // base_url \"https://west-us-azure-baml.openai.azure.com/openai/deployments/gpt-35-turbo-default\"\n api_version \"2024-02-01\"\n api_key env.AZURE_OPENAI_API_KEY\n }\n}\n\nclient Gemini {\n provider google-ai\n options{\n model \"gemini-1.5-pro-001\"\n api_key env.GOOGLE_API_KEY\n }\n}\n\n\nclient Claude {\n provider anthropic\n options {\n model claude-3-haiku-20240307\n api_key env.ANTHROPIC_API_KEY\n max_tokens 1000\n }\n}\n\nclient Resilient_SimpleSyntax {\n retry_policy Foo\n provider baml-fallback\n options {\n strategy [\n GPT4Turbo\n GPT35\n Lottery_SimpleSyntax\n ]\n }\n} \n \nclient Lottery_SimpleSyntax {\n provider baml-round-robin\n options {\n start 0\n strategy [\n GPT35\n Claude\n ]\n }\n}\n", "fiddle-examples/chain-of-thought.baml": "class Email {\n subject string\n body string\n from_address string\n}\n\nenum OrderStatus {\n ORDERED\n SHIPPED\n DELIVERED\n CANCELLED\n}\n\nclass OrderInfo {\n order_status OrderStatus\n tracking_number string?\n estimated_arrival_date string?\n}\n\nfunction GetOrderInfo(email: Email) -> OrderInfo {\n client GPT4\n prompt #\"\n Given the email below:\n\n ```\n from: {{email.from_address}}\n Email Subject: {{email.subject}}\n Email Body: {{email.body}}\n ```\n\n Extract this info from the email in JSON format:\n {{ ctx.output_format }}\n\n Before you output the JSON, please explain your\n reasoning step-by-step. Here is an example on how to do this:\n 'If we think step by step we can see that ...\n therefore the output JSON is:\n {\n ... the json schema ...\n }'\n \"#\n}", "fiddle-examples/chat-roles.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category2 {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage2(input: string) -> Category {\n client GPT4\n\n prompt #\"\n {{ _.role(\"system\") }}\n // You can use _.role(\"system\") to indicate that this text should be a system message\n\n Classify the following INPUT into ONE\n of the following categories:\n\n {{ ctx.output_format }}\n\n {{ _.role(\"user\") }}\n // And _.role(\"user\") to indicate that this text should be a user message\n\n INPUT: {{ input }}\n\n Response:\n \"#\n}", "fiddle-examples/classify-message.baml": "// This will be available as an enum in your Python and Typescript code.\nenum Category {\n Refund\n CancelOrder\n TechnicalSupport\n AccountIssue\n Question\n}\n\nfunction ClassifyMessage(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}", @@ -44,8 +44,9 @@ const fileMap = { "test-files/functions/output/boolean.baml": "function FnOutputBool(input: string) -> bool {\n client GPT35\n prompt #\"\n Return a true: {{ ctx.output_format}}\n \"#\n}\n\ntest FnOutputBool {\n functions [FnOutputBool]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-dynamic.baml": "class Person {\n name string?\n hair_color Color?\n\n @@dynamic\n}\n\nenum Color {\n RED\n BLUE\n GREEN\n YELLOW\n BLACK\n WHITE\n\n @@dynamic\n}\n\nfunction ExtractPeople(text: string) -> Person[] {\n client GPT4\n prompt #\"\n {{ _.role('system') }}\n\t\t 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.\n\t\t \n\t\t {# This is a special macro that prints out the output schema of the function #}\n\t\t {{ ctx.output_format }} \n\t\t \n\t\t {{ _.role('user') }}\n\t\t {{text}}\n \"#\n}\n\nenum Hobby {\n SPORTS\n MUSIC\n READING\n\n @@dynamic\n}\n", "test-files/functions/output/class-list.baml": "function FnOutputClassList(input: string) -> TestOutputClass[] {\n client GPT35\n prompt #\"\n Return a JSON array that follows this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}\n\ntest FnOutputClassList {\n functions [FnOutputClassList]\n args {\n input \"example input\"\n }\n}\n", + "test-files/functions/output/class-nested.baml": "class TestClassNested {\n prop1 string\n prop2 InnerClass\n}\n\nclass InnerClass {\n prop1 string\n prop2 string\n inner InnerClass2\n}\n\nclass InnerClass2 {\n prop2 int\n prop3 float\n}\n\nfunction FnOutputClassNested(input: string) -> TestClassNested {\n client Ollama\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassNested {\n functions [FnOutputClassNested]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/class-with-enum.baml": "enum EnumInClass {\n ONE\n TWO\n}\n\nclass TestClassWithEnum {\n prop1 string\n prop2 EnumInClass\n}\n\nfunction FnOutputClassWithEnum(input: string) -> TestClassWithEnum {\n client GPT35\n prompt #\"\n Return a made up json blob that matches this schema:\n {{ctx.output_format}}\n ---\n\n JSON:\n \"#\n}\n\ntest FnOutputClassWithEnum {\n functions [FnOutputClassWithEnum]\n args {\n input \"example input\"\n }\n}\n", - "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass, FnOutputNestedClass]\n args {\n input \"example input\"\n }\n}\n\n \n\nclass TestOutputClassNested {\n prop1 string\n prop2 int\n prop3 TestOutputClass\n}\n\nfunction FnOutputNestedClass(input: string) -> TestOutputClassNested {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n JSON:\n \"#\n}", + "test-files/functions/output/class.baml": "class TestOutputClass {\n prop1 string\n prop2 int\n}\n\nfunction FnOutputClass(input: string) -> TestOutputClass {\n client GPT35\n prompt #\"\n Return a JSON blob with this schema: \n {{ctx.output_format}}\n\n For the prop2, always return a 540\n\n JSON:\n \"#\n}\n\ntest TestClass {\n functions [FnOutputClass]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum-list.baml": "function FnEnumListOutput(input: string) -> EnumOutput[] {\n client GPT35\n prompt #\"\n Print out two of these values randomly selected from the list below in a json array.\n\n {{ctx.output_format}}\n\n Answer:\n \"#\n} \n\ntest FnEnumListOutput {\n functions [FnEnumListOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/enum.baml": "enum EnumOutput {\n ONE\n TWO\n THREE\n\n @@alias(\"VALUE_ENUM\")\n}\n\nfunction FnEnumOutput(input: string) -> EnumOutput {\n client GPT35\n prompt #\"\n Choose one of these values randomly. Before you give the answer, write out an unrelated haiku about the ocean.\n\n {{ctx.output_format(prefix=null)}}\n \"#\n}\n\ntest FnEnumOutput {\n functions [FnEnumOutput]\n args {\n input \"example input\"\n }\n}\n", "test-files/functions/output/int.baml": " ", diff --git a/integ-tests/typescript/baml_client/type_builder.ts b/integ-tests/typescript/baml_client/type_builder.ts index eaa6b2350..ff4473cf8 100644 --- a/integ-tests/typescript/baml_client/type_builder.ts +++ b/integ-tests/typescript/baml_client/type_builder.ts @@ -44,7 +44,7 @@ export default class TypeBuilder { constructor() { this.tb = new _TypeBuilder({ classes: new Set([ - "Blah","ClassOptionalOutput","ClassOptionalOutput2","ClassWithImage","DynamicClassOne","DynamicClassTwo","DynamicOutput","Education","Email","Event","FakeImage","NamedArgsSingleClass","OptionalTest_Prop1","OptionalTest_ReturnType","OrderInfo","Person","RaysData","Resume","SearchParams","SomeClassNestedDynamic","TestClassAlias","TestClassWithEnum","TestOutputClass","TestOutputClassNested","UnionTest_ReturnType","WithReasoning", + "Blah","ClassOptionalOutput","ClassOptionalOutput2","ClassWithImage","DynamicClassOne","DynamicClassTwo","DynamicOutput","Education","Email","Event","FakeImage","InnerClass","InnerClass2","NamedArgsSingleClass","OptionalTest_Prop1","OptionalTest_ReturnType","OrderInfo","Person","RaysData","Resume","SearchParams","SomeClassNestedDynamic","TestClassAlias","TestClassNested","TestClassWithEnum","TestOutputClass","UnionTest_ReturnType","WithReasoning", ]), enums: new Set([ "Category","Category2","Category3","Color","DataType","DynEnumOne","DynEnumTwo","EnumInClass","EnumOutput","Hobby","NamedArgsSingleEnum","NamedArgsSingleEnumList","OptionalTest_CategoryType","OrderStatus","Tag","TestEnum", diff --git a/integ-tests/typescript/baml_client/types.ts b/integ-tests/typescript/baml_client/types.ts index fb0d6d69e..fa7f03d01 100644 --- a/integ-tests/typescript/baml_client/types.ts +++ b/integ-tests/typescript/baml_client/types.ts @@ -188,6 +188,19 @@ export interface FakeImage { } +export interface InnerClass { + prop1: string + prop2: string + inner: InnerClass2 + +} + +export interface InnerClass2 { + prop2: number + prop3: number + +} + export interface NamedArgsSingleClass { key: string key_two: boolean @@ -263,22 +276,21 @@ export interface TestClassAlias { } -export interface TestClassWithEnum { +export interface TestClassNested { prop1: string - prop2: EnumInClass + prop2: InnerClass } -export interface TestOutputClass { +export interface TestClassWithEnum { prop1: string - prop2: number + prop2: EnumInClass } -export interface TestOutputClassNested { +export interface TestOutputClass { prop1: string prop2: number - prop3: TestOutputClass } diff --git a/integ-tests/typescript/tests/integ-tests.test.ts b/integ-tests/typescript/tests/integ-tests.test.ts index f0cd66868..820d1efad 100644 --- a/integ-tests/typescript/tests/integ-tests.test.ts +++ b/integ-tests/typescript/tests/integ-tests.test.ts @@ -1,7 +1,8 @@ import assert from 'assert' import { Image } from '@boundaryml/baml' -import { b, NamedArgsSingleEnumList, flush, traceAsync, traceSync, setTags } from '../baml_client' +import { b, NamedArgsSingleEnumList, flush, traceAsync, traceSync, setTags, TestClassNested } from '../baml_client' import TypeBuilder from "../baml_client/type_builder"; +import { RecursivePartialNull } from '../baml_client/client'; describe('Integ tests', () => { it('should work for all inputs', async () => { @@ -220,6 +221,19 @@ describe('Integ tests', () => { expect(res.length).toBeGreaterThan(0) console.log(res) }) + + it('should work with nested classes', async () => { + let stream = b.stream.FnOutputClassNested('hi!'); + let msgs: RecursivePartialNull = []; + for await (const msg of stream) { + console.log('msg', msg) + msgs.push(msg); + } + + const final = await stream.getFinalResponse() + expect(msgs.length).toBeGreaterThan(0) + expect(msgs.at(-1)).toEqual(final) + }) }) function asyncDummyFunc(myArg: string): Promise {