feat: advance main agent runs from homepage handoff
This commit is contained in:
@@ -28,6 +28,36 @@
|
||||
`;
|
||||
}
|
||||
|
||||
function createHandoffMetadata(config = {}) {
|
||||
const steps = safeArray(config.planSteps).map((item) => String(item || "").trim()).filter(Boolean);
|
||||
return {
|
||||
sourceScreen: config.sourceScreen || "dashboard",
|
||||
sourceActionKey: config.sourceActionKey || "homepage-action",
|
||||
intentKey: config.intentKey || "custom",
|
||||
title: config.title || "",
|
||||
goal: config.goal || config.title || "",
|
||||
summary: config.summary || "",
|
||||
platform: config.platform || "",
|
||||
platformScope: config.platformScope || "single_platform",
|
||||
planSteps: steps.length ? steps : ["读取当前项目上下文", "结合当前动作生成执行计划", "等待确认后执行"]
|
||||
};
|
||||
}
|
||||
|
||||
function buildHandoffAttrs(config, escapeHtml) {
|
||||
const metadata = createHandoffMetadata(config);
|
||||
return [
|
||||
`data-source-screen="${escapeHtml(metadata.sourceScreen)}"`,
|
||||
`data-source-action-key="${escapeHtml(metadata.sourceActionKey)}"`,
|
||||
`data-intent-key="${escapeHtml(metadata.intentKey)}"`,
|
||||
`data-title="${escapeHtml(metadata.title)}"`,
|
||||
`data-goal="${escapeHtml(metadata.goal)}"`,
|
||||
`data-summary="${escapeHtml(metadata.summary)}"`,
|
||||
`data-platform-scope="${escapeHtml(metadata.platformScope)}"`,
|
||||
`data-plan-steps="${escapeHtml(JSON.stringify(metadata.planSteps))}"`,
|
||||
metadata.platform ? `data-platform="${escapeHtml(metadata.platform)}"` : ""
|
||||
].filter(Boolean);
|
||||
}
|
||||
|
||||
function createDashboardHomeModel(raw) {
|
||||
const trackedAccountsCount = Number(raw?.trackedAccountsCount || 0);
|
||||
const assistantCount = Number(raw?.assistantCount || 0);
|
||||
@@ -44,7 +74,11 @@
|
||||
badges: ["最优先", "项目入口"],
|
||||
goAction: "goto-intake",
|
||||
goLabel: "去项目",
|
||||
agentLabel: "交给主 Agent"
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: "homepage-primary-action",
|
||||
intentKey: "create_project",
|
||||
platformScope: "all_platforms",
|
||||
planSteps: ["读取当前工作区项目列表", "确认需要切换还是新建项目", "给出主流程推进建议"]
|
||||
});
|
||||
} else if (trackedAccountsCount > 0) {
|
||||
actions.push({
|
||||
@@ -53,7 +87,11 @@
|
||||
badges: ["最优先", "预计 10 分钟判断", "关联:重点账号"],
|
||||
goAction: "goto-discovery",
|
||||
goLabel: "去找对标",
|
||||
agentLabel: "交给主 Agent"
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: "homepage-primary-action",
|
||||
intentKey: "analyze_top_videos",
|
||||
platform: "douyin",
|
||||
planSteps: ["读取当前项目上下文", "检查重点账号最近变化", "补充高分作品分析结论"]
|
||||
});
|
||||
} else if (assistantCount <= 0) {
|
||||
actions.push({
|
||||
@@ -62,7 +100,10 @@
|
||||
badges: ["最优先", "Agent 缺失"],
|
||||
goAction: "goto-playbook",
|
||||
goLabel: "去创建",
|
||||
agentLabel: "交给主 Agent"
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: "homepage-primary-action",
|
||||
intentKey: "create_assistant",
|
||||
planSteps: ["读取当前项目职责", "确认首个 Agent 角色", "给出创建与配置建议"]
|
||||
});
|
||||
} else {
|
||||
actions.push({
|
||||
@@ -71,7 +112,10 @@
|
||||
badges: ["默认推进", "主流程"],
|
||||
goAction: "goto-production",
|
||||
goLabel: "去处理",
|
||||
agentLabel: "交给主 Agent"
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: "homepage-primary-action",
|
||||
intentKey: "custom",
|
||||
planSteps: ["读取当前项目上下文", "检查对标和生产链路状态", "生成下一步执行计划"]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -80,7 +124,11 @@
|
||||
title: "确认一个待执行的生产计划",
|
||||
reason: "素材和结论都在,只差最后确认。",
|
||||
goAction: "goto-production",
|
||||
goLabel: "去处理"
|
||||
goLabel: "去处理",
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: "homepage-secondary-action-1",
|
||||
intentKey: "custom",
|
||||
planSteps: ["读取当前待执行生产任务", "确认素材和结论完整性", "给出执行确认建议"]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -88,7 +136,11 @@
|
||||
title: "更新重点账号的跟踪摘要",
|
||||
reason: "有新动态,但不值得占据大块首页空间。",
|
||||
goAction: "goto-tracking",
|
||||
goLabel: "去处理"
|
||||
goLabel: "去处理",
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: `homepage-secondary-action-${Math.max(actions.length, 1)}`,
|
||||
intentKey: "track_account",
|
||||
planSteps: ["读取重点账号近 7 天动态", "更新跟踪摘要", "给出是否继续跟进建议"]
|
||||
});
|
||||
|
||||
while (actions.length < 3) {
|
||||
@@ -96,7 +148,11 @@
|
||||
title: "继续补高分对标并安排生产",
|
||||
reason: "当前项目没有更多高优先动作时,保持主流程推进。",
|
||||
goAction: "goto-production",
|
||||
goLabel: "去处理"
|
||||
goLabel: "去处理",
|
||||
agentLabel: "交给主 Agent",
|
||||
sourceActionKey: `homepage-secondary-action-${actions.length}`,
|
||||
intentKey: "custom",
|
||||
planSteps: ["读取当前项目上下文", "检查主流程空缺", "给出下一步执行建议"]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -122,6 +178,17 @@
|
||||
}
|
||||
|
||||
function renderSecondaryAction(item, index, escapeHtml) {
|
||||
const handoffAttrs = buildHandoffAttrs({
|
||||
sourceScreen: "dashboard",
|
||||
sourceActionKey: item.sourceActionKey || `homepage-secondary-action-${index + 1}`,
|
||||
intentKey: item.intentKey || "custom",
|
||||
title: item.title,
|
||||
goal: item.title,
|
||||
summary: item.reason,
|
||||
platform: item.platform,
|
||||
platformScope: item.platformScope || "single_platform",
|
||||
planSteps: item.planSteps
|
||||
}, escapeHtml);
|
||||
return `
|
||||
<div class="dashboard-action-secondary">
|
||||
<div class="dashboard-action-index">${index + 2}</div>
|
||||
@@ -141,6 +208,12 @@
|
||||
action: item.goAction || "goto-production",
|
||||
tone: "secondary"
|
||||
}, escapeHtml)}
|
||||
${renderActionButton({
|
||||
label: item.agentLabel || "交给主 Agent",
|
||||
action: "handoff-to-main-agent",
|
||||
tone: "secondary",
|
||||
attrs: handoffAttrs
|
||||
}, escapeHtml)}
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
@@ -152,6 +225,17 @@
|
||||
const contextLinks = safeArray(model?.contextLinks);
|
||||
const primaryAction = model?.primaryAction || {};
|
||||
const secondaryActions = safeArray(model?.secondaryActions);
|
||||
const primaryHandoffAttrs = buildHandoffAttrs({
|
||||
sourceScreen: "dashboard",
|
||||
sourceActionKey: primaryAction.sourceActionKey || "homepage-primary-action",
|
||||
intentKey: primaryAction.intentKey || "custom",
|
||||
title: primaryAction.title,
|
||||
goal: primaryAction.title,
|
||||
summary: primaryAction.reason,
|
||||
platform: primaryAction.platform,
|
||||
platformScope: primaryAction.platformScope || "single_platform",
|
||||
planSteps: primaryAction.planSteps
|
||||
}, escapeHtml);
|
||||
|
||||
return `
|
||||
<div class="dashboard-home">
|
||||
@@ -214,8 +298,9 @@
|
||||
}, escapeHtml)}
|
||||
${renderActionButton({
|
||||
label: primaryAction.agentLabel || "交给主 Agent",
|
||||
action: "open-oneliner",
|
||||
tone: "primary"
|
||||
action: "handoff-to-main-agent",
|
||||
tone: "primary",
|
||||
attrs: primaryHandoffAttrs
|
||||
}, escapeHtml)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -57,6 +57,7 @@ test("homepage v6 puts actions before overview and uses 1-primary-2-secondary st
|
||||
assert.match(html, /先补抖音重点对标的高分作品分析/);
|
||||
assert.match(html, /确认一个待执行的生产计划/);
|
||||
assert.match(html, /更新重点账号的跟踪摘要/);
|
||||
assert.match(html, /data-action="handoff-to-main-agent"/);
|
||||
});
|
||||
|
||||
test("homepage model builds one primary action, two secondary actions, and a rule fallback label", () => {
|
||||
@@ -98,3 +99,11 @@ test("homepage overview uses tab buttons and does not render legacy repeated sec
|
||||
assert.ok(!html.includes("当前项目推进详情"));
|
||||
assert.ok(!html.includes("重点账号 / 对标</h3><div class=\"panel-subtitle\">右栏保留"));
|
||||
});
|
||||
|
||||
test("homepage handoff buttons carry runtime plan metadata instead of only opening chat", () => {
|
||||
const source = fs.readFileSync(path.join(ROOT, "assets/storyforge-dashboard-home.js"), "utf8");
|
||||
assert.match(source, /handoff-to-main-agent/);
|
||||
assert.match(source, /data-source-screen=/);
|
||||
assert.match(source, /data-source-action-key=/);
|
||||
assert.match(source, /data-plan-steps=/);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user