feat: auto-poll active main agent runs

This commit is contained in:
kris
2026-03-29 19:35:58 +08:00
parent 6c0f40c908
commit f14e773aa3
2 changed files with 49 additions and 0 deletions

View File

@@ -87,6 +87,7 @@ const appState = {
};
let PLATFORM_RUNTIME = null;
let onelinerRunPollTimer = null;
const API_CLIENT = StoryForgeApiClient.create({
getSession: () => appState.session,
@@ -1281,15 +1282,48 @@ function renderOneLinerUi() {
if (input && !input.value && !safeArray(appState.onelinerMessages).length) {
input.value = "";
}
syncOneLinerRunPolling();
}
function clearOneLinerRunPollTimer() {
if (onelinerRunPollTimer) {
clearTimeout(onelinerRunPollTimer);
onelinerRunPollTimer = null;
}
}
function syncOneLinerRunPolling() {
clearOneLinerRunPollTimer();
const panel = document.querySelector(".oneliner-backdrop");
const isPanelVisible = Boolean(panel && !panel.classList.contains("hidden"));
const currentRun = getCurrentOneLinerRun();
const shouldPoll = Boolean(
isPanelVisible
&& currentRun?.id
&& ["queued", "running", "blocked"].includes(currentRun.run_status)
);
if (!shouldPoll) {
return;
}
onelinerRunPollTimer = setTimeout(async () => {
try {
await hydrateSelectedOneLinerRun();
renderAll();
} catch {
clearOneLinerRunPollTimer();
}
}, 1500);
}
function openOneLinerPanel() {
ensureOneLinerUi();
document.querySelector(".oneliner-backdrop")?.classList.remove("hidden");
syncOneLinerRunPolling();
}
function closeOneLinerPanel() {
document.querySelector(".oneliner-backdrop")?.classList.add("hidden");
clearOneLinerRunPollTimer();
}
function readActionForm() {

View File

@@ -290,3 +290,18 @@ test("oneliner runtime shows grouped run health summary above the current run ca
assert.match(runtime, /已完成/);
assert.match(runtime, /safeArray\(runs\)\.filter\(\(item\) => item\.run_status === "needs_confirmation"\)\.length/);
});
test("oneliner panel auto-polls active runs while the floating panel stays open", () => {
const render = extractBetween(APP, "function renderOneLinerUi()", "function openOneLinerPanel()");
const open = extractBetween(APP, "function openOneLinerPanel()", "function closeOneLinerPanel()");
const close = extractBetween(APP, "function closeOneLinerPanel()", "function readActionForm()");
assert.match(APP, /let onelinerRunPollTimer = null;/);
assert.match(APP, /function clearOneLinerRunPollTimer\(\)/);
assert.match(APP, /function syncOneLinerRunPolling\(\)/);
assert.match(render, /syncOneLinerRunPolling\(\);/);
assert.match(open, /syncOneLinerRunPolling\(\);/);
assert.match(close, /clearOneLinerRunPollTimer\(\);/);
assert.match(APP, /setTimeout\(async \(\) => \{/);
assert.match(APP, /await hydrateSelectedOneLinerRun\(\);/);
});