From fc7cd30bd15bedbdc6048c3fa24121410d2f74ae Mon Sep 17 00:00:00 2001 From: can1357 Date: Tue, 4 Aug 2026 18:25:07 +0200 Subject: [PATCH] fix(omptype): restored required-first wire ordering and defaulted optional keys - Restored required-before-optional property ordering in JSON Schema emission; downstream wire consumers (pi-ai toolWireSchema) rely on that stable ordering. - Mapped Type.Optional with a default to a plain defaulted key in the TypeBox shim, since omptype (like ArkType) rejects optional keys that specify defaults. --- packages/omptype/src/json-schema.ts | 5 ++++- packages/omptype/src/typebox.ts | 6 +++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/omptype/src/json-schema.ts b/packages/omptype/src/json-schema.ts index b5f050831..31844189e 100644 --- a/packages/omptype/src/json-schema.ts +++ b/packages/omptype/src/json-schema.ts @@ -273,7 +273,10 @@ function emitObject( const properties: Record = {}; const required: string[] = []; const filled = (prop: PropIR): boolean => !prop.opt && (ctx.options?.io === "output" || !prop.hasDefault); - for (const prop of props) { + // ArkType emits required properties first (each group in declaration + // order); downstream wire consumers rely on that stable ordering. + const ordered = [...props.filter(filled), ...props.filter(prop => !filled(prop))]; + for (const prop of ordered) { if (typeof prop.key === "symbol") throw new TypeError("Cannot convert a symbol to a string"); const key = String(prop.key); const propertySchema = emit(prop.val, ctx); diff --git a/packages/omptype/src/typebox.ts b/packages/omptype/src/typebox.ts index c3243050a..2654f5372 100644 --- a/packages/omptype/src/typebox.ts +++ b/packages/omptype/src/typebox.ts @@ -401,7 +401,11 @@ function tObject>(properties: P, opts? for (const key in properties) { const schema = properties[key]; const inner = asRuntime(schema)[OPTIONAL_INNER]; - def[inner ? `${key}?` : key] = inner ?? schema; + // A defaulted `Type.Optional(...)` maps to a plain defaulted key: + // omptype (like ArkType) rejects `key?` with a default, and a default + // already makes the key omittable on input. + const optionalKey = inner !== undefined && !asRuntime(inner).hasDefault; + def[optionalKey ? `${key}?` : key] = inner ?? schema; props[key] = schema; } if (opts?.additionalProperties === false) def["+"] = "reject";