feat(ai): added 2020-12 schema migration to ai strict validation

- Added draft-07-to-2020-12 schema upgrade logic for `$schema`, `definitions`, `$ref`, tuple, and nullable mapping.
- Integrated `upgradeJsonSchemaTo202012` into strict adaptation, validation, strict-mode, sanitizer, and wire/dereference flows.
- Replaced set-based traversal helpers with record maps, `for...in` loops, and epoch/`once` cycle guards.
- Added unreleased changelog entries and tests for schema normalization, `oneOf` to `anyOf`, and tuple validation edge cases.
This commit is contained in:
can1357
2026-05-15 22:38:05 +02:00
parent 09303733d5
commit 0d00f015ec
19 changed files with 1256 additions and 454 deletions
@@ -6,8 +6,10 @@ import {
sanitizeSchemaForCCA,
sanitizeSchemaForGoogle,
sanitizeSchemaForStrictMode,
schemaNeedsDraft202012Upgrade,
stripResidualCombiners,
tryEnforceStrictSchema,
upgradeJsonSchemaTo202012,
} from "@oh-my-pi/pi-ai/utils/schema";
// ---------------------------------------------------------------------------
@@ -94,6 +96,64 @@ describe("sanitizeSchemaForStrictMode", () => {
});
});
// ---------------------------------------------------------------------------
// upgradeJsonSchemaTo202012
// ---------------------------------------------------------------------------
describe("upgradeJsonSchemaTo202012", () => {
it("infers draft-07 tuple and dependency keywords without a $schema URI", () => {
const schema = {
type: "object",
properties: {
definitions: { type: "string" },
tuple: {
type: "array",
items: [{ type: "string" }, { type: "integer" }],
additionalItems: false,
},
gated: {
type: "object",
dependencies: {
a: ["b"],
c: { required: ["d"] },
},
},
},
definitions: {
Ref: { type: "string" },
},
};
expect(schemaNeedsDraft202012Upgrade(schema)).toBe(true);
expect(upgradeJsonSchemaTo202012(schema)).toEqual({
type: "object",
properties: {
definitions: { type: "string" },
tuple: {
type: "array",
prefixItems: [{ type: "string" }, { type: "integer" }],
items: false,
},
gated: {
type: "object",
dependentRequired: { a: ["b"] },
dependentSchemas: { c: { required: ["d"] } },
},
},
$defs: {
Ref: { type: "string" },
},
});
});
it("returns unchanged schemas by identity when no draft upgrade is needed", () => {
const schema = { type: "object", properties: { name: { type: "string" } } };
expect(schemaNeedsDraft202012Upgrade(schema)).toBe(false);
expect(upgradeJsonSchemaTo202012(schema)).toBe(schema);
});
});
// ---------------------------------------------------------------------------
// sanitizeSchemaForGoogle
// ---------------------------------------------------------------------------