From db9a3b6c418727ea65fd1a7cc005d590897f5644 Mon Sep 17 00:00:00 2001 From: Kit Langton Date: Tue, 11 Aug 2026 12:09:37 -0400 Subject: [PATCH] refactor(core): compact question tool schema (#41772) --- packages/core/src/tool/plugin/question.ts | 4 +++- packages/core/test/tool-question.test.ts | 24 +++++++++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/packages/core/src/tool/plugin/question.ts b/packages/core/src/tool/plugin/question.ts index 1ab11db94b..4dd848cc4c 100644 --- a/packages/core/src/tool/plugin/question.ts +++ b/packages/core/src/tool/plugin/question.ts @@ -21,7 +21,9 @@ Usage notes: - If you recommend a specific option, make that the first option in the list and add "(Recommended)" at the end of the label` export const Input = Schema.Struct({ - questions: Schema.NonEmptyArray(Question.Prompt).annotate({ description: "Questions to ask" }), + questions: Schema.Array(Question.Prompt) + .check(Schema.isNonEmpty()) + .annotate({ description: "Questions to ask" }), }) export const Output = Schema.Struct({ diff --git a/packages/core/test/tool-question.test.ts b/packages/core/test/tool-question.test.ts index 9193ecab25..8fe3d6ab01 100644 --- a/packages/core/test/tool-question.test.ts +++ b/packages/core/test/tool-question.test.ts @@ -89,6 +89,30 @@ const it = testEffect( ) describe("QuestionTool", () => { + it.effect("emits one item schema for the nonempty questions array", () => + Effect.gen(function* () { + captured = undefined + const registry = yield* Tool.Service + const definition = (yield* toolDefinitions(registry)).find((tool) => tool.name === QuestionTool.name) + + expect(definition?.inputSchema).toHaveProperty("properties.questions.type", "array") + expect(definition?.inputSchema).toHaveProperty("properties.questions.minItems", 1) + expect(definition?.inputSchema).toHaveProperty("properties.questions.items") + expect(definition?.inputSchema).not.toHaveProperty("properties.questions.prefixItems") + expect( + yield* executeTool(registry, { + sessionID, + ...toolIdentity, + call: { type: "tool-call", id: "call-question-empty", name: QuestionTool.name, input: { questions: [] } }, + }), + ).toMatchObject({ + status: "error", + error: { type: "tool.execution", message: expect.stringContaining("Invalid tool input") }, + }) + expect(capturedInput()).toBeUndefined() + }), + ) + it.effect("omits a catalog-denied question and enforces its leaf permission", () => Effect.gen(function* () { captured = undefined