fix(chat): tolerate 500 on empty inbox edges; fix(agent): clear LLM-unavailable msg
- chatApi.listThreads: catch on the edges query so a fresh empty inbox doesn't bubble a 500 to the UI. New users see 'No conversations yet' instead of the error banner. - agentTools.llmFallback: when the LLM gateway returns 503/500, show a clear 'plain-language replies temporarily unavailable' message naming the reason, listing the deterministic capabilities that still work. No more silent null returns.
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
// End-to-end Studio flow against LIVE.
|
||||
import { chromium } from "playwright";
|
||||
|
||||
const URL = "https://canvas.flow-master.ai/";
|
||||
const calls = [];
|
||||
const consoleErrs = [];
|
||||
|
||||
const b = await chromium.launch({ headless: true });
|
||||
const ctx = await b.newContext({ viewport: { width: 1440, height: 900 } });
|
||||
const p = await ctx.newPage();
|
||||
p.on("response", (r) => {
|
||||
const u = r.url();
|
||||
if (u.includes("/api/")) calls.push({ status: r.status(), method: r.request().method(), url: u.replace("https://canvas.flow-master.ai", "") });
|
||||
});
|
||||
p.on("console", (m) => { if (m.type() === "error") consoleErrs.push(m.text().slice(0, 200)); });
|
||||
await ctx.addInitScript(() => localStorage.setItem("fm.canvas.tour.seen", String(Date.now())));
|
||||
|
||||
const log = (s) => console.log(`[${(Date.now() - t0) / 1000}s] ${s}`);
|
||||
const t0 = Date.now();
|
||||
|
||||
log("login");
|
||||
await p.goto(URL, { waitUntil: "domcontentloaded" });
|
||||
await p.waitForTimeout(2500);
|
||||
await p.locator(".persona-chip").filter({ hasText: /Mariana/ }).click();
|
||||
await p.waitForSelector(".topbar", { timeout: 30000 });
|
||||
log("logged in, on " + (await p.evaluate(() => document.querySelector("[class*='shell-']")?.className)));
|
||||
|
||||
log("nav to studio");
|
||||
const studioTab = p.locator(".tab").filter({ hasText: /Studio/i }).first();
|
||||
await studioTab.click({ timeout: 10000 });
|
||||
await p.waitForTimeout(2500);
|
||||
log("studio scene: " + (await p.evaluate(() => document.querySelector(".scene")?.innerText?.slice(0, 150))));
|
||||
|
||||
log("fill intake");
|
||||
const desc = p.locator("textarea").first();
|
||||
await desc.fill("E2E test: when a store manager requests a laptop, run procurement approval.");
|
||||
await p.waitForTimeout(500);
|
||||
|
||||
log("click Start drafting");
|
||||
await p.locator("button.btn-primary").filter({ hasText: /draft/i }).first().click({ timeout: 8000 });
|
||||
await p.waitForTimeout(7000);
|
||||
|
||||
log("step now: " + (await p.evaluate(() => {
|
||||
const t = document.querySelector(".scene")?.innerText || "";
|
||||
return t.split("\n").slice(0, 3).join(" | ");
|
||||
})));
|
||||
|
||||
log("click Confirm structure");
|
||||
const confirmBtn = p.locator("button.btn-primary").filter({ hasText: /Confirm structure/i }).first();
|
||||
if (await confirmBtn.count()) {
|
||||
await confirmBtn.click({ timeout: 8000 });
|
||||
log("waiting for toast or step change…");
|
||||
await p.waitForTimeout(10000);
|
||||
const toasts = await p.locator(".toaster, .toast, .toast-msg").allTextContents();
|
||||
log("toasts: " + JSON.stringify(toasts.slice(-3)));
|
||||
const step = await p.evaluate(() => {
|
||||
const t = document.querySelector(".scene")?.innerText || "";
|
||||
return t.split("\n").slice(0, 3).join(" | ");
|
||||
});
|
||||
log("now: " + step);
|
||||
}
|
||||
|
||||
await p.screenshot({ path: "/tmp/canvas-evidence/studio-e2e.png" });
|
||||
|
||||
await b.close();
|
||||
console.log("\n=== Network ===");
|
||||
const byStatus = {};
|
||||
for (const c of calls) byStatus[c.status] = (byStatus[c.status] || 0) + 1;
|
||||
console.log("by status:", JSON.stringify(byStatus));
|
||||
const fails = calls.filter(c => c.status >= 400);
|
||||
console.log("\nFails:");
|
||||
for (const f of fails) console.log(` ${f.status} ${f.method} ${f.url.slice(0, 90)}`);
|
||||
const applyBatchCalls = calls.filter(c => c.url.includes("apply-batch"));
|
||||
console.log("\napply-batch calls:");
|
||||
for (const c of applyBatchCalls) console.log(` ${c.status} ${c.method} ${c.url}`);
|
||||
console.log("\nConsole errors:");
|
||||
for (const e of consoleErrs.slice(-10)) console.log(" " + e);
|
||||
Reference in New Issue
Block a user