/// import { computed, Default, generateObject, handler, ifElse, NAME, pattern, UI, type VNode, Writable, } from "commontools"; // ===== Types ===== type QuestionInput = { topic?: Default; context?: Default, Record>; }; type QuestionOutput = { [NAME]: string; [UI]: VNode; topic: string; question: string; options: string[]; answer: Writable; pending: boolean; }; // ===== Handler (module scope) ===== const onAnswer = handler< { detail: { answer: string } }, { answer: Writable } >(({ detail }, { answer }) => { answer.set(detail.answer); }); // ===== Pattern ===== /** * Generates a clarifying question to ask the user based on the topic and context. * Designed as "suggestion fuel" - useful when the system needs more information * before proceeding, or to prompt the user to think about something. */ const Question = pattern( ({ topic, context }) => { const prompt = computed(() => { const t = topic || "the current situation"; return `Generate a single, thoughtful clarifying question about: ${t}. Include 2-4 multiple choice options if appropriate, or leave options empty for a free-text answer.`; }); const response = generateObject<{ question: string; options: string[]; }>({ system: "You generate thoughtful, specific questions that help clarify intent or gather useful information. Questions should be concise and actionable. Provide 2-4 multiple choice options when the answer space is bounded, or an empty options array for open-ended questions.", prompt, context, schema: { type: "object", properties: { question: { type: "string" }, options: { type: "array", items: { type: "string" }, }, }, required: ["question", "options"], }, model: "anthropic:claude-haiku-4-5", }); const answer = Writable.of(""); return { [NAME]: computed(() => (topic ? `Question: ${topic}` : "Question")), [UI]: ( {computed(() => topic || "Question")} {ifElse( response.pending,
Generating question...
, response.result?.question || "", )} options={computed( () => response.result?.options || [], )} onct-answer={onAnswer({ answer })} />, )}
), topic, question: computed(() => response.result?.question || ""), options: computed(() => response.result?.options || []), answer, pending: response.pending, }; }, ); export default Question;