-
Notifications
You must be signed in to change notification settings - Fork 755
fix(kosong/kimi): move parent type into anyOf/oneOf/allOf items #2182
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -116,8 +116,9 @@ const NUMERIC_STRUCTURE_KEYS = new Set([ | |
| * a provider-compatibility normalizer, not a complete JSON Schema compiler: | ||
| * it resolves local refs, preserves combinator nodes, infers obvious | ||
| * scalar/object/array types, and falls back to `string` only for nested | ||
| * typeless property schemas. The root schema object is treated as a container | ||
| * and is not itself normalized. | ||
| * typeless property schemas. It also rewrites nodes that declare `type` | ||
| * alongside a combinator (`anyOf` / `oneOf` / `allOf`), which Moonshot | ||
| * rejects, by moving the parent `type` into each combinator item. | ||
| */ | ||
| export function normalizeKimiToolSchema(schema: Record<string, unknown>): Record<string, unknown> { | ||
| return ensureKimiPropertyTypes(derefJsonSchema(schema)); | ||
|
|
@@ -128,10 +129,36 @@ function ensureKimiPropertyTypes(schema: Record<string, unknown>): Record<string | |
| if (!isRecord(normalized)) { | ||
| throw new Error('JSON Schema root must normalize to an object.'); | ||
| } | ||
| fixCombinatorParentType(normalized); | ||
| recurseSchema(normalized); | ||
| return normalized; | ||
| } | ||
|
|
||
| /** | ||
| * Moonshot's tool validator rejects schemas that declare `type` on the same | ||
| * node as a combinator (`anyOf` / `oneOf` / `allOf`): the type must live on | ||
| * each combinator item instead. Distribute the parent `type` into items that | ||
| * lack one and drop it from the parent. Since the parent `type` constrained | ||
| * every variant anyway, copying it into each item preserves the semantics. | ||
| */ | ||
| function fixCombinatorParentType(node: unknown): void { | ||
| if (!isRecord(node) || !hasOwn(node, 'type')) { | ||
| return; | ||
| } | ||
| for (const key of ['anyOf', 'oneOf', 'allOf']) { | ||
| const items = node[key]; | ||
| if (!Array.isArray(items) || items.length === 0) { | ||
| continue; | ||
| } | ||
| for (const item of items) { | ||
| if (isRecord(item) && !hasOwn(item, 'type')) { | ||
| item['type'] = node['type']; | ||
| } | ||
| } | ||
| delete node['type']; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a schema contains more than one combinator, the first iteration deletes Useful? React with 👍 / 👎. |
||
| } | ||
| } | ||
|
|
||
| function hasUnresolvedDefinitionRef(node: unknown, bucketKey: string): boolean { | ||
| if (Array.isArray(node)) { | ||
| return node.some((child) => hasUnresolvedDefinitionRef(child, bucketKey)); | ||
|
|
@@ -300,6 +327,8 @@ function normalizeProperty(node: unknown): void { | |
| return; | ||
| } | ||
|
|
||
| fixCombinatorParentType(node); | ||
|
|
||
| if (!hasOwn(node, 'type') && !hasAnyKey(node, TYPE_COMPLETION_SKIP_KEYS)) { | ||
| const enumValues = node['enum']; | ||
| if (Array.isArray(enumValues) && enumValues.length > 0) { | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a combinator item already has a conflicting
type, leaving it untouched while deleting the parent type changes the schema's accepted values. For example,{type:'object', anyOf:[{type:'string'}, {required:['a']}]}originally rejects strings because the parent requires an object, but the normalized schema accepts them through the first branch;{type:'object', allOf:[{type:'string'}]}similarly changes from unsatisfiable to a string schema. The rewrite must preserve the parent constraint for explicitly typed items as well, or reject conflicting schemas rather than broadening them.Useful? React with 👍 / 👎.