From f60a04d13c60071b555f9c615ebe17e65ec294f0 Mon Sep 17 00:00:00 2001 From: luvs01 Date: Thu, 13 Aug 2026 11:10:30 +0900 Subject: [PATCH] fix(kiro): preserve keyword-named composed properties --- src/adapters/kiro-tools.ts | 4 ++-- tests/kiro-adapter.test.ts | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/adapters/kiro-tools.ts b/src/adapters/kiro-tools.ts index 6aa8bb2a42..c25e55ae05 100644 --- a/src/adapters/kiro-tools.ts +++ b/src/adapters/kiro-tools.ts @@ -103,7 +103,7 @@ function ensureRootObjectType(schema: unknown): Record { // Seed with the root's own properties/required so a schema like // { type:"object", properties:{path}, required:["path"], oneOf:[...] } keeps them. if (obj.properties && typeof obj.properties === "object") { - Object.assign(props, sanitizeKiroSchema(obj.properties) as Record); + Object.assign(props, sanitizeSchemaMap(obj.properties) as Record); } if (Array.isArray(obj.required)) { for (const r of obj.required) if (typeof r === "string") required.add(r); @@ -118,7 +118,7 @@ function ensureRootObjectType(schema: unknown): Record { if (!variant || typeof variant !== "object" || Array.isArray(variant)) continue; const v = variant as Record; if (v.properties && typeof v.properties === "object") { - Object.assign(props, sanitizeKiroSchema(v.properties) as Record); + Object.assign(props, sanitizeSchemaMap(v.properties) as Record); } if (mergeRequired && Array.isArray(v.required)) { for (const r of v.required) if (typeof r === "string") required.add(r); diff --git a/tests/kiro-adapter.test.ts b/tests/kiro-adapter.test.ts index 779816a559..e0354a43e4 100644 --- a/tests/kiro-adapter.test.ts +++ b/tests/kiro-adapter.test.ts @@ -674,6 +674,16 @@ describe("kiro adapter — buildRequest", () => { const withDefs = await pick({ $defs: { X: { type: "string" } }, anyOf: [{ properties: { a: { $ref: "#/$defs/X" } } }] }); expect(withDefs.$defs).toEqual({ X: { type: "string" } }); expect(withDefs.properties).toEqual({ a: { $ref: "#/$defs/X" } }); + + // Property names remain data while flattening, even when they collide with rejected keywords. + const keywordNames = await pick({ + properties: { format: { type: "string", format: "uuid" } }, + required: ["format"], + oneOf: [{ properties: { pattern: { type: "string", pattern: "^x" } } }], + }); + expect(keywordNames.properties.format).toEqual({ type: "string" }); + expect(keywordNames.properties.pattern).toEqual({ type: "string" }); + expect(keywordNames.required).toEqual(["format"]); }); test("tool descriptions use deterministic model-specific caps without prompt injection", async () => {