fix question option schema (#846)

This commit is contained in:
Ted 2026-01-19 14:57:23 +01:00 committed by GitHub
parent 4cc1c96495
commit f711340136
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -22,28 +22,17 @@ interface QuestionDetails {
wasCustom?: boolean;
}
// Support both simple strings and objects with descriptions
const OptionSchema = Type.Union([
Type.String(),
Type.Object({
label: Type.String({ description: "Display label for the option" }),
description: Type.Optional(Type.String({ description: "Optional description shown below label" })),
}),
]);
// Options with labels and optional descriptions
const OptionSchema = Type.Object({
label: Type.String({ description: "Display label for the option" }),
description: Type.Optional(Type.String({ description: "Optional description shown below label" })),
});
const QuestionParams = Type.Object({
question: Type.String({ description: "The question to ask the user" }),
options: Type.Array(OptionSchema, { description: "Options for the user to choose from" }),
});
// Normalize option to { label, description? }
function normalizeOption(opt: string | { label: string; description?: string }): OptionWithDesc {
if (typeof opt === "string") {
return { label: opt };
}
return opt;
}
export default function question(pi: ExtensionAPI) {
pi.registerTool({
name: "question",
@ -57,7 +46,7 @@ export default function question(pi: ExtensionAPI) {
content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }],
details: {
question: params.question,
options: params.options.map((o) => (typeof o === "string" ? o : o.label)),
options: params.options.map((o) => o.label),
answer: null,
} as QuestionDetails,
};
@ -70,9 +59,7 @@ export default function question(pi: ExtensionAPI) {
};
}
// Normalize options
const normalizedOptions = params.options.map(normalizeOption);
const allOptions: DisplayOption[] = [...normalizedOptions, { label: "Type something.", isOther: true }];
const allOptions: DisplayOption[] = [...params.options, { label: "Type something.", isOther: true }];
const result = await ctx.ui.custom<{ answer: string; wasCustom: boolean; index?: number } | null>(
(tui, theme, _kb, done) => {
@ -209,7 +196,7 @@ export default function question(pi: ExtensionAPI) {
);
// Build simple options list for details
const simpleOptions = normalizedOptions.map((o) => o.label);
const simpleOptions = params.options.map((o) => o.label);
if (!result) {
return {
@ -244,7 +231,7 @@ export default function question(pi: ExtensionAPI) {
let text = theme.fg("toolTitle", theme.bold("question ")) + theme.fg("muted", args.question);
const opts = Array.isArray(args.options) ? args.options : [];
if (opts.length) {
const labels = opts.map((o: string | { label: string }) => (typeof o === "string" ? o : o.label));
const labels = opts.map((o: OptionWithDesc) => o.label);
const numbered = [...labels, "Type something."].map((o, i) => `${i + 1}. ${o}`);
text += `\n${theme.fg("dim", ` Options: ${numbered.join(", ")}`)}`;
}