import { CardBlockSchema, SUGGESTION_TTL_MS } from "@rakazo/contracts"; import { describe, expect, it } from "vitest"; import { applyCardAct, cardHistoryText } from "./cards.js"; import { buildSuggestionCard, describeSuggestion, suggestionStatus, withSuggestionStatus, } from "./suggestions.js"; const walk = { id: "s1", effectId: "s1", tool: "schedule_create", args: { name: "Morning walk", prompt: "Take a walk.", cron: "0 8 * * *" }, why: "A nudge each morning makes it a habit.", }; describe("suggestions", () => { it("says what the stored call does, not what the model claims", () => { expect(describeSuggestion(walk.tool, walk.args)).toEqual({ title: "Set up a routine", details: ["Morning walk", "Take a walk.", "Every day at 8:00 AM"], }); expect(describeSuggestion("gmail_send_email", {}).title).toBe("Gmail send email"); }); it("shows a suggested look instead of describing it", () => { const card = buildSuggestionCard({ id: "s2", effectId: "s2", tool: "update_bot", args: { look: "oo1:c=f4a7b9;sp=cat" }, why: "Cosy for recipe nights.", }); expect(card.sections?.[0]).toEqual({ type: "header", title: "New look", subtitle: "Cosy for recipe nights.", avatar: "oo1:c=F4A7B9;sp=cat", }); expect(CardBlockSchema.safeParse(card).success).toBe(true); expect(describeSuggestion("update_bot", { look: "nope", name: "Mia" })).toEqual({ title: "Update profile", details: ["Mia"], }); }); it("takes one tap: accept runs it, then nothing else applies", () => { const card = buildSuggestionCard(walk); const accepted = applyCardAct(card, { type: "action", actionId: "accept" }); expect(accepted).toMatchObject({ ok: true, suggestion: "accept" }); if (!accepted.ok) throw new Error(accepted.error); expect(accepted.block.suggestion?.status).toBe("running"); expect(accepted.reply).toBeUndefined(); expect(applyCardAct(accepted.block, { type: "action", actionId: "dismiss" })).toMatchObject({ ok: false, }); expect(applyCardAct(card, { type: "action", actionId: "dismiss" })).toMatchObject({ ok: true, suggestion: "dismiss", block: { suggestion: { status: "dismissed" } }, }); }); it("reads an open suggestion past its time as expired", () => { const card = buildSuggestionCard(walk); const created = new Date("2026-10-01T08:00:00Z"); expect(suggestionStatus(card, created, created.getTime() + 1000)).toBe("proposed"); expect(suggestionStatus(card, created, created.getTime() + SUGGESTION_TTL_MS + 1)).toBe( "expired", ); const done = withSuggestionStatus(card, "done"); expect(suggestionStatus(done, created, created.getTime() + SUGGESTION_TTL_MS + 1)).toBe("done"); }); it("tells the model where the suggestion stands", () => { const failed = withSuggestionStatus(buildSuggestionCard(walk), "failed", "No such tool."); expect(cardHistoryText(failed)).toContain("schedule_create"); expect(cardHistoryText(failed)).toContain("No such tool."); }); });