Skip to content

Commit dbc419c

Browse files
committed
feat: Update Anthropic schema cleaning to preserve default, oneOf, anyOf, allOf and conditionally remove additionalProperties.
1 parent 6396ae7 commit dbc419c

File tree

1 file changed

+37
-9
lines changed

1 file changed

+37
-9
lines changed

src/ax/ai/anthropic/api.ts

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,34 +34,62 @@ import {
3434
* Clean function schema for Anthropic API compatibility
3535
* Anthropic uses input_schema and may not support certain JSON Schema fields
3636
*/
37-
const cleanSchemaForAnthropic = (schema: any): any => {
37+
const cleanSchemaForAnthropic = (
38+
schema: any,
39+
preserveAdditionalProperties: boolean = false
40+
): any => {
3841
if (!schema || typeof schema !== 'object') {
3942
return schema;
4043
}
4144

4245
const cleaned = { ...schema };
4346

4447
// Remove fields that might cause issues with Anthropic
45-
delete cleaned.additionalProperties;
46-
delete cleaned.default;
48+
if (!preserveAdditionalProperties) {
49+
delete cleaned.additionalProperties;
50+
}
51+
52+
// Anthropic supports default, anyOf, allOf, const, enum.
53+
// We only remove fields that are definitely not supported or non-standard.
4754
delete cleaned.optional;
48-
delete cleaned.oneOf;
49-
delete cleaned.anyOf;
50-
delete cleaned.allOf;
55+
// delete cleaned.default; // Supported
56+
// delete cleaned.oneOf; // Supported
57+
// delete cleaned.anyOf; // Supported
58+
// delete cleaned.allOf; // Supported
5159

5260
// Recursively clean properties
5361
if (cleaned.properties && typeof cleaned.properties === 'object') {
5462
cleaned.properties = Object.fromEntries(
5563
Object.entries(cleaned.properties).map(([key, value]) => [
5664
key,
57-
cleanSchemaForAnthropic(value),
65+
cleanSchemaForAnthropic(value, preserveAdditionalProperties),
5866
])
5967
);
6068
}
6169

6270
// Recursively clean items (for arrays)
6371
if (cleaned.items) {
64-
cleaned.items = cleanSchemaForAnthropic(cleaned.items);
72+
cleaned.items = cleanSchemaForAnthropic(
73+
cleaned.items,
74+
preserveAdditionalProperties
75+
);
76+
}
77+
78+
// Recursively clean anyOf, allOf, oneOf
79+
if (Array.isArray(cleaned.anyOf)) {
80+
cleaned.anyOf = cleaned.anyOf.map((s: any) =>
81+
cleanSchemaForAnthropic(s, preserveAdditionalProperties)
82+
);
83+
}
84+
if (Array.isArray(cleaned.allOf)) {
85+
cleaned.allOf = cleaned.allOf.map((s: any) =>
86+
cleanSchemaForAnthropic(s, preserveAdditionalProperties)
87+
);
88+
}
89+
if (Array.isArray(cleaned.oneOf)) {
90+
cleaned.oneOf = cleaned.oneOf.map((s: any) =>
91+
cleanSchemaForAnthropic(s, preserveAdditionalProperties)
92+
);
6593
}
6694

6795
return cleaned;
@@ -395,7 +423,7 @@ class AxAIAnthropicImpl
395423

396424
outputFormat = {
397425
type: 'json_schema',
398-
schema: cleanSchemaForAnthropic(schema),
426+
schema: cleanSchemaForAnthropic(schema, true),
399427
};
400428
this.usedStructuredOutput = true;
401429
}

0 commit comments

Comments
 (0)