diff --git a/client/src/components/ToolsTab.tsx b/client/src/components/ToolsTab.tsx index 9d3dca70..cd8e2ad5 100644 --- a/client/src/components/ToolsTab.tsx +++ b/client/src/components/ToolsTab.tsx @@ -159,17 +159,21 @@ const ToolsTab = ({ id={key} name={key} placeholder={prop.description} - value={(params[key] as string) ?? ""} + value={ + params[key] === undefined + ? "" + : String(params[key]) + } onChange={(e) => { const value = e.target.value; - if (value === "" && !required) { - // Optional field cleared - set to undefined to omit from request + if (value === "") { + // Field cleared - set to undefined setParams({ ...params, [key]: undefined, }); } else { - // Field has value or is required - keep as string + // Field has value - keep as string setParams({ ...params, [key]: value, @@ -206,22 +210,26 @@ const ToolsTab = ({ id={key} name={key} placeholder={prop.description} - value={(params[key] as string) ?? ""} + value={ + params[key] === undefined + ? "" + : String(params[key]) + } onChange={(e) => { const value = e.target.value; - if (value === "" && !required) { - // Optional field cleared - set to undefined to omit from request + if (value === "") { + // Field cleared - set to undefined setParams({ ...params, [key]: undefined, }); } else { - // Field has value or is required - convert to number + // Field has value - convert to number (never store strings) const num = Number(value); - if (!isNaN(num) || value === "") { + if (!isNaN(num)) { setParams({ ...params, - [key]: value === "" ? "" : num, + [key]: num, }); } } diff --git a/client/src/utils/__tests__/paramUtils.test.ts b/client/src/utils/__tests__/paramUtils.test.ts index 84735a04..3dfd5382 100644 --- a/client/src/utils/__tests__/paramUtils.test.ts +++ b/client/src/utils/__tests__/paramUtils.test.ts @@ -2,7 +2,7 @@ import { cleanParams } from "../paramUtils"; import type { JsonSchemaType } from "../jsonUtils"; describe("cleanParams", () => { - it("should preserve required fields even when empty", () => { + it("should preserve required fields even when undefined", () => { const schema: JsonSchemaType = { type: "object", required: ["requiredString", "requiredNumber"], @@ -15,17 +15,17 @@ describe("cleanParams", () => { }; const params = { - requiredString: "", - requiredNumber: 0, - optionalString: "", + requiredString: undefined, + requiredNumber: undefined, + optionalString: undefined, optionalNumber: undefined, }; const cleaned = cleanParams(params, schema); expect(cleaned).toEqual({ - requiredString: "", - requiredNumber: 0, + requiredString: undefined, + requiredNumber: undefined, // optionalString and optionalNumber should be omitted }); }); @@ -181,4 +181,28 @@ describe("cleanParams", () => { optionalNumber: 0, }); }); + + it("should handle the new undefined-first approach (no empty strings)", () => { + const schema: JsonSchemaType = { + type: "object", + required: ["requiredField"], + properties: { + requiredField: { type: "string" }, + optionalField: { type: "string" }, + }, + }; + + // New behavior: cleared fields are undefined, never empty strings + const params = { + requiredField: undefined, // cleared required field + optionalField: undefined, // cleared optional field + }; + + const cleaned = cleanParams(params, schema); + + expect(cleaned).toEqual({ + requiredField: undefined, // required field preserved as undefined + // optionalField omitted entirely + }); + }); });