From 873751ba84f736dfbcbd9cbb0b6debfe7081cc1f Mon Sep 17 00:00:00 2001 From: Antonio Sarosi Date: Mon, 11 Nov 2024 17:36:32 +0000 Subject: [PATCH] Make render messages dynamic and use `hoisted_class_prefix` instead of `"schema"` (#1155) > [!IMPORTANT] > Add `hoisted_class_prefix` to `RenderOptions` for customizable hoisted class prefixes in rendered messages. > > - **Behavior**: > - `RenderOptions` in `types.rs` now supports `hoisted_class_prefix` to customize prefix for hoisted classes. > - Default prefix for hoisted classes changed from "schema" to user-defined or "interface". > - Updated rendering logic in `OutputFormatContent` to use `hoisted_class_prefix`. > - **Documentation**: > - Added `hoisted_class_prefix` parameter to `output-format.mdx` with examples. > - **Tests**: > - Added tests in `types.rs` to verify `hoisted_class_prefix` functionality. > > This description was created by [Ellipsis](https://www.ellipsis.dev?ref=BoundaryML%2Fbaml&utm_source=github&utm_medium=referral) for 6c7c38ce936c3c0e6f05ef5c5d55b88ff15c8867. It will automatically update as commits are pushed. --- .../jinja-runtime/src/output_format/types.rs | 54 ++++++++++++------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/engine/baml-lib/jinja-runtime/src/output_format/types.rs b/engine/baml-lib/jinja-runtime/src/output_format/types.rs index 54a0f4e4e..d1fe52dcc 100644 --- a/engine/baml-lib/jinja-runtime/src/output_format/types.rs +++ b/engine/baml-lib/jinja-runtime/src/output_format/types.rs @@ -165,6 +165,7 @@ impl Default for RenderOptions { impl RenderOptions { const DEFAULT_OR_SPLITTER: &'static str = " or "; + const DEFAULT_TYPE_PREFIX_IN_RENDER_MESSAGE: &'static str = "schema"; pub(crate) fn new( prefix: Option>, @@ -293,38 +294,51 @@ impl OutputFormatContent { Builder::new(target) } - fn prefix<'a>(&self, options: &'a RenderOptions) -> Option<&'a str> { + fn prefix<'a>(&self, options: &'a RenderOptions) -> Option { fn auto_prefix( ft: &FieldType, + options: &RenderOptions, output_format_content: &OutputFormatContent, - ) -> Option<&'static str> { + ) -> Option { match ft { FieldType::Primitive(TypeValue::String) => None, - FieldType::Primitive(_) => Some("Answer as a: "), - FieldType::Literal(_) => Some("Answer using this specific value:\n"), - FieldType::Enum(_) => Some("Answer with any of the categories:\n"), - // TODO: Func returns &str we can't format!, do something to - // avoid duplicating the string. + FieldType::Primitive(_) => Some(String::from("Answer as a: ")), + FieldType::Literal(_) => Some(String::from("Answer using this specific value:\n")), + FieldType::Enum(_) => Some(String::from("Answer with any of the categories:\n")), FieldType::Class(cls) => { - Some(if output_format_content.recursive_classes.contains(cls) { - "Answer in JSON using this schema: " + let type_prefix = match &options.hoisted_class_prefix { + RenderSetting::Always(prefix) if !prefix.is_empty() => prefix, + _ => RenderOptions::DEFAULT_TYPE_PREFIX_IN_RENDER_MESSAGE, + }; + + // Line break if schema else just inline the name. + let end = if output_format_content.recursive_classes.contains(cls) { + " " } else { - "Answer in JSON using this schema:\n" - }) + "\n" + }; + + Some(format!("Answer in JSON using this {type_prefix}:{end}")) + } + FieldType::List(_) => Some(String::from( + "Answer with a JSON Array using this schema:\n", + )), + FieldType::Union(_) => { + Some(String::from("Answer in JSON using any of these schemas:\n")) } - FieldType::List(_) => Some("Answer with a JSON Array using this schema:\n"), - FieldType::Union(_) => Some("Answer in JSON using any of these schemas:\n"), - FieldType::Optional(_) => Some("Answer in JSON using this schema:\n"), - FieldType::Map(_, _) => Some("Answer in JSON using this schema:\n"), + FieldType::Optional(_) => Some(String::from("Answer in JSON using this schema:\n")), + FieldType::Map(_, _) => Some(String::from("Answer in JSON using this schema:\n")), FieldType::Tuple(_) => None, - FieldType::Constrained { base, .. } => auto_prefix(base, output_format_content), + FieldType::Constrained { base, .. } => { + auto_prefix(base, options, output_format_content) + } } } match &options.prefix { - RenderSetting::Always(prefix) => Some(prefix.as_str()), + RenderSetting::Always(prefix) => Some(prefix.to_owned()), RenderSetting::Never => None, - RenderSetting::Auto => auto_prefix(&self.target, self), + RenderSetting::Auto => auto_prefix(&self.target, options, self), } } @@ -587,7 +601,7 @@ impl OutputFormatContent { } if let Some(p) = prefix { - output.push_str(p); + output.push_str(&p); } if let Some(m) = message { @@ -1662,7 +1676,7 @@ interface C { pointer: A or null, } -Answer in JSON using this schema: +Answer in JSON using this interface: { pointer: A, data: int,