feat: continue platform agent executions from recent runs
Some checks failed
StoryForge CI / Baseline checks (push) Has been cancelled
StoryForge CI / Backend tests (push) Has been cancelled
StoryForge CI / Web tests (push) Has been cancelled

This commit is contained in:
kris
2026-04-04 04:35:22 +08:00
parent a76bdb432f
commit 01ce085f6a
3 changed files with 84 additions and 24 deletions

View File

@@ -144,3 +144,10 @@
- `GET /v2/platform-agents` 能返回 `recent_execution`
- 最近执行会带上 run id、intent 和 `oneliner_profile_version_no`
- 前端工作台测试新增平台 Agent 最近执行渲染断言,锁住总览卡和详情弹层里的“最近执行”展示。
### 平台 Agent 最近执行继续处理
- 平台 Agent 总览卡和详情弹层里的“最近执行”现在都带上了直接动作,不再只是只读摘要。
- 新增“查看执行结果”,会直接打开对应主 Agent run 的结果卡。
- 新增“回到主 Agent 查看”,会切到对应 run 的上下文并打开主 Agent 悬浮窗口,方便顺着同一轮执行继续处理。
- 前端回归也补上了这两个动作入口和事件处理器,避免后续又退回成只能展示、不能继续操作。

View File

@@ -2268,31 +2268,59 @@ async function executeOneLinerAction(executorKey, options = {}) {
}
function openCurrentOneLinerRunResultAction(runId = "") {
const currentRun = safeArray(appState.onelinerRuns).find((item) => item.id === runId) || getCurrentOneLinerRun();
if (!currentRun?.id) {
rememberAction("还没有可查看的结果", "当前主 Agent 任务还没有返回可展示的执行结果。", "orange");
renderAll();
return;
}
if (!currentRun.result || !Object.keys(currentRun.result || {}).length) {
rememberAction("结果还在生成中", currentRun.status_summary || "当前主 Agent 任务还没有返回执行结果。", "orange", currentRun);
renderAll();
return;
}
appState.selectedOnelinerRunId = currentRun.id;
appState.onelinerRunFilter = currentRun.run_status === "done" ? "done" : appState.onelinerRunFilter;
openActionModal({
title: currentRun.title || currentRun.plan?.goal || "主 Agent 执行结果",
description: currentRun.result?.execution_summary || currentRun.status_summary || "这是当前主 Agent 任务的执行结果。",
hideSubmit: true,
fields: [
{
type: "html",
label: "执行结果",
html: `<div class="sheet-html">${renderOneLinerExecutionPayloadHtml(currentRun.result)}</div>`
openOneLinerRunContextAction(runId)
.then((currentRun) => {
if (!currentRun?.id) {
rememberAction("还没有可查看的结果", "当前主 Agent 任务还没有返回可展示的执行结果。", "orange");
renderAll();
return;
}
]
});
if (!currentRun.result || !Object.keys(currentRun.result || {}).length) {
rememberAction("结果还在生成中", currentRun.status_summary || "当前主 Agent 任务还没有返回执行结果。", "orange", currentRun);
renderAll();
return;
}
appState.selectedOnelinerRunId = currentRun.id;
appState.onelinerRunFilter = currentRun.run_status === "done" ? "done" : appState.onelinerRunFilter;
openActionModal({
title: currentRun.title || currentRun.plan?.goal || "主 Agent 执行结果",
description: currentRun.result?.execution_summary || currentRun.status_summary || "这是当前主 Agent 任务的执行结果。",
hideSubmit: true,
fields: [
{
type: "html",
label: "执行结果",
html: `<div class="sheet-html">${renderOneLinerExecutionPayloadHtml(currentRun.result)}</div>`
}
]
});
})
.catch(() => {
rememberAction("还没有可查看的结果", "当前主 Agent 任务还没有返回可展示的执行结果。", "orange");
renderAll();
});
}
async function openOneLinerRunContextAction(runId = "") {
const targetRunId = runId || appState.selectedOnelinerRunId || "";
if (!targetRunId) {
rememberAction("还没有可查看的运行", "当前还没有主 Agent 运行可继续查看。", "orange");
renderAll();
return null;
}
const currentProjectId = appState.selectedProjectId || getOneLinerProjectId();
if (!safeArray(appState.onelinerRuns).some((item) => item.id === targetRunId) && currentProjectId) {
await loadAgentControlSurfaces(currentProjectId);
}
appState.selectedOnelinerRunId = targetRunId;
const hydrated = await hydrateSelectedOneLinerRun();
const currentRun = hydrated || safeArray(appState.onelinerRuns).find((item) => item.id === targetRunId) || null;
if (currentRun?.run_status === "done") {
appState.onelinerRunFilter = "done";
}
openOneLinerPanel();
renderAll();
return currentRun;
}
function openConfirmOneLinerRunAction(runId = "") {
@@ -4432,6 +4460,10 @@ function renderPlatformAgentPanel() {
${item.recent_execution.oneliner_profile_version_no ? `<span class="tag">配置 v${escapeHtml(formatNumber(item.recent_execution.oneliner_profile_version_no))}</span>` : ""}
${item.recent_execution.source_screen ? `<span class="tag">${escapeHtml(screenLabel(item.recent_execution.source_screen) || item.recent_execution.source_screen)}</span>` : ""}
</div>
<div class="task-meta" style="margin-top:8px;">
<span class="tag clickable-tag" data-action="open-oneliner-run-result" data-run-id="${escapeHtml(item.recent_execution.run_id)}">查看执行结果</span>
<span class="tag clickable-tag" data-action="open-oneliner-run-context" data-run-id="${escapeHtml(item.recent_execution.run_id)}">回到主 Agent 查看</span>
</div>
</div>
` : ""}
<div class="task-meta" style="margin-top:10px;">
@@ -9364,6 +9396,10 @@ async function openPlatformAgentDetailAction(platform) {
${profile.recent_execution.oneliner_profile_version_no ? `<span class="tag">配置 v${escapeHtml(formatNumber(profile.recent_execution.oneliner_profile_version_no))}</span>` : ""}
${profile.recent_execution.source_screen ? `<span class="tag">${escapeHtml(screenLabel(profile.recent_execution.source_screen) || profile.recent_execution.source_screen)}</span>` : ""}
</div>
<div class="task-meta" style="margin-top:8px;">
<span class="tag clickable-tag" data-action="open-oneliner-run-result" data-run-id="${escapeHtml(profile.recent_execution.run_id)}">查看执行结果</span>
<span class="tag clickable-tag" data-action="open-oneliner-run-context" data-run-id="${escapeHtml(profile.recent_execution.run_id)}">回到主 Agent 查看</span>
</div>
</div>
` : ""}
<div class="two-col" style="margin-top:12px;">
@@ -11068,6 +11104,17 @@ document.addEventListener("click", async (event) => {
openCurrentOneLinerRunResultAction(action.dataset.runId || "");
return;
}
if (name === "open-oneliner-run-context") {
try {
setBusy(true, "正在切到主 Agent 运行上下文...");
await openOneLinerRunContextAction(action.dataset.runId || "");
} catch (error) {
presentActionFailure(error, "打开主 Agent 运行失败");
} finally {
setBusy(false, "");
}
return;
}
if (name === "confirm-oneliner-run") {
openConfirmOneLinerRunAction(action.dataset.runId || "");
return;

View File

@@ -274,12 +274,18 @@ test("governance and quota panels use real empty-state language instead of backe
test("platform agent surfaces recent execution feedback from main agent runs", () => {
const platformAgents = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
assert.match(platformAgents, /recent_execution/);
assert.match(platformAgents, /最近执行/);
assert.match(platformAgents, /配置 v/);
assert.match(platformAgents, /open-oneliner-run-result/);
assert.match(platformAgents, /open-oneliner-run-context/);
assert.match(detail, /最近执行/);
assert.match(detail, /recent_execution/);
assert.match(detail, /open-oneliner-run-result/);
assert.match(detail, /open-oneliner-run-context/);
assert.match(actions, /name === "open-oneliner-run-context"[\s\S]*openOneLinerRunContextAction/);
});
test("quota and review screens foreground live next-step guidance", () => {