chore: format chat run error changes

This commit is contained in:
Shakker
2026-07-19 18:07:12 +01:00
committed by Shakker
parent 9dd021a5cc
commit 1e80a0ee88
2 changed files with 81 additions and 75 deletions
+80 -73
View File
@@ -2144,83 +2144,90 @@ describeControlUiE2e("Control UI mocked Gateway E2E", () => {
it.each([
{ label: "desktop", viewport: { height: 900, width: 1280 } },
{ label: "mobile", viewport: { height: 844, width: 390 } },
])("keeps streamed text visible when a chat error terminates the turn on $label", async ({
viewport,
}) => {
const context = await newBrowserContext({
locale: "en-US",
serviceWorkers: "block",
viewport,
});
const page = await context.newPage();
const gateway = await installMockGateway(page);
try {
await page.goto(`${server.baseUrl}chat`);
const prompt = "stream before terminal error";
await page.locator(".agent-chat__composer-combobox textarea").fill(prompt);
await page.getByRole("button", { name: "Send message" }).click();
const sendRequest = await gateway.waitForRequest("chat.send");
const params = requireRecord(sendRequest.params);
const runId = requireString(params.idempotencyKey, "chat send idempotency key");
const partialText = "Partial answer before gateway error.";
await gateway.emitGatewayEvent("chat", {
deltaText: partialText,
message: {
content: [{ text: partialText, type: "text" }],
role: "assistant",
timestamp: Date.now(),
},
runId,
sessionKey: "main",
state: "delta",
])(
"keeps streamed text visible when a chat error terminates the turn on $label",
async ({ viewport }) => {
const context = await newBrowserContext({
locale: "en-US",
serviceWorkers: "block",
viewport,
});
await page.locator(".chat-thread-inner").getByText(partialText).waitFor({ timeout: 10_000 });
const page = await context.newPage();
const gateway = await installMockGateway(page);
const gatewayErrorText =
"⚠️ Model login expired on the gateway for openai. Send `/login codex` from a private chat or Web UI session to pair a new Codex login, or re-auth with `openclaw models auth login --provider openai` in a terminal, then try again.";
const errorText = gatewayErrorText.replace(/^\s*/u, "");
await gateway.emitGatewayEvent("chat", {
errorMessage: gatewayErrorText,
message: {
content: [{ text: gatewayErrorText, type: "text" }],
role: "assistant",
timestamp: Date.now(),
},
runId,
sessionKey: "main",
state: "error",
});
try {
await page.goto(`${server.baseUrl}chat`);
await page.locator(".chat-thread-inner").getByText(partialText).waitFor({ timeout: 10_000 });
const alert = page.locator(".chat-run-error");
await alert.getByText(errorText).waitFor({ timeout: 10_000 });
expect(await alert.locator("button").count()).toBe(0);
expect(await page.locator(".chat-thread-inner").getByText(errorText).count()).toBe(0);
expect(
await alert.evaluate((element) =>
element.nextElementSibling?.classList.contains("agent-chat__composer-shell"),
),
).toBe(true);
const [alertBox, composerBox] = await Promise.all([
alert.boundingBox(),
page.locator(".agent-chat__composer-shell").boundingBox(),
]);
expect(alertBox).not.toBeNull();
expect(composerBox).not.toBeNull();
expect(Math.abs((alertBox?.x ?? 0) - (composerBox?.x ?? 0))).toBeLessThan(1);
expect(Math.abs((alertBox?.width ?? 0) - (composerBox?.width ?? 0))).toBeLessThan(1);
const prompt = "stream before terminal error";
await page.locator(".agent-chat__composer-combobox textarea").fill(prompt);
await page.getByRole("button", { name: "Send message" }).click();
await page.locator(".agent-chat__composer-combobox textarea").fill("retry after error");
await page.getByRole("button", { name: "Send message" }).click();
await waitForRequests(gateway, "chat.send", 2);
await alert.waitFor({ state: "detached", timeout: 10_000 });
} finally {
await closeBrowserContext(context);
}
});
const sendRequest = await gateway.waitForRequest("chat.send");
const params = requireRecord(sendRequest.params);
const runId = requireString(params.idempotencyKey, "chat send idempotency key");
const partialText = "Partial answer before gateway error.";
await gateway.emitGatewayEvent("chat", {
deltaText: partialText,
message: {
content: [{ text: partialText, type: "text" }],
role: "assistant",
timestamp: Date.now(),
},
runId,
sessionKey: "main",
state: "delta",
});
await page
.locator(".chat-thread-inner")
.getByText(partialText)
.waitFor({ timeout: 10_000 });
const gatewayErrorText =
"⚠️ Model login expired on the gateway for openai. Send `/login codex` from a private chat or Web UI session to pair a new Codex login, or re-auth with `openclaw models auth login --provider openai` in a terminal, then try again.";
const errorText = gatewayErrorText.replace(/^\s*/u, "");
await gateway.emitGatewayEvent("chat", {
errorMessage: gatewayErrorText,
message: {
content: [{ text: gatewayErrorText, type: "text" }],
role: "assistant",
timestamp: Date.now(),
},
runId,
sessionKey: "main",
state: "error",
});
await page
.locator(".chat-thread-inner")
.getByText(partialText)
.waitFor({ timeout: 10_000 });
const alert = page.locator(".chat-run-error");
await alert.getByText(errorText).waitFor({ timeout: 10_000 });
expect(await alert.locator("button").count()).toBe(0);
expect(await page.locator(".chat-thread-inner").getByText(errorText).count()).toBe(0);
expect(
await alert.evaluate((element) =>
element.nextElementSibling?.classList.contains("agent-chat__composer-shell"),
),
).toBe(true);
const [alertBox, composerBox] = await Promise.all([
alert.boundingBox(),
page.locator(".agent-chat__composer-shell").boundingBox(),
]);
expect(alertBox).not.toBeNull();
expect(composerBox).not.toBeNull();
expect(Math.abs((alertBox?.x ?? 0) - (composerBox?.x ?? 0))).toBeLessThan(1);
expect(Math.abs((alertBox?.width ?? 0) - (composerBox?.width ?? 0))).toBeLessThan(1);
await page.locator(".agent-chat__composer-combobox textarea").fill("retry after error");
await page.getByRole("button", { name: "Send message" }).click();
await waitForRequests(gateway, "chat.send", 2);
await alert.waitFor({ state: "detached", timeout: 10_000 });
} finally {
await closeBrowserContext(context);
}
},
);
it("replaces the pending reading indicator with the streamed response", async () => {
const context = await newBrowserContext({
+1 -2
View File
@@ -160,8 +160,7 @@ function payloadMessageIsErrorProjection(
return messageText.startsWith("⚠️") || /^Error:\s*/iu.test(messageText);
}
return (
normalizeChatErrorComparisonText(messageText) ===
normalizeChatErrorComparisonText(errorText)
normalizeChatErrorComparisonText(messageText) === normalizeChatErrorComparisonText(errorText)
);
}