From de36ce7fe9b97a3398dcefd3aad06d7415d9db03 Mon Sep 17 00:00:00 2001 From: kris Date: Sun, 5 Apr 2026 07:15:28 +0800 Subject: [PATCH] feat: direct-execute main agent landing quick actions --- CHANGELOG.md | 5 ++ web/storyforge-web-v4/assets/app.js | 70 ++++++++++++++++--- .../tests/workbench-pages.test.mjs | 15 ++++ 3 files changed, 82 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ec7097c..054e1a7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -452,3 +452,8 @@ - `导入当前对标 / 加入跟踪 / 账号分析 / 高分分析 / 查相似 / 存对标` 这批高频动作现在默认直接执行,不再先开表单。 - 执行后会按真实 `recommended_action` 继续落到任务详情、当前对象或关系区;只有当前没有可直接执行的候选时,才回退到原来的高级表单。 - `接入当前项目` 卡片里的 `导入当前对标 / 加入跟踪` 也已统一切到 direct-execute,避免同一页面里出现新旧两套动作体验。 + +### 主 Agent 落点快捷动作继续下沉 + +- 主 Agent 落到 `找对标 / Agent / 生产中心 / 发布与复盘` 后,快捷动作里原先的 `高分分析 / 新建 Agent / 写复盘 / 做 AI 视频 / 做实拍剪辑` 已优先改成 direct-execute。 +- 这些动作现在直接调用 `OneLiner` 执行器并按真实结果继续落到对象详情、Agent 编辑页、复盘页或任务详情,而不是先打开旧表单。 diff --git a/web/storyforge-web-v4/assets/app.js b/web/storyforge-web-v4/assets/app.js index 2161867..18e3b80 100644 --- a/web/storyforge-web-v4/assets/app.js +++ b/web/storyforge-web-v4/assets/app.js @@ -2463,6 +2463,29 @@ async function runDirectDiscoveryAction(executorKey, payload, options = {}) { } } +async function runDirectWorkbenchAction(executorKey, options = {}) { + const platform = normalizePlatformValue(options.platform || getPreferredPlatform(), getPreferredPlatform()); + setBusy(true, options.busyLabel || "正在执行当前动作..."); + try { + const result = await executeOneLinerAction(executorKey, { + platform, + payload: options.payload || {}, + showResultModal: false + }); + await followRecommendedActionResult(result, { + platform, + refreshWorkbench: options.refreshWorkbench !== false, + discoveryFocus: options.discoveryFocus || "" + }); + return result; + } catch (error) { + presentActionFailure(error, options.errorTitle || "执行失败"); + throw error; + } finally { + setBusy(false, ""); + } +} + function openCurrentOneLinerRunResultAction(runId = "") { openOneLinerRunContextAction(runId) .then((currentRun) => { @@ -5152,6 +5175,9 @@ function captureMainAgentLandingContext(action, targetScreen) { } function renderMainAgentLandingQuickActions(screenKey) { + const selectedAccount = getSelectedAccountRow(); + const discoveryImportAction = selectedAccount ? "direct-import-selected-account" : "open-import-homepage"; + const discoveryImportLabel = selectedAccount ? "导入当前对标" : "导入主页"; const actionMap = { intake: [ { action: "create-project", label: "新建项目" }, @@ -5159,9 +5185,9 @@ function renderMainAgentLandingQuickActions(screenKey) { { action: "open-upload-video", label: "上传视频" } ], discovery: [ - { action: "open-import-homepage", label: "导入主页" }, - { action: "analyze-top-videos", label: "高分分析" }, - { action: "goto-tracking", label: "去跟踪账号" } + { action: discoveryImportAction, label: discoveryImportLabel }, + { action: "direct-analyze-top-videos", label: "高分分析" }, + { action: "direct-search-similar", label: "查相似" } ], tracking: [ { action: "refresh-tracking", label: "同步全部" }, @@ -5174,16 +5200,16 @@ function renderMainAgentLandingQuickActions(screenKey) { ], playbook: [ { action: "open-oneliner-profile", label: "配置 OneLiner" }, - { action: "open-create-assistant", label: "新建 Agent" }, + { action: "direct-create-assistant", label: "新建 Agent" }, { action: "goto-production", label: "去生产中心" } ], production: [ - { action: "goto-review", label: "去复盘" }, - { action: "batch-recover-jobs", label: "批量恢复" }, - { action: "refresh-data", label: "刷新队列" } + { action: "direct-review-draft", label: "生成复盘" }, + { action: "direct-create-ai-video", label: "做 AI 视频" }, + { action: "direct-create-real-cut", label: "做实拍剪辑" } ], review: [ - { action: "open-create-review", label: "写复盘" }, + { action: "direct-review-draft", label: "生成复盘" }, { action: "goto-production", label: "去生产中心" }, { action: "refresh-data", label: "刷新结果" } ], @@ -12067,6 +12093,13 @@ document.addEventListener("click", async (event) => { openCreateAssistantAction(); return; } + if (name === "direct-create-assistant") { + await runDirectWorkbenchAction("create-assistant", { + busyLabel: "正在创建 Agent...", + errorTitle: "创建 Agent 失败" + }); + return; + } if (name === "open-dashboard-project-switcher") { openDashboardProjectSwitcher(); return; @@ -12325,14 +12358,35 @@ document.addEventListener("click", async (event) => { openCreateAiVideoAction(); return; } + if (name === "direct-create-ai-video") { + await runDirectWorkbenchAction("create-ai-video", { + busyLabel: "正在创建 AI 视频任务...", + errorTitle: "创建 AI 视频任务失败" + }); + return; + } if (name === "open-real-cut") { openCreateRealCutAction(); return; } + if (name === "direct-create-real-cut") { + await runDirectWorkbenchAction("create-real-cut", { + busyLabel: "正在创建实拍剪辑任务...", + errorTitle: "创建实拍剪辑任务失败" + }); + return; + } if (name === "open-create-review") { openReviewAction(); return; } + if (name === "direct-review-draft") { + await runDirectWorkbenchAction("review-draft", { + busyLabel: "正在生成复盘草稿...", + errorTitle: "生成复盘草稿失败" + }); + return; + } if (name === "open-preferred-model") { openPreferredModelAction(); return; diff --git a/web/storyforge-web-v4/tests/workbench-pages.test.mjs b/web/storyforge-web-v4/tests/workbench-pages.test.mjs index 3cb7770..5e1234a 100644 --- a/web/storyforge-web-v4/tests/workbench-pages.test.mjs +++ b/web/storyforge-web-v4/tests/workbench-pages.test.mjs @@ -983,6 +983,21 @@ test("main agent route actions keep landing context and destination screens rend assert.match(production, /renderMainAgentLandingNotice\("production"\)/); }); +test("main agent landing quick actions prefer direct execute flows where executors already exist", () => { + const landingActions = extractBetween(APP, "function renderMainAgentLandingQuickActions(screenKey)", "function renderMainAgentLandingNotice(screenKey)"); + assert.match(landingActions, /direct-analyze-top-videos/); + assert.match(landingActions, /direct-search-similar/); + assert.match(landingActions, /direct-create-assistant/); + assert.match(landingActions, /direct-review-draft/); + assert.match(landingActions, /direct-create-ai-video/); + assert.match(landingActions, /direct-create-real-cut/); + assert.match(APP, /if \(name === "direct-create-assistant"\)/); + assert.match(APP, /if \(name === "direct-review-draft"\)/); + assert.match(APP, /if \(name === "direct-create-ai-video"\)/); + assert.match(APP, /if \(name === "direct-create-real-cut"\)/); + assert.match(APP, /async function runDirectWorkbenchAction\(executorKey, options = \{\}\)/); +}); + test("main agent landing notices expose a compact mobile follow-up strip", () => { const landing = extractBetween(APP, "function renderMainAgentLandingNotice(screenKey)", "function renderEmptyState(title, description)"); assert.match(landing, /mobile-only compact-summary-row/);