test(skills): harden local agent QA automation

This commit is contained in:
huanghuoguoguo
2026-07-26 21:29:30 +08:00
parent e32210301a
commit 4bae8728a6
7 changed files with 176 additions and 17 deletions
+61
View File
@@ -56,6 +56,7 @@ import {
findNewFailureSignal,
hasDebugChatOutcome,
minExpectedOccurrences,
waitForDebugChatReady,
} from "../scripts/e2e/lib/debug-chat.mjs";
import {
beginBackendLogCapture,
@@ -1897,6 +1898,26 @@ test("debug chat classifier prefers latest response leaf over body counts", () =
assert.match(result.reason, /latest visible response leaf/);
});
test("debug chat readiness waits for the websocket to enable the input", async () => {
let enabledChecks = 0;
const input = {
isVisible: async () => true,
isEnabled: async () => {
enabledChecks += 1;
return enabledChecks >= 3;
},
};
const page = {
locator: () => ({ last: () => input }),
waitForTimeout: async () => {},
};
const result = await waitForDebugChatReady(page, 1_000);
assert.deepEqual(result, { ready: true, reason: "" });
assert.equal(enabledChecks, 3);
});
test("debug chat classifier distinguishes new failure signals from old history", () => {
assert.equal(
findNewFailureSignal(
@@ -2043,6 +2064,46 @@ test("debug chat classifier passes when expected text appears in a new assistant
assert.equal(result.new_assistant_message_count, 1);
});
test("debug chat classifier accepts formatted responses containing every required fragment", () => {
const expectedTexts = ["MULTITOOL_COMBO_FINAL", "passcode-6718", "rag-7421", "tool-a", "tool-b"];
const result = classifyDebugChatResult({
beforeText: "",
afterText: "Bot response with formatted details",
expectedText: expectedTexts[0],
expectedTexts,
prompt: "Run the combined task",
latestExpectedLeaf: "MULTITOOL_COMBO_FINAL",
latestFailureLeaf: "",
beforeMessages: [],
afterMessages: [{
role: "assistant",
text: "MULTITOOL_COMBO_FINAL\n- passcode-6718\n- rag-7421\n- tool-a\n- tool-b",
}],
latestAssistantText: "MULTITOOL_COMBO_FINAL\n- passcode-6718\n- rag-7421\n- tool-a\n- tool-b",
});
assert.equal(result.status, "pass");
assert.deepEqual(result.missing_expected_texts, []);
});
test("debug chat classifier rejects formatted responses missing a required fragment", () => {
const result = classifyDebugChatResult({
beforeText: "",
afterText: "Bot response with incomplete details",
expectedText: "MULTITOOL_COMBO_FINAL",
expectedTexts: ["MULTITOOL_COMBO_FINAL", "tool-a", "tool-b"],
prompt: "Run the combined task",
latestExpectedLeaf: "MULTITOOL_COMBO_FINAL",
latestFailureLeaf: "",
beforeMessages: [],
afterMessages: [{ role: "assistant", text: "MULTITOOL_COMBO_FINAL\n- tool-a" }],
latestAssistantText: "MULTITOOL_COMBO_FINAL\n- tool-a",
});
assert.equal(result.status, "fail");
assert.deepEqual(result.missing_expected_texts, ["tool-b"]);
});
test("debug chat classifier rejects split non-streaming assistant messages", () => {
const expectedText = "E2E_OK:skill";
const result = classifyDebugChatResult({
@@ -0,0 +1,34 @@
from __future__ import annotations
import importlib.util
import unittest
from pathlib import Path
VERIFY_PATH = (
Path(__file__).resolve().parents[1]
/ "skills"
/ "langbot-testing"
/ "fixtures"
/ "complex-agent-task"
/ "verify.py"
)
SPEC = importlib.util.spec_from_file_location("complex_agent_task_verify", VERIFY_PATH)
assert SPEC and SPEC.loader
MODULE = importlib.util.module_from_spec(SPEC)
SPEC.loader.exec_module(MODULE)
class ComplexAgentTaskVerifyTests(unittest.TestCase):
def test_accepts_initial_failure_heading(self) -> None:
self.assertTrue(MODULE.has_initial_failure_section("## Initial failing tests\n- test_price"))
def test_accepts_baseline_failure_heading(self) -> None:
self.assertTrue(MODULE.has_initial_failure_section("## Baseline failing tests\n- test_price"))
def test_rejects_report_without_failure_section(self) -> None:
self.assertFalse(MODULE.has_initial_failure_section("## Verification\nAll tests pass."))
if __name__ == "__main__":
unittest.main()