fix(stage-ui): normalize spark:command tool schema (#1845)

This commit is contained in:
Neko
2026-05-19 19:07:29 +08:00
committed by GitHub
parent c04f4773c5
commit 6b31552a16
6 changed files with 65 additions and 10 deletions
@@ -51,7 +51,7 @@
},
"inlinedDependencies": {
"@electron-toolkit/preload": "3.0.2",
"@moeru/eventa": "catalog:",
"@moeru/eventa": "1.0.0-beta.5",
"async-mutex": "0.5.0",
"nanoid": [
"5.1.11",
@@ -66,7 +66,7 @@ signIn:
footer:
prefix: Al continuar, aceptas nuestros
terms: Términos
and: "y"
and: 'y'
privacy: Política de Privacidad
verifyEmail:
title:
+2 -2
View File
@@ -685,7 +685,7 @@ pages:
empty: Здесь пока ничего нет. Добавьте одно ниже!
add:
title: Новый
description: "Заполните новый сервер, затем нажмите кнопку «Сохранить и перезапустить» — он будет перемещен в «Конфигурация» выше."
description: 'Заполните новый сервер, затем нажмите кнопку «Сохранить и перезапустить» — он будет перемещен в «Конфигурация» выше.'
pending-badge: Не сохранено
status:
unknown: Не загружен
@@ -902,7 +902,7 @@ pages:
description: >-
Провайдеры транскрипции (speech-to-text): Whisper.cpp, OpenAI, Azure Speech
artistry:
title: Artistry
title: Artistry
description: Поставщики моделей генерации и создания изображений, например ComfyUI, Replicate.
items:
comfyui:
@@ -685,7 +685,7 @@ pages:
empty: 这里什么都还没有哦,在下面添加一个!
add:
title: 新建
description: "填写新的服务器配置,然后点击「保存并重启」,完成后将会更新至上方的「已配置」"
description: '填写新的服务器配置,然后点击「保存并重启」,完成后将会更新至上方的「已配置」'
pending-badge: 未保存
status:
unknown: 未加载
@@ -178,13 +178,22 @@ export function normalizeNullableAnyOf(schema: JsonSchema): JsonSchema {
const next: JsonSchema = { ...schema }
if (next.properties) {
next.properties = Object.fromEntries(
const properties = Object.fromEntries(
Object.entries(next.properties).map(([key, value]) => {
if (!isJsonSchema(value))
return [key, value]
return [key, normalizeNullableAnyOf(value)]
}),
)
next.properties = properties
if (Array.isArray(next.required)) {
const propertyNames = new Set(Object.keys(properties))
next.required = next.required.filter(key => propertyNames.has(key))
if (next.required.length === 0)
delete next.required
}
}
if (Array.isArray(next.items)) {
@@ -59,9 +59,10 @@ describe('tools/character/orchestrator/spark-command', () => {
testField: z.union([z.string(), z.null()]),
}))
const normalized = normalizeNullableAnyOf(schemaTestUnion as JsonSchema)
const testField = normalized.properties?.testField as JsonSchema
expect((normalized.properties?.testField as JsonSchema).type).toEqual(['string', 'null'])
expect((normalized.properties?.testField as JsonSchema).anyOf).toBeUndefined()
expect(testField.type).toEqual(['string', 'null'])
expect(testField.anyOf).toBeUndefined()
})
it('deduplicates primitive types after normalization', async () => {
@@ -69,9 +70,54 @@ describe('tools/character/orchestrator/spark-command', () => {
testField: z.union([z.literal('force'), z.literal('soft'), z.literal(false)]),
}))
const normalized = normalizeNullableAnyOf(schemaTestUnion as JsonSchema)
const testField = normalized.properties?.testField as JsonSchema
expect((normalized.properties?.testField as JsonSchema).type).toEqual(['string', 'boolean'])
expect((normalized.properties?.testField as JsonSchema).anyOf).toBeUndefined()
expect(testField.type).toEqual(['string', 'boolean'])
expect(testField.anyOf).toBeUndefined()
})
it('removes required keys that are not declared in sibling properties', () => {
const normalized = normalizeNullableAnyOf({
type: 'object',
properties: {
contexts: {
anyOf: [
{
type: 'array',
items: {
type: 'object',
properties: {
metadata: {
anyOf: [
{
type: 'array',
items: {
type: 'object',
properties: {
key: { type: 'string' },
},
required: ['key', 'value'],
},
},
{ type: 'null' },
],
},
},
},
},
{ type: 'null' },
],
},
},
required: ['contexts'],
} as JsonSchema)
const contexts = getArraySchema(normalized.properties?.contexts as JsonSchema)
const contextItem = contexts?.items as JsonSchema
const metadata = getArraySchema(contextItem.properties?.metadata as JsonSchema)
const metadataItem = metadata?.items as JsonSchema
expect(metadataItem.required).toEqual(['key'])
})
it('should render sparkNotifyCommandItemSchema into correct schema', async () => {