feat: add direct oneliner follow-up actions
This commit is contained in:
@@ -1996,6 +1996,9 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
if (!payload || typeof payload !== "object") {
|
||||
return `<div class="task-item compact"><h4>没有返回执行结果</h4><p>当前执行器没有附带额外数据。</p></div>`;
|
||||
}
|
||||
const recommendedAction = payload.recommended_action && typeof payload.recommended_action === "object"
|
||||
? payload.recommended_action
|
||||
: null;
|
||||
if (payload.result_kind === "main_agent_plan") {
|
||||
const landingRunId = String(payload.run_id || "").trim();
|
||||
const landingScreen = String(payload.recommended_action?.screen || "").trim();
|
||||
@@ -2106,6 +2109,11 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
if (payload.job) {
|
||||
const job = payload.job || {};
|
||||
const sourceJob = payload.source_job || {};
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "production",
|
||||
title: job.title || "任务已创建",
|
||||
summary: recommendedAction?.summary || payload.brief || sourceJob.title || ""
|
||||
});
|
||||
return `
|
||||
<div class="task-item compact">
|
||||
<h4>${escapeHtml(job.title || "任务已创建")}</h4>
|
||||
@@ -2113,7 +2121,7 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
<div class="task-meta">
|
||||
<span class="tag blue">${escapeHtml(job.line_type || job.source_type || "analysis")}</span>
|
||||
<span class="tag ${job.status === "completed" ? "green" : "orange"}">${escapeHtml(job.status || "queued")}</span>
|
||||
${job.id ? `<span class="tag clickable-tag" data-action="open-job-detail" data-job-id="${escapeHtml(job.id)}">看任务详情</span>` : ""}
|
||||
${recommendedAction?.action ? actionTag(recommendedAction.label || "看任务详情", recommendedAction.action, recommendedAttrs) : job.id ? `<span class="tag clickable-tag" data-action="open-job-detail" data-job-id="${escapeHtml(job.id)}">看任务详情</span>` : ""}
|
||||
<span class="tag clickable-tag" data-action="goto-production">去生产中心</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2123,6 +2131,11 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
const saved = payload.saved || {};
|
||||
const item = saved.item || {};
|
||||
const started = payload.started || {};
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "production",
|
||||
title: item.binding_title || payload.source_url || "录制源已保存",
|
||||
summary: recommendedAction?.summary || item.source_url || payload.source_url || ""
|
||||
});
|
||||
return `
|
||||
<div class="task-item compact">
|
||||
<h4>${escapeHtml(item.binding_title || payload.source_url || "录制源已保存")}</h4>
|
||||
@@ -2131,12 +2144,17 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
<span class="tag blue">${escapeHtml(platformLabel(payload.platform || item.platform || "kuaishou"))}</span>
|
||||
<span class="tag">${escapeHtml(item.quality || "原画")}</span>
|
||||
<span class="tag ${started && started.ok === false ? "orange" : "green"}">${escapeHtml(started && started.ok === false ? "启动待重试" : "已同步")}</span>
|
||||
<span class="tag clickable-tag" data-action="open-live-recorder">打开录制控制</span>
|
||||
${recommendedAction?.action ? actionTag(recommendedAction.label || "打开录制控制", recommendedAction.action, recommendedAttrs) : `<span class="tag clickable-tag" data-action="open-live-recorder">打开录制控制</span>`}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
if (payload.analyzed_count !== undefined && safeArray(payload.items).length) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "discovery",
|
||||
title: "OneLiner 已分析高分作品",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<div class="mini-card"><small>平台</small><strong>${escapeHtml(platformLabel(payload.platform || payload.account?.platform || "douyin"))}</strong></div>
|
||||
@@ -2146,19 +2164,29 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
</div>
|
||||
<div class="list" style="margin-top:12px;">
|
||||
${safeArray(payload.items).slice(0, 4).map((item) => `
|
||||
<div class="task-item compact">
|
||||
<h4>${escapeHtml(item.video_title || "高分作品")}</h4>
|
||||
<p>${escapeHtml(item.summary_text || "已完成拆解。")}</p>
|
||||
<div class="task-meta">
|
||||
<span class="tag blue">得分 ${escapeHtml(formatNumber(item.performance_score || 0))}</span>
|
||||
${item.latest_job_id ? `<span class="tag clickable-tag" data-action="open-job-detail" data-job-id="${escapeHtml(item.latest_job_id)}">看原分析</span>` : ""}
|
||||
<div class="task-item compact">
|
||||
<h4>${escapeHtml(item.video_title || "高分作品")}</h4>
|
||||
<p>${escapeHtml(item.summary_text || "已完成拆解。")}</p>
|
||||
<div class="task-meta">
|
||||
<span class="tag blue">得分 ${escapeHtml(formatNumber(item.performance_score || 0))}</span>
|
||||
${item.latest_job_id ? `<span class="tag clickable-tag" data-action="open-job-detail" data-job-id="${escapeHtml(item.latest_job_id)}">看原分析</span>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`).join("")}
|
||||
`).join("")}
|
||||
</div>
|
||||
${recommendedAction?.action ? `
|
||||
<div class="task-meta" style="margin-top:12px;">
|
||||
${actionTag(recommendedAction.label || "回到找对标", recommendedAction.action, recommendedAttrs)}
|
||||
</div>
|
||||
` : ""}
|
||||
`;
|
||||
}
|
||||
if (payload.route_checks) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: recommendedAction?.screen || "playbook",
|
||||
title: payload.platform_label || payload.platform || "平台自检",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<div class="mini-card"><small>平台</small><strong>${escapeHtml(payload.platform_label || payload.platform || "-")}</strong></div>
|
||||
@@ -2191,9 +2219,19 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
${recommendedAction?.action ? `
|
||||
<div class="task-meta" style="margin-top:12px;">
|
||||
${actionTag(recommendedAction.label || "查看平台 Agent", recommendedAction.action, recommendedAttrs)}
|
||||
</div>
|
||||
` : ""}
|
||||
`;
|
||||
}
|
||||
if (payload.strategy && payload.tenant_usage) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "automation",
|
||||
title: "当前存储状态",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<div class="mini-card"><small>jobs</small><strong>${escapeHtml(payload.tenant_usage?.project_jobs?.human_size || "0B")}</strong></div>
|
||||
@@ -2201,17 +2239,37 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
<div class="mini-card"><small>模型目录</small><strong>${escapeHtml(payload.strategy?.models?.mode || "-")}</strong></div>
|
||||
<div class="mini-card"><small>录像</small><strong>${escapeHtml(payload.strategy?.live_recorder?.mode || "-")}</strong></div>
|
||||
</div>
|
||||
${recommendedAction?.action ? `
|
||||
<div class="task-meta" style="margin-top:12px;">
|
||||
${actionTag(recommendedAction.label || "去自动流程", recommendedAction.action, recommendedAttrs)}
|
||||
</div>
|
||||
` : ""}
|
||||
`;
|
||||
}
|
||||
if (payload.items || payload.files) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "production",
|
||||
title: "直播录制状态",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="detail-grid">
|
||||
<div class="mini-card"><small>录制源</small><strong>${escapeHtml(formatNumber(safeArray(payload.items).length))}</strong></div>
|
||||
<div class="mini-card"><small>最近文件</small><strong>${escapeHtml(formatNumber(safeArray(payload.files).length))}</strong></div>
|
||||
</div>
|
||||
${recommendedAction?.action ? `
|
||||
<div class="task-meta" style="margin-top:12px;">
|
||||
${actionTag(recommendedAction.label || "打开录制维护", recommendedAction.action, recommendedAttrs)}
|
||||
</div>
|
||||
` : ""}
|
||||
`;
|
||||
}
|
||||
if (payload.content) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "playbook",
|
||||
title: "生成文案",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="task-item compact">
|
||||
<h4>生成文案</h4>
|
||||
@@ -2219,11 +2277,17 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
<div class="task-meta">
|
||||
${payload.assistant_id ? `<span class="tag blue">${escapeHtml(payload.assistant_id)}</span>` : ""}
|
||||
<span class="tag">${escapeHtml(formatNumber(safeArray(payload.used_documents).length))} 个参考素材</span>
|
||||
${recommendedAction?.action ? actionTag(recommendedAction.label || "继续调文案", recommendedAction.action, recommendedAttrs) : ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
if (payload.verdict !== undefined || payload.next_actions !== undefined || payload.highlights !== undefined) {
|
||||
const recommendedAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
screen: "review",
|
||||
title: payload.title || "复盘草稿",
|
||||
summary: recommendedAction?.summary || ""
|
||||
});
|
||||
return `
|
||||
<div class="task-item compact">
|
||||
<h4>${escapeHtml(payload.title || "复盘草稿")}</h4>
|
||||
@@ -2232,7 +2296,7 @@ function renderOneLinerExecutionPayloadHtml(payload) {
|
||||
<span class="tag blue">${escapeHtml(platformLabel(payload.platform || "douyin"))}</span>
|
||||
<span class="tag">${escapeHtml(payload.verdict || "待补充")}</span>
|
||||
${payload.source_job_id ? `<span class="tag clickable-tag" data-action="open-job-detail" data-job-id="${escapeHtml(payload.source_job_id)}">看任务详情</span>` : ""}
|
||||
${payload.id ? `<span class="tag clickable-tag" data-action="open-review-edit" data-review-id="${escapeHtml(payload.id)}">打开复盘</span>` : ""}
|
||||
${recommendedAction?.action ? actionTag(recommendedAction.label || "打开复盘", recommendedAction.action, recommendedAttrs) : payload.id ? `<span class="tag clickable-tag" data-action="open-review-edit" data-review-id="${escapeHtml(payload.id)}">打开复盘</span>` : ""}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -7825,12 +7889,40 @@ function extractGeneratedCopy(payload) {
|
||||
return brief(raw, 2400);
|
||||
}
|
||||
|
||||
function buildRecommendedActionAttrs(recommendedAction, landing = {}) {
|
||||
const action = recommendedAction && typeof recommendedAction === "object" ? recommendedAction : {};
|
||||
const attrs = [];
|
||||
const landingAttrs = buildMainAgentLandingAttrs({
|
||||
runId: landing.runId || "",
|
||||
screen: action.screen || landing.screen || "",
|
||||
title: landing.title || "",
|
||||
summary: action.summary || landing.summary || ""
|
||||
});
|
||||
if (landingAttrs) attrs.push(landingAttrs);
|
||||
const attrMap = {
|
||||
job_id: "data-job-id",
|
||||
review_id: "data-review-id",
|
||||
platform: "data-platform",
|
||||
source_id: "data-source-id",
|
||||
file_id: "data-file-id",
|
||||
incident_id: "data-incident-id",
|
||||
run_id: "data-run-id"
|
||||
};
|
||||
Object.entries(attrMap).forEach(([key, attr]) => {
|
||||
const value = action[key];
|
||||
const text = String(value ?? "").trim();
|
||||
if (!text) return;
|
||||
attrs.push(`${attr}="${escapeHtml(text)}"`);
|
||||
});
|
||||
return attrs.join(" ");
|
||||
}
|
||||
|
||||
function renderLastActionCard() {
|
||||
if (!appState.lastAction) return "";
|
||||
const payload = appState.lastAction.payload || {};
|
||||
const recommendedAction = payload?.result?.recommended_action || payload?.recommended_action || null;
|
||||
const runId = payload?.id || payload?.run_id || "";
|
||||
const landingAttrs = buildMainAgentLandingAttrs({
|
||||
const actionAttrs = buildRecommendedActionAttrs(recommendedAction, {
|
||||
runId,
|
||||
screen: recommendedAction?.screen || "",
|
||||
title: appState.lastAction.title || "",
|
||||
@@ -7851,7 +7943,7 @@ function renderLastActionCard() {
|
||||
${(runId || recommendedAction?.action) ? `
|
||||
<div class="task-meta" style="margin-top:10px;">
|
||||
${runId ? `<span class="tag clickable-tag" data-action="open-oneliner-run-result" data-run-id="${escapeHtml(runId)}">查看结果</span>` : ""}
|
||||
${recommendedAction?.action ? `<span class="tag clickable-tag" data-action="${escapeHtml(recommendedAction.action)}" ${landingAttrs}>${escapeHtml(recommendedAction.label || "回到对应页面")}</span>` : ""}
|
||||
${recommendedAction?.action ? actionTag(recommendedAction.label || "回到对应页面", recommendedAction.action, actionAttrs) : ""}
|
||||
</div>
|
||||
` : ""}
|
||||
</div>
|
||||
|
||||
@@ -754,6 +754,25 @@ test("main agent result rendering offers a direct route back into the recommende
|
||||
assert.match(lastAction, /recommended_action/);
|
||||
});
|
||||
|
||||
test("direct oneliner execution results preserve structured follow-up attrs", () => {
|
||||
const helpers = extractBetween(APP, "function extractGeneratedCopy(payload)", "function renderLastActionCard()");
|
||||
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
|
||||
const lastAction = extractBetween(APP, "function renderLastActionCard()", "function getJobRecoveryCategory(job)");
|
||||
assert.match(helpers, /function buildRecommendedActionAttrs\(recommendedAction, landing = \{\}\)/);
|
||||
assert.match(helpers, /job_id: "data-job-id"/);
|
||||
assert.match(helpers, /review_id: "data-review-id"/);
|
||||
assert.match(helpers, /platform: "data-platform"/);
|
||||
assert.match(helpers, /source_id: "data-source-id"/);
|
||||
assert.match(execution, /const recommendedAction = payload\.recommended_action/);
|
||||
assert.match(execution, /buildRecommendedActionAttrs\(recommendedAction/);
|
||||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "看任务详情"/);
|
||||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "打开复盘"/);
|
||||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "打开录制控制"/);
|
||||
assert.match(execution, /actionTag\(recommendedAction\.label \|\| "查看平台 Agent"/);
|
||||
assert.match(lastAction, /buildRecommendedActionAttrs\(recommendedAction/);
|
||||
assert.match(lastAction, /actionTag\(recommendedAction\.label \|\| "回到对应页面"/);
|
||||
});
|
||||
|
||||
test("platform agent profiles expose history, rollback, and execution version context", () => {
|
||||
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");
|
||||
const profileEditor = extractBetween(APP, "function openPlatformAgentProfileAction(platform)", "async function openPlatformAgentProfileHistoryAction(platform, preferredVersionId = \"\")");
|
||||
|
||||
Reference in New Issue
Block a user