// Targeted LLM path verification — ask a question that no deterministic tool matches. import { chromium } from "playwright"; const b = await chromium.launch({ headless: true }); const ctx = await b.newContext({ viewport: { width: 1440, height: 900 } }); const p = await ctx.newPage(); await ctx.addInitScript(() => localStorage.setItem("fm.canvas.tour.seen", String(Date.now()))); const calls = []; p.on("response", (r) => { const u = r.url(); if (u.includes("/api/v1/llm/")) calls.push({ status: r.status(), url: u.replace("https://canvas.flow-master.ai", "") }); }); await p.goto("https://canvas.flow-master.ai/", { waitUntil: "domcontentloaded" }); await p.waitForTimeout(2500); await p.locator(".persona-chip").filter({ hasText: /Mariana/ }).click(); await p.waitForSelector(".topbar", { timeout: 30000 }); await p.waitForTimeout(2000); await p.locator(".tab").filter({ hasText: /Assistant/i }).first().click(); await p.waitForTimeout(3000); // A question no tool matches const input = p.locator(".agent-composer textarea").first(); const queries = [ "Explain what EA2 means in two sentences.", "What is the difference between a flow and a view?", "Tell me a joke about procurement.", ]; for (const q of queries) { console.log(`\n→ "${q}"`); await input.fill(q); await input.press("Enter"); await p.waitForTimeout(8000); const replies = await p.locator(".agent-turn-body").allTextContents(); console.log(" last reply:", replies.slice(-1)[0]?.slice(0, 280)); } console.log("\n=== /api/v1/llm/* calls ==="); for (const c of calls) console.log(` ${c.status} ${c.url}`); await p.screenshot({ path: "/tmp/canvas-evidence/llm-path.png" }); await b.close();