From 2aaf5a3baa18bdf5caa1e533b690ed49b7825eef Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Fri, 10 Apr 2026 18:17:57 +0530 Subject: [PATCH] fix(qa-lab): address telegram qa review comments --- extensions/qa-lab/src/cli.runtime.test.ts | 14 +++++++++++++ extensions/qa-lab/src/cli.runtime.ts | 4 +++- extensions/qa-lab/src/cli.ts | 2 +- .../qa-lab/src/telegram-live.runtime.test.ts | 21 +++++++++++++++++++ .../qa-lab/src/telegram-live.runtime.ts | 9 +++++--- 5 files changed, 45 insertions(+), 5 deletions(-) diff --git a/extensions/qa-lab/src/cli.runtime.test.ts b/extensions/qa-lab/src/cli.runtime.test.ts index 3a2c4f8f042..a805bae61c2 100644 --- a/extensions/qa-lab/src/cli.runtime.test.ts +++ b/extensions/qa-lab/src/cli.runtime.test.ts @@ -185,6 +185,20 @@ describe("qa cli runtime", () => { }); }); + it("defaults telegram qa runs onto the live provider lane", async () => { + await runQaTelegramCommand({ + repoRoot: "/tmp/openclaw-repo", + scenarioIds: ["telegram-help-command"], + }); + + expect(runTelegramQaLive).toHaveBeenCalledWith( + expect.objectContaining({ + repoRoot: path.resolve("/tmp/openclaw-repo"), + providerMode: "live-frontier", + }), + ); + }); + it("normalizes legacy live-openai suite runs onto the frontier provider mode", async () => { await runQaSuiteCommand({ repoRoot: "/tmp/openclaw-repo", diff --git a/extensions/qa-lab/src/cli.runtime.ts b/extensions/qa-lab/src/cli.runtime.ts index 6a1921b24dc..8182b26f8a2 100644 --- a/extensions/qa-lab/src/cli.runtime.ts +++ b/extensions/qa-lab/src/cli.runtime.ts @@ -292,10 +292,12 @@ export async function runQaTelegramCommand(opts: { sutAccountId?: string; }) { const repoRoot = path.resolve(opts.repoRoot ?? process.cwd()); + const providerMode: QaProviderMode = + opts.providerMode === undefined ? "live-frontier" : normalizeQaProviderMode(opts.providerMode); const result = await runTelegramQaLive({ repoRoot, outputDir: opts.outputDir ? path.resolve(repoRoot, opts.outputDir) : undefined, - providerMode: opts.providerMode, + providerMode, primaryModel: opts.primaryModel, alternateModel: opts.alternateModel, fastMode: opts.fastMode, diff --git a/extensions/qa-lab/src/cli.ts b/extensions/qa-lab/src/cli.ts index b254e901646..93c74c7b70e 100644 --- a/extensions/qa-lab/src/cli.ts +++ b/extensions/qa-lab/src/cli.ts @@ -163,7 +163,7 @@ export function registerQaLabCli(program: Command) { .option( "--provider-mode ", "Provider mode: mock-openai or live-frontier (legacy live-openai still works)", - "mock-openai", + "live-frontier", ) .option("--model ", "Primary provider/model ref") .option("--alt-model ", "Alternate provider/model ref") diff --git a/extensions/qa-lab/src/telegram-live.runtime.test.ts b/extensions/qa-lab/src/telegram-live.runtime.test.ts index 539865b9632..0c7de85b725 100644 --- a/extensions/qa-lab/src/telegram-live.runtime.test.ts +++ b/extensions/qa-lab/src/telegram-live.runtime.test.ts @@ -151,4 +151,25 @@ describe("telegram live qa runtime", () => { "Confirm the SUT bot is present in the target private group and can receive /help@BotUsername commands there.", ); }); + + it("treats null canary context as a non-canary error", () => { + const error = new Error("boom"); + error.name = "TelegramQaCanaryError"; + Object.assign(error, { + phase: "sut_reply_timeout", + context: null, + }); + + const message = __testing.canaryFailureMessage({ + error, + groupId: "-100123", + driverBotId: 42, + driverUsername: "driver_bot", + sutBotId: 88, + sutUsername: "sut_bot", + }); + + expect(message).toContain("Phase: unknown"); + expect(message).toContain("boom"); + }); }); diff --git a/extensions/qa-lab/src/telegram-live.runtime.ts b/extensions/qa-lab/src/telegram-live.runtime.ts index 5b1b2fd07d9..4c3ce897e72 100644 --- a/extensions/qa-lab/src/telegram-live.runtime.ts +++ b/extensions/qa-lab/src/telegram-live.runtime.ts @@ -95,7 +95,8 @@ function isTelegramQaCanaryError(error: unknown): error is TelegramQaCanaryError (typeof error === "object" && error !== null && typeof (error as { phase?: unknown }).phase === "string" && - typeof (error as { context?: unknown }).context === "object") + typeof (error as { context?: unknown }).context === "object" && + (error as { context?: unknown }).context !== null) ); } @@ -306,8 +307,9 @@ async function getBotIdentity(token: string) { } async function flushTelegramUpdates(token: string) { + const startedAt = Date.now(); let offset = 0; - while (true) { + while (Date.now() - startedAt < 15_000) { const updates = await callTelegramApi(token, "getUpdates", { offset, timeout: 0, @@ -318,6 +320,7 @@ async function flushTelegramUpdates(token: string) { } offset = (updates.at(-1)?.update_id ?? offset) + 1; } + return offset; } async function sendGroupMessage(token: string, groupId: string, text: string) { @@ -580,7 +583,7 @@ export async function runTelegramQaLive(params: { await fs.mkdir(outputDir, { recursive: true }); const runtimeEnv = resolveTelegramQaRuntimeEnv(); - const providerMode = normalizeQaProviderMode(params.providerMode ?? "mock-openai"); + const providerMode = normalizeQaProviderMode(params.providerMode ?? "live-frontier"); const primaryModel = params.primaryModel?.trim() || defaultQaModelForMode(providerMode); const alternateModel = params.alternateModel?.trim() || defaultQaModelForMode(providerMode, true); const sutAccountId = params.sutAccountId?.trim() || "sut";