feat: continue platform agent executions from recent runs
This commit is contained in:
@@ -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 悬浮窗口,方便顺着同一轮执行继续处理。
|
||||
- 前端回归也补上了这两个动作入口和事件处理器,避免后续又退回成只能展示、不能继续操作。
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
Reference in New Issue
Block a user