Handle nullable arrays in tool inputSchemas
* In DynamicJsonForm.tsx
- In debouncedUpdateParent, formatJson, and validateJson,
- when trimming the JSON value, use ?.trim() in case the field is null
* In jsonUtils.ts
- in tryParseJson
- use ?.trim() in case the field is null
* In schemaUtils.ts
- in normalizeUnionType
- add condition to handle the case where there is an anyOf with array or null as options
* In ToolsTab.tsx
- for nullable fields, in null checkbox, in onCheckedChange handler
- when not checked, if prop type is array, set to undefined (empty input field that can be edited rather than the word "null" as the default could provide
Fixes #846
This commit is contained in:
parent
c7683b464a
commit
37acee9283
4 changed files with 28 additions and 15 deletions
|
|
@ -113,8 +113,8 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
||||||
setJsonError(errorMessage);
|
setJsonError(errorMessage);
|
||||||
|
|
||||||
// Reset to default for clearly invalid JSON (not just incomplete typing)
|
// Reset to default for clearly invalid JSON (not just incomplete typing)
|
||||||
const trimmed = jsonString.trim();
|
const trimmed = jsonString?.trim();
|
||||||
if (trimmed.length > 5 && !trimmed.match(/^[\s[{]/)) {
|
if (trimmed && trimmed.length > 5 && !trimmed.match(/^[\s[{]/)) {
|
||||||
onChange(generateDefaultValue(schema));
|
onChange(generateDefaultValue(schema));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -155,7 +155,7 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
||||||
|
|
||||||
const formatJson = () => {
|
const formatJson = () => {
|
||||||
try {
|
try {
|
||||||
const jsonStr = rawJsonValue.trim();
|
const jsonStr = rawJsonValue?.trim();
|
||||||
if (!jsonStr) {
|
if (!jsonStr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -171,7 +171,7 @@ const DynamicJsonForm = forwardRef<DynamicJsonFormRef, DynamicJsonFormProps>(
|
||||||
const validateJson = () => {
|
const validateJson = () => {
|
||||||
if (!isJsonMode) return { isValid: true, error: null };
|
if (!isJsonMode) return { isValid: true, error: null };
|
||||||
try {
|
try {
|
||||||
const jsonStr = rawJsonValue.trim();
|
const jsonStr = rawJsonValue?.trim();
|
||||||
if (!jsonStr) return { isValid: true, error: null };
|
if (!jsonStr) return { isValid: true, error: null };
|
||||||
const parsed = JSON.parse(jsonStr);
|
const parsed = JSON.parse(jsonStr);
|
||||||
// Clear any pending debounced update and immediately update parent
|
// Clear any pending debounced update and immediately update parent
|
||||||
|
|
|
||||||
|
|
@ -181,16 +181,18 @@ const ToolsTab = ({
|
||||||
...params,
|
...params,
|
||||||
[key]: checked
|
[key]: checked
|
||||||
? null
|
? null
|
||||||
: prop.default !== null
|
: prop.type === "array"
|
||||||
? prop.default
|
? undefined
|
||||||
: prop.type === "boolean"
|
: prop.default !== null
|
||||||
? false
|
? prop.default
|
||||||
: prop.type === "string"
|
: prop.type === "boolean"
|
||||||
? ""
|
? false
|
||||||
: prop.type === "number" ||
|
: prop.type === "string"
|
||||||
prop.type === "integer"
|
? ""
|
||||||
? undefined
|
: prop.type === "number" ||
|
||||||
: undefined,
|
prop.type === "integer"
|
||||||
|
? undefined
|
||||||
|
: undefined,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -84,8 +84,9 @@ export function tryParseJson(str: string): {
|
||||||
success: boolean;
|
success: boolean;
|
||||||
data: JsonValue;
|
data: JsonValue;
|
||||||
} {
|
} {
|
||||||
const trimmed = str.trim();
|
const trimmed = str?.trim();
|
||||||
if (
|
if (
|
||||||
|
trimmed &&
|
||||||
!(trimmed.startsWith("{") && trimmed.endsWith("}")) &&
|
!(trimmed.startsWith("{") && trimmed.endsWith("}")) &&
|
||||||
!(trimmed.startsWith("[") && trimmed.endsWith("]"))
|
!(trimmed.startsWith("[") && trimmed.endsWith("]"))
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,16 @@ export function normalizeUnionType(schema: JsonSchemaType): JsonSchemaType {
|
||||||
return { ...schema, type: "integer", anyOf: undefined, nullable: true };
|
return { ...schema, type: "integer", anyOf: undefined, nullable: true };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle anyOf with exactly array and null (FastMCP pattern)
|
||||||
|
if (
|
||||||
|
schema.anyOf &&
|
||||||
|
schema.anyOf.length === 2 &&
|
||||||
|
schema.anyOf.some((t) => (t as JsonSchemaType).type === "array") &&
|
||||||
|
schema.anyOf.some((t) => (t as JsonSchemaType).type === "null")
|
||||||
|
) {
|
||||||
|
return { ...schema, type: "array", anyOf: undefined, nullable: true };
|
||||||
|
}
|
||||||
|
|
||||||
// Handle array type with exactly string and null
|
// Handle array type with exactly string and null
|
||||||
if (
|
if (
|
||||||
Array.isArray(schema.type) &&
|
Array.isArray(schema.type) &&
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue