Files
pikasTech-unidesk/scripts/src/hwlab-node-web-observe-runner-actions-source.ts
T
2026-06-26 04:07:26 +08:00

74 lines
3.4 KiB
TypeScript

// SPEC: PJ2026-01040111 长程观测 draft-2026-06-20-p0-passive-web-probe-observer.
// Responsibility: Extra control actions injected into the pure-client web-probe observer runner.
export function nodeWebObserveRunnerCommandActionsSource(): string {
return String.raw`
async function cancelRunningTurn() {
const beforeUrl = currentPageUrl();
const editor = page.locator("#command-input").last();
if (await editor.isVisible().catch(() => false)) {
const tag = await editor.evaluate((element) => element.tagName.toLowerCase()).catch(() => "");
const editable = await editor.evaluate((element) => element.getAttribute("contenteditable") === "true").catch(() => false);
if (tag === "textarea" || tag === "input") await editor.fill("");
else if (editable) {
await editor.click();
await page.keyboard.press(process.platform === "darwin" ? "Meta+A" : "Control+A").catch(() => {});
await page.keyboard.press("Backspace").catch(() => {});
}
}
const cancelSelectors = [
'button:has-text("取消")',
'button:has-text("Cancel")',
'[data-testid*="cancel" i]',
'[aria-label*="cancel" i]',
'[aria-label*="取消"]'
].join(", ");
const primaryButton = page.locator('#command-submit, [data-testid="command-submit"], [data-testid="composer-submit"], [data-testid="send-command"]').last();
const explicitCancelButton = page.locator(cancelSelectors).last();
let button = null;
if (await primaryButton.isVisible().catch(() => false)) {
const primaryLooksCancelable = await primaryButton.evaluate((element) => {
const parts = [
element.textContent || "",
element.getAttribute("aria-label") || "",
element.getAttribute("title") || "",
element.getAttribute("data-testid") || "",
element.getAttribute("data-state") || "",
element.getAttribute("data-action") || "",
element.className || ""
];
return /cancel|取消|停止|stop|abort/i.test(parts.join(" "));
}).catch(() => false);
if (primaryLooksCancelable) button = primaryButton;
}
if (button === null && await explicitCancelButton.isVisible().catch(() => false)) button = explicitCancelButton;
if (button === null) {
return {
beforeUrl,
afterUrl: currentPageUrl(),
cancelSubmit: { status: null, statusText: null, skipped: true, reason: "cancel-button-not-visible", responseObserved: false },
pageId
};
}
await button.waitFor({ state: "visible", timeout: 15000 });
const cancelResponsePromise = page.waitForResponse((response) => {
const request = response.request();
if (request.method().toUpperCase() !== "POST") return false;
try {
const pathname = new URL(response.url()).pathname;
return pathname === "/v1/agent/chat/cancel" || /\/cancel$/u.test(pathname);
} catch {
return false;
}
}, { timeout: 10000 }).catch((error) => ({ waitError: errorSummary(error) }));
await button.click();
const cancelResponse = await cancelResponsePromise;
await page.waitForTimeout(500);
if (cancelResponse?.waitError) {
return { beforeUrl, afterUrl: currentPageUrl(), cancelSubmit: { status: null, statusText: null, waitError: cancelResponse.waitError, responseObserved: false }, pageId };
}
return { beforeUrl, afterUrl: currentPageUrl(), cancelSubmit: { status: cancelResponse.status(), statusText: cancelResponse.statusText(), urlPath: safeUrlPath(cancelResponse.url()), responseObserved: true }, pageId };
}
`;
}