From 3d48d5baa53ae81ebc6d0168488d9c0757925378 Mon Sep 17 00:00:00 2001 From: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> Date: Mon, 26 Oct 2026 01:28:24 +0800 Subject: [PATCH] test(workspace): model explicit empty steward discovery Signed-off-by: LoopX Agent <337587101+loopx-agent@users.noreply.github.com> --- .../conversation-startup.mjs | 13 +++++++++++++ examples/personal-workspace-browser/fixture.mjs | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/examples/personal-workspace-browser/conversation-startup.mjs b/examples/personal-workspace-browser/conversation-startup.mjs index dd6407f07e..c9a0a196ac 100644 --- a/examples/personal-workspace-browser/conversation-startup.mjs +++ b/examples/personal-workspace-browser/conversation-startup.mjs @@ -7,11 +7,17 @@ export const conversationStartupScenario = { async run({ browser, collectCoverage, url }) { const waiting = []; let fail = false; + let sourceAvailable = false; + let sessionCreates = 0; const context = await openWorkspacePage(browser, url, { collectCoverage, gotoWaitUntil: "domcontentloaded", beforeGoto: async (_api, page) => { + await page.route("**/api/chat/app-steward", route => sourceAvailable + ? route.fallback() + : route.fulfill({status: 503, json: {ok: false, error: "Source unavailable"}})); await page.route("**/api/chat/sessions", async route => { if (route.request().method() !== "POST") return route.fallback(); + sessionCreates += 1; if (!fail) await new Promise(resolve => waiting.push(resolve)); if (fail) return route.fulfill({ status: 503, json: { ok: false, error_code: "host_gate", error: "Executor connection timed out." } }); return route.fallback(); @@ -20,6 +26,13 @@ export const conversationStartupScenario = { }); const { page, api } = context; try { + await page.getByRole("alert").filter({hasText: "原管家会话暂不可用"}).waitFor(); + assert.equal(await page.getByLabel("向 LoopX 发送消息").isDisabled(), true); + assert.equal(await page.getByRole("button", {name: "发送", exact: true}).isDisabled(), true); + assert.equal(sessionCreates, 0, "failed source discovery cannot create an ordinary manager session"); + assert.equal(api.turnRequests.length, 0, "failed source discovery cannot dispatch work"); + sourceAvailable = true; + await page.getByRole("button", {name: "重试读取", exact: true}).click(); const send = async text => { await page.getByLabel("向 LoopX 发送消息").fill(text); await page.getByRole("button", { name: "发送", exact: true }).click(); diff --git a/examples/personal-workspace-browser/fixture.mjs b/examples/personal-workspace-browser/fixture.mjs index 7edd02b7c0..7a8993e5f8 100644 --- a/examples/personal-workspace-browser/fixture.mjs +++ b/examples/personal-workspace-browser/fixture.mjs @@ -988,6 +988,12 @@ export async function installApi(page, { fixturePort = port, goalSubagentConfigu await page.route("**/api/chat/**", async (route) => { const request = route.request(); const url = new URL(request.url()); + if (url.pathname === "/api/chat/app-steward" && request.method() === "GET") { + // An ordinary manager is available only after discovery explicitly finds + // no selected original conversation; a missing/failed read is not empty. + await route.fulfill({json: {ok: true, binding_id: null, session_id: null}}); + return; + } if (url.pathname === "/api/chat/sidebar-goal-order") { const body = request.method() === "POST" ? request.postDataJSON() : null; const source = body?.source ?? url.searchParams.get("source");