diff --git a/CHANGELOG.md b/CHANGELOG.md
index 86657a0..573c76a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -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 悬浮窗口,方便顺着同一轮执行继续处理。
+- 前端回归也补上了这两个动作入口和事件处理器,避免后续又退回成只能展示、不能继续操作。
diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js
index 55e3ef8..228c7cf 100644
--- a/web/storyforge-web-v4/assets/app.js
+++ b/web/storyforge-web-v4/assets/app.js
@@ -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: `
${renderOneLinerExecutionPayloadHtml(currentRun.result)}
`
+ 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: `${renderOneLinerExecutionPayloadHtml(currentRun.result)}
`
+ }
+ ]
+ });
+ })
+ .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 ? `配置 v${escapeHtml(formatNumber(item.recent_execution.oneliner_profile_version_no))}` : ""}
${item.recent_execution.source_screen ? `${escapeHtml(screenLabel(item.recent_execution.source_screen) || item.recent_execution.source_screen)}` : ""}
+
+ 查看执行结果
+ 回到主 Agent 查看
+
` : ""}
@@ -9364,6 +9396,10 @@ async function openPlatformAgentDetailAction(platform) {
${profile.recent_execution.oneliner_profile_version_no ? `配置 v${escapeHtml(formatNumber(profile.recent_execution.oneliner_profile_version_no))}` : ""}
${profile.recent_execution.source_screen ? `${escapeHtml(screenLabel(profile.recent_execution.source_screen) || profile.recent_execution.source_screen)}` : ""}
+
+ 查看执行结果
+ 回到主 Agent 查看
+
` : ""}
@@ -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;
diff --git a/web/storyforge-web-v4/tests/workbench-pages.test.mjs b/web/storyforge-web-v4/tests/workbench-pages.test.mjs
index f446d51..34c46e1 100644
--- a/web/storyforge-web-v4/tests/workbench-pages.test.mjs
+++ b/web/storyforge-web-v4/tests/workbench-pages.test.mjs
@@ -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", () => {