/// import { computed, Default, generateObject, ifElse, NAME, pattern, UI, type VNode, } from "commontools"; // ===== Types ===== type BudgetInput = { topic?: Default; context?: Default, Record>; maxAmount?: Default; }; type BudgetItem = { name: string; amount: Default; }; type BudgetOutput = { [NAME]: string; [UI]: VNode; topic: string; items: BudgetItem[]; total: number; remaining: number; pending: boolean; }; // ===== Pattern ===== /** * Generates a budget breakdown with adjustable amounts for each category. * Designed as "suggestion fuel" - suggests spending categories that fit * within a given budget ceiling. */ const BudgetPlanner = pattern( ({ topic, context, maxAmount }) => { const prompt = computed(() => { const t = topic || "a general budget"; return `Create a budget breakdown for: ${t}. Suggest 4-8 spending categories with dollar amounts that sum to exactly $${maxAmount}.`; }); const response = generateObject<{ items: BudgetItem[] }>({ system: "You create practical budget breakdowns. Each item should have a descriptive name and a reasonable dollar amount. Keep categories specific and actionable. Amounts should be whole numbers.", prompt, context, schema: { type: "object", properties: { items: { type: "array", items: { type: "object", properties: { name: { type: "string" }, amount: { type: "number" }, }, required: ["name", "amount"], }, }, }, required: ["items"], }, model: "anthropic:claude-haiku-4-5", }); const items = computed(() => response.result?.items || []); const total = computed(() => { let sum = 0; for (const item of items) { sum += item.amount || 0; } return sum; }); const remaining = computed(() => (maxAmount || 0) - total); return { [NAME]: computed(() => (topic ? `Budget: ${topic}` : "Budget Planner")), [UI]: ( {computed(() => topic || "Budget Planner")} Budget: ${maxAmount} {ifElse( response.pending, Generating budget... , {items.map((item) => ( {item.name} $ ))} Total ${total} Remaining remaining < 0 ? "var(--ct-color-danger, #ef4444)" : "var(--ct-color-text-secondary)" ), }} > ${remaining} , )} ), topic, items, total, remaining, pending: response.pending, }; }, ); export default BudgetPlanner;