systemprompt_models/schema/
capabilities.rs1use serde_json::Value;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub struct SchemaComposition {
15 pub allof: bool,
16 pub anyof: bool,
17 pub oneof: bool,
18 pub if_then_else: bool,
19 pub not: bool,
20}
21
22#[expect(
23 clippy::struct_excessive_bools,
24 reason = "schema feature matrix: each bool is an independent JSON-Schema construct the \
25 provider does or does not accept, not state"
26)]
27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
28pub struct SchemaFeatures {
29 pub references: bool,
30 pub definitions: bool,
31 pub additional_properties: bool,
32 pub const_values: bool,
33 pub exclusive_bounds: bool,
36 pub property_names: bool,
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)]
42pub struct ProviderCapabilities {
43 pub composition: SchemaComposition,
44 pub features: SchemaFeatures,
45}
46
47impl ProviderCapabilities {
48 pub const fn anthropic() -> Self {
49 Self {
50 composition: SchemaComposition {
51 allof: true,
52 anyof: true,
53 oneof: true,
54 if_then_else: true,
55 not: true,
56 },
57 features: SchemaFeatures {
58 references: true,
59 definitions: true,
60 additional_properties: true,
61 const_values: true,
62 exclusive_bounds: true,
63 property_names: true,
64 },
65 }
66 }
67
68 pub const fn openai() -> Self {
69 Self {
70 composition: SchemaComposition {
71 allof: true,
72 anyof: true,
73 oneof: true,
74 if_then_else: false,
75 not: false,
76 },
77 features: SchemaFeatures {
78 references: true,
79 definitions: true,
80 additional_properties: true,
81 const_values: true,
82 exclusive_bounds: true,
83 property_names: true,
84 },
85 }
86 }
87
88 pub const fn gemini() -> Self {
89 Self {
90 composition: SchemaComposition {
91 allof: false,
92 anyof: true,
93 oneof: false,
94 if_then_else: false,
95 not: false,
96 },
97 features: SchemaFeatures {
98 references: false,
99 definitions: false,
100 additional_properties: false,
101 const_values: false,
102 exclusive_bounds: false,
103 property_names: false,
104 },
105 }
106 }
107
108 pub fn requires_transformation(&self, schema: &Value) -> bool {
109 if let Some(obj) = schema.as_object() {
110 if obj.contains_key("allOf") && !self.composition.allof {
111 return true;
112 }
113 if obj.contains_key("anyOf") && !self.composition.anyof {
114 return true;
115 }
116 if obj.contains_key("oneOf") && !self.composition.oneof {
117 return true;
118 }
119 if obj.contains_key("if") && !self.composition.if_then_else {
120 return true;
121 }
122 if obj.contains_key("$ref") && !self.features.references {
123 return true;
124 }
125 if (obj.contains_key("definitions") || obj.contains_key("$defs"))
126 && !self.features.definitions
127 {
128 return true;
129 }
130 if obj.contains_key("not") && !self.composition.not {
131 return true;
132 }
133 }
134 false
135 }
136}