schema.rs

 1use anyhow::Result;
 2use language_model::LanguageModelToolSchemaFormat;
 3use schemars::{
 4    JsonSchema,
 5    schema::{RootSchema, Schema, SchemaObject},
 6};
 7
 8pub fn json_schema_for<T: JsonSchema>(
 9    format: LanguageModelToolSchemaFormat,
10) -> Result<serde_json::Value> {
11    let schema = root_schema_for::<T>(format);
12    schema_to_json(&schema, format)
13}
14
15fn schema_to_json(
16    schema: &RootSchema,
17    format: LanguageModelToolSchemaFormat,
18) -> Result<serde_json::Value> {
19    let mut value = serde_json::to_value(schema)?;
20    assistant_tool::adapt_schema_to_format(&mut value, format)?;
21    Ok(value)
22}
23
24fn root_schema_for<T: JsonSchema>(format: LanguageModelToolSchemaFormat) -> RootSchema {
25    let mut generator = match format {
26        LanguageModelToolSchemaFormat::JsonSchema => schemars::SchemaGenerator::default(),
27        LanguageModelToolSchemaFormat::JsonSchemaSubset => {
28            schemars::r#gen::SchemaSettings::default()
29                .with(|settings| {
30                    settings.meta_schema = None;
31                    settings.inline_subschemas = true;
32                    settings
33                        .visitors
34                        .push(Box::new(TransformToJsonSchemaSubsetVisitor));
35                })
36                .into_generator()
37        }
38    };
39    generator.root_schema_for::<T>()
40}
41
42#[derive(Debug, Clone)]
43struct TransformToJsonSchemaSubsetVisitor;
44
45impl schemars::visit::Visitor for TransformToJsonSchemaSubsetVisitor {
46    fn visit_root_schema(&mut self, root: &mut RootSchema) {
47        schemars::visit::visit_root_schema(self, root)
48    }
49
50    fn visit_schema(&mut self, schema: &mut Schema) {
51        schemars::visit::visit_schema(self, schema)
52    }
53
54    fn visit_schema_object(&mut self, schema: &mut SchemaObject) {
55        // Ensure that the type field is not an array, this happens when we use
56        // Option<T>, the type will be [T, "null"].
57        if let Some(instance_type) = schema.instance_type.take() {
58            schema.instance_type = match instance_type {
59                schemars::schema::SingleOrVec::Single(t) => {
60                    Some(schemars::schema::SingleOrVec::Single(t))
61                }
62                schemars::schema::SingleOrVec::Vec(items) => items
63                    .into_iter()
64                    .next()
65                    .map(schemars::schema::SingleOrVec::from),
66            };
67        }
68
69        // One of is not supported, use anyOf instead.
70        if let Some(subschema) = schema.subschemas.as_mut() {
71            if let Some(one_of) = subschema.one_of.take() {
72                subschema.any_of = Some(one_of);
73            }
74        }
75
76        schemars::visit::visit_schema_object(self, schema)
77    }
78}