use anyhow::Result;use language_model::LanguageModelToolSchemaFormat;use schemars::{ JsonSchema, schema::{RootSchema, Schema, SchemaObject},}; pub fn json_schema_for<T: JsonSchema>( format: LanguageModelToolSchemaFormat,) -> Result<serde_json::Value> { let schema = root_schema_for::<T>(format); schema_to_json(&schema, format)} fn schema_to_json( schema: &RootSchema, format: LanguageModelToolSchemaFormat,) -> Result<serde_json::Value> { let mut value = serde_json::to_value(schema)?; assistant_tool::adapt_schema_to_format(&mut value, format)?; Ok(value)} fn root_schema_for<T: JsonSchema>(format: LanguageModelToolSchemaFormat) -> RootSchema { let mut generator = match format { LanguageModelToolSchemaFormat::JsonSchema => schemars::SchemaGenerator::default(), LanguageModelToolSchemaFormat::JsonSchemaSubset => { schemars::r#gen::SchemaSettings::default() .with(|settings| { settings.meta_schema = None; settings.inline_subschemas = true; settings .visitors .push(Box::new(TransformToJsonSchemaSubsetVisitor)); }) .into_generator() } }; generator.root_schema_for::<T>()} #[derive(Debug, Clone)]struct TransformToJsonSchemaSubsetVisitor; impl schemars::visit::Visitor for TransformToJsonSchemaSubsetVisitor { fn visit_root_schema(&mut self, root: &mut RootSchema) { schemars::visit::visit_root_schema(self, root) } fn visit_schema(&mut self, schema: &mut Schema) { schemars::visit::visit_schema(self, schema) } fn visit_schema_object(&mut self, schema: &mut SchemaObject) { // Ensure that the type field is not an array, this happens when we use // Option<T>, the type will be [T, "null"]. if let Some(instance_type) = schema.instance_type.take() { schema.instance_type = match instance_type { schemars::schema::SingleOrVec::Single(t) => { Some(schemars::schema::SingleOrVec::Single(t)) } schemars::schema::SingleOrVec::Vec(items) => items .into_iter() .next() .map(schemars::schema::SingleOrVec::from), }; } // One of is not supported, use anyOf instead. if let Some(subschema) = schema.subschemas.as_mut() { if let Some(one_of) = subschema.one_of.take() { subschema.any_of = Some(one_of); } } schemars::visit::visit_schema_object(self, schema) }}
use anyhow::Result;
use language_model::LanguageModelToolSchemaFormat;
use schemars::{
JsonSchema,
schema::{RootSchema, Schema, SchemaObject},
};
pub fn json_schema_for<T: JsonSchema>(
format: LanguageModelToolSchemaFormat,
) -> Result<serde_json::Value> {
let schema = root_schema_for::<T>(format);
schema_to_json(&schema, format)
}
fn schema_to_json(
schema: &RootSchema,
format: LanguageModelToolSchemaFormat,
) -> Result<serde_json::Value> {
let mut value = serde_json::to_value(schema)?;
assistant_tool::adapt_schema_to_format(&mut value, format)?;
Ok(value)
}
fn root_schema_for<T: JsonSchema>(format: LanguageModelToolSchemaFormat) -> RootSchema {
let mut generator = match format {
LanguageModelToolSchemaFormat::JsonSchema => schemars::SchemaGenerator::default(),
LanguageModelToolSchemaFormat::JsonSchemaSubset => {
schemars::r#gen::SchemaSettings::default()
.with(|settings| {
settings.meta_schema = None;
settings.inline_subschemas = true;
settings
.visitors
.push(Box::new(TransformToJsonSchemaSubsetVisitor));
})
.into_generator()
}
};
generator.root_schema_for::<T>()
}
#[derive(Debug, Clone)]
struct TransformToJsonSchemaSubsetVisitor;
impl schemars::visit::Visitor for TransformToJsonSchemaSubsetVisitor {
fn visit_root_schema(&mut self, root: &mut RootSchema) {
schemars::visit::visit_root_schema(self, root)
}
fn visit_schema(&mut self, schema: &mut Schema) {
schemars::visit::visit_schema(self, schema)
}
fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
// Ensure that the type field is not an array, this happens when we use
// Option<T>, the type will be [T, "null"].
if let Some(instance_type) = schema.instance_type.take() {
schema.instance_type = match instance_type {
schemars::schema::SingleOrVec::Single(t) => {
Some(schemars::schema::SingleOrVec::Single(t))
}
schemars::schema::SingleOrVec::Vec(items) => items
.into_iter()
.next()
.map(schemars::schema::SingleOrVec::from),
};
}
// One of is not supported, use anyOf instead.
if let Some(subschema) = schema.subschemas.as_mut() {
if let Some(one_of) = subschema.one_of.take() {
subschema.any_of = Some(one_of);
}
}
schemars::visit::visit_schema_object(self, schema)
}
}