mirror of
https://github.com/openclaw/openclaw.git
synced 2026-06-22 11:48:11 +00:00
fix: preserve non-oneOf schema array order (#91891)
This commit is contained in:
@@ -385,10 +385,19 @@ export function normalizeGeneratedTypeScript(text: string): string {
|
||||
.replaceAll("| null | null", "| null");
|
||||
}
|
||||
|
||||
export function canonicalizeCodexAppServerProtocolJson(value: unknown): unknown {
|
||||
// Sort typed-object arrays for schema keywords whose item order does not affect
|
||||
// payload validity; preserve order everywhere else, especially prefixItems.
|
||||
const typeSortedSchemaArrayKeys = new Set(["anyOf", "enum", "oneOf", "required"]);
|
||||
|
||||
export function canonicalizeCodexAppServerProtocolJson(
|
||||
value: unknown,
|
||||
parentKey?: string,
|
||||
): unknown {
|
||||
if (Array.isArray(value)) {
|
||||
const items = value.map(canonicalizeCodexAppServerProtocolJson);
|
||||
return sortCodexProtocolJsonArrayByType(items);
|
||||
const items = value.map((item) => canonicalizeCodexAppServerProtocolJson(item));
|
||||
return parentKey !== undefined && typeSortedSchemaArrayKeys.has(parentKey)
|
||||
? sortCodexProtocolJsonArrayByType(items)
|
||||
: items;
|
||||
}
|
||||
|
||||
if (!isPlainObject(value)) {
|
||||
@@ -397,7 +406,7 @@ export function canonicalizeCodexAppServerProtocolJson(value: unknown): unknown
|
||||
|
||||
const sorted: Record<string, unknown> = {};
|
||||
const entries = Object.entries(value)
|
||||
.map(([key, child]) => [key, canonicalizeCodexAppServerProtocolJson(child)] as const)
|
||||
.map(([key, child]) => [key, canonicalizeCodexAppServerProtocolJson(child, key)] as const)
|
||||
.toSorted(([left], [right]) => {
|
||||
if (left < right) {
|
||||
return -1;
|
||||
|
||||
@@ -206,16 +206,31 @@ describe("Codex app-server protocol JSON canonicalizer", () => {
|
||||
`);
|
||||
});
|
||||
|
||||
it("sorts arrays only when plain object items expose top-level type values", () => {
|
||||
it("sorts typed-object arrays only for order-insensitive schema keywords", () => {
|
||||
expect(
|
||||
canonicalizeCodexAppServerProtocolJson({
|
||||
enum: ["z", "a"],
|
||||
anyOf: [
|
||||
{ z: 1, type: "string" },
|
||||
{ type: "integer", a: 2 },
|
||||
],
|
||||
enum: [
|
||||
{ z: 1, type: "z" },
|
||||
{ type: "a", a: 2 },
|
||||
],
|
||||
mixed: [{ type: "b" }, "item", { type: "a" }],
|
||||
oneOf: [
|
||||
{ title: "Second", z: true },
|
||||
{ a: true, title: "First" },
|
||||
{ type: "object", z: true },
|
||||
{ a: true, type: "array" },
|
||||
{ type: "object", z: false },
|
||||
],
|
||||
prefixItems: [
|
||||
{ z: 1, type: "string" },
|
||||
{ type: "number", a: 2 },
|
||||
],
|
||||
required: [
|
||||
{ z: 1, type: "z" },
|
||||
{ type: "a", a: 2 },
|
||||
],
|
||||
required: ["z", "a"],
|
||||
typed: [
|
||||
{ type: "beta", z: 1 },
|
||||
{ type: "alpha", z: 2 },
|
||||
@@ -223,16 +238,31 @@ describe("Codex app-server protocol JSON canonicalizer", () => {
|
||||
],
|
||||
}),
|
||||
).toEqual({
|
||||
enum: ["z", "a"],
|
||||
anyOf: [
|
||||
{ a: 2, type: "integer" },
|
||||
{ type: "string", z: 1 },
|
||||
],
|
||||
enum: [
|
||||
{ a: 2, type: "a" },
|
||||
{ type: "z", z: 1 },
|
||||
],
|
||||
mixed: [{ type: "b" }, "item", { type: "a" }],
|
||||
oneOf: [
|
||||
{ title: "Second", z: true },
|
||||
{ a: true, title: "First" },
|
||||
{ a: true, type: "array" },
|
||||
{ type: "object", z: true },
|
||||
{ type: "object", z: false },
|
||||
],
|
||||
prefixItems: [
|
||||
{ type: "string", z: 1 },
|
||||
{ a: 2, type: "number" },
|
||||
],
|
||||
required: [
|
||||
{ a: 2, type: "a" },
|
||||
{ type: "z", z: 1 },
|
||||
],
|
||||
required: ["z", "a"],
|
||||
typed: [
|
||||
{ type: "alpha", z: 2 },
|
||||
{ type: "beta", z: 1 },
|
||||
{ type: "alpha", z: 2 },
|
||||
{ type: "beta", z: 3 },
|
||||
],
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user