feat: version platform agent profiles through main agent runs
Some checks failed
StoryForge CI / Baseline checks (push) Has been cancelled
StoryForge CI / Backend tests (push) Has been cancelled
StoryForge CI / Web tests (push) Has been cancelled

This commit is contained in:
kris
2026-04-04 05:08:15 +08:00
parent 01ce085f6a
commit 895e3f3b13
6 changed files with 554 additions and 3 deletions

View File

@@ -2019,6 +2019,7 @@ function renderOneLinerExecutionPayloadHtml(payload) {
<span class="tag blue">${escapeHtml(platformAgentProfile.platform_label || platformLabel(platformAgentProfile.platform))}</span>
${platformAgentProfile.name ? `<span class="tag">${escapeHtml(platformAgentProfile.name)}</span>` : ""}
${platformAgentProfile.assistant_name ? `<span class="tag green">${escapeHtml(platformAgentProfile.assistant_name)}</span>` : ""}
${platformAgentProfile.version_no ? `<span class="tag">${escapeHtml(platformLabel(platformAgentProfile.platform || payload.platform || ""))} Agent v${escapeHtml(formatNumber(platformAgentProfile.version_no || 0))}</span>` : ""}
${platformAgentProfile.readiness_label ? `<span class="tag ${platformAgentProfile.readiness_score >= 75 ? "green" : platformAgentProfile.readiness_score >= 50 ? "blue" : "orange"}">${escapeHtml(platformAgentProfile.readiness_label)} ${escapeHtml(formatNumber(platformAgentProfile.readiness_score || 0))}</span>` : ""}
</div>
</div>
@@ -4458,6 +4459,7 @@ function renderPlatformAgentPanel() {
<span class="tag blue">${escapeHtml(item.recent_execution.intent_label || "主 Agent 任务")}</span>
<span class="tag">${escapeHtml(item.recent_execution.run_status || "done")}</span>
${item.recent_execution.oneliner_profile_version_no ? `<span class="tag">配置 v${escapeHtml(formatNumber(item.recent_execution.oneliner_profile_version_no))}</span>` : ""}
${item.recent_execution.platform_agent_profile_version_no ? `<span class="tag">${escapeHtml(item.platform_label || platformLabel(item.platform))} Agent v${escapeHtml(formatNumber(item.recent_execution.platform_agent_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;">
@@ -4469,6 +4471,7 @@ function renderPlatformAgentPanel() {
<div class="task-meta" style="margin-top:10px;">
<span class="tag clickable-tag" data-action="open-platform-agent-detail" data-platform="${escapeHtml(item.platform)}">查看详情</span>
<span class="tag clickable-tag" data-action="open-platform-agent-profile" data-platform="${escapeHtml(item.platform)}">配置</span>
<span class="tag clickable-tag" data-action="open-platform-agent-profile-history" data-platform="${escapeHtml(item.platform)}">看配置历史</span>
<span class="tag clickable-tag" data-action="open-platform-agent-memory" data-platform="${escapeHtml(item.platform)}">补记忆</span>
<span class="tag clickable-tag" data-action="open-platform-agent-skill" data-platform="${escapeHtml(item.platform)}">补技能</span>
</div>
@@ -9239,11 +9242,13 @@ function openPlatformAgentProfileAction(platform) {
description: "给这个平台绑定自己的执行 Agent并补充任务目标和方法论定位。",
submitLabel: "保存平台 Agent",
fields: [
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(current, `当前 ${platformLabel(platform)} Agent 还没有历史版本。`) },
{ name: "assistantId", label: "绑定执行 Agent", type: "select", value: current.assistant_id || assistants[0]?.value || "", options: [{ value: "", label: "先不绑定" }, ...assistants] },
{ name: "name", label: "名称", value: current.name || `${platformLabel(platform)} Agent`, placeholder: "例如:快手增长 Agent" },
{ name: "mission", label: "任务目标", type: "textarea", rows: 4, value: current.mission || "", placeholder: "例如:沉淀快手平台的开场结构、停留逻辑和转化方法论" },
{ name: "notes", label: "补充说明", type: "textarea", rows: 4, value: current.notes || "", placeholder: "例如:优先观察短句节奏、直播切片和成交句式" },
{ name: "status", label: "状态", type: "select", value: current.status || "active", options: [{ value: "active", label: "启用" }, { value: "draft", label: "草稿" }, { value: "paused", label: "暂停" }] }
{ name: "status", label: "状态", type: "select", value: current.status || "active", options: [{ value: "active", label: "启用" }, { value: "draft", label: "草稿" }, { value: "paused", label: "暂停" }] },
{ name: "reason", label: "变更原因", type: "textarea", rows: 3, value: "", placeholder: "例如:调整当前平台 Agent 的拆解重点和执行方向" }
],
onSubmit: async (values) => {
const saved = await storyforgeFetch(`/v2/platform-agents/${encodeURIComponent(platform)}/profile`, {
@@ -9255,6 +9260,7 @@ function openPlatformAgentProfileAction(platform) {
mission: values.mission || "",
notes: values.notes || "",
status: values.status || "active",
reason: values.reason || "",
config: {
self_optimize: true,
tenant_scoped_memory: true,
@@ -9263,7 +9269,44 @@ function openPlatformAgentProfileAction(platform) {
}
});
appState.platformAgents = safeArray(appState.platformAgents).filter((item) => item.platform !== platform).concat(saved).sort((a, b) => String(a.platform).localeCompare(String(b.platform)));
rememberAction("平台 Agent 已保存", `已更新 ${platformLabel(platform)} Agent。`, "green", saved);
rememberAction("平台 Agent 已保存", `已更新 ${platformLabel(platform)} Agent,当前版本 ${saved.current_version?.version_no || 1}`, "green", saved);
renderAll();
}
});
}
async function openPlatformAgentProfileHistoryAction(platform) {
const project = requireSelectedProject();
const normalizedPlatform = normalizePlatformValue(platform || getPreferredPlatform(), "douyin");
const history = await loadPolicyVersions(`/v2/platform-agents/${encodeURIComponent(normalizedPlatform)}/profile/versions?project_id=${encodeURIComponent(project.id)}`);
const audits = await storyforgeFetch(`/v2/platform-agents/${encodeURIComponent(normalizedPlatform)}/profile/audits?project_id=${encodeURIComponent(project.id)}`).catch(() => ({ items: [] }));
const current = safeArray(appState.platformAgents).find((item) => item.platform === normalizedPlatform) || {};
const selectedVersionId = history.items[0]?.id || "";
openActionModal({
title: `${platformLabel(normalizedPlatform)} Agent 配置历史`,
description: "查看平台 Agent 配置版本,并从历史里选择一个版本回滚。",
submitLabel: "回滚到所选版本",
hideSubmit: !selectedVersionId,
fields: [
{ type: "html", label: "当前版本", html: renderPolicyVersionSummary(current, `当前 ${platformLabel(normalizedPlatform)} Agent 还没有历史版本。`) },
{ type: "html", label: "历史版本", html: renderPolicyVersionsHtml(history.items, `当前 ${platformLabel(normalizedPlatform)} Agent 还没有历史版本。`) },
{ type: "html", label: "审计记录", html: renderPolicyAuditsHtml(safeArray(audits.items || audits), "当前还没有审计记录。") },
...(selectedVersionId ? [
{ name: "versionId", label: "回滚版本", type: "select", value: selectedVersionId, options: safeArray(history.items).map((item) => ({ value: item.id, label: `v${formatNumber(item.version_no || 0)} · ${item.title || brief(item.summary || item.id, 24)}` })) },
{ name: "reason", label: "回滚原因", type: "textarea", rows: 3, value: "", placeholder: "例如:恢复到上一版平台 Agent 方法论" }
] : [])
],
onSubmit: async (values) => {
const saved = await storyforgeFetch(`/v2/platform-agents/${encodeURIComponent(normalizedPlatform)}/profile/rollback`, {
method: "POST",
body: {
project_id: project.id,
version_id: values.versionId || selectedVersionId,
reason: values.reason || ""
}
});
appState.platformAgents = safeArray(appState.platformAgents).filter((item) => item.platform !== normalizedPlatform).concat(saved).sort((a, b) => String(a.platform).localeCompare(String(b.platform)));
rememberAction(`${platformLabel(normalizedPlatform)} Agent 已回滚`, `已回滚到版本 ${saved.current_version?.version_no || "所选版本"}`, "green", saved);
renderAll();
}
});
@@ -9394,6 +9437,7 @@ async function openPlatformAgentDetailAction(platform) {
<span class="tag blue">${escapeHtml(profile.recent_execution.intent_label || "主 Agent 任务")}</span>
<span class="tag">${escapeHtml(profile.recent_execution.run_status || "done")}</span>
${profile.recent_execution.oneliner_profile_version_no ? `<span class="tag">配置 v${escapeHtml(formatNumber(profile.recent_execution.oneliner_profile_version_no))}</span>` : ""}
${profile.recent_execution.platform_agent_profile_version_no ? `<span class="tag">${escapeHtml(platformLabel(normalizedPlatform))} Agent v${escapeHtml(formatNumber(profile.recent_execution.platform_agent_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;">
@@ -9446,6 +9490,7 @@ async function openPlatformAgentDetailAction(platform) {
<div class="task-meta" style="margin-top:12px;">
<span class="tag clickable-tag" data-action="run-oneliner-action" data-executor-key="platform-self-check" data-platform="${escapeHtml(normalizedPlatform)}">运行平台自检</span>
<span class="tag clickable-tag" data-action="open-platform-agent-profile" data-platform="${escapeHtml(normalizedPlatform)}">编辑配置</span>
<span class="tag clickable-tag" data-action="open-platform-agent-profile-history" data-platform="${escapeHtml(normalizedPlatform)}">看配置历史</span>
<span class="tag clickable-tag" data-action="open-platform-agent-memory" data-platform="${escapeHtml(normalizedPlatform)}">继续补记忆</span>
<span class="tag clickable-tag" data-action="open-platform-agent-skill" data-platform="${escapeHtml(normalizedPlatform)}">继续补技能</span>
<span class="tag clickable-tag" data-action="handoff-to-main-agent" data-platform="${escapeHtml(normalizedPlatform)}" data-source-screen="playbook" data-source-action-key="platform-agent-handoff" data-intent-key="custom" data-title="继续完善平台 Agent" data-goal="继续完善平台 Agent" data-summary="让主 Agent 结合当前平台记忆和技能,给出下一步执行计划。" data-plan-steps="${escapeHtml(JSON.stringify(["读取当前平台 Agent 配置", "检查记忆与技能缺口", "生成下一步执行计划"]))}">交给主 Agent 继续</span>
@@ -11172,6 +11217,10 @@ document.addEventListener("click", async (event) => {
openPlatformAgentProfileAction(action.dataset.platform || "");
return;
}
if (name === "open-platform-agent-profile-history") {
await openPlatformAgentProfileHistoryAction(action.dataset.platform || "");
return;
}
if (name === "open-platform-agent-detail") {
await openPlatformAgentDetailAction(action.dataset.platform || "");
return;

View File

@@ -749,6 +749,33 @@ test("main agent result rendering offers a direct route back into the recommende
assert.match(lastAction, /recommended_action/);
});
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)");
const profileHistory = extractBetween(APP, "async function openPlatformAgentProfileHistoryAction(platform)", "function openPlatformAgentMemoryAction(platform)");
const panel = extractBetween(APP, "function renderPlatformAgentPanel()", "function renderAdminOpsPanel()");
const detail = extractBetween(APP, "async function openPlatformAgentDetailAction(platform)", "function openPlatformSkillReviewAction(platform, skillId, accepted)");
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
assert.match(profileEditor, /renderPolicyVersionSummary\(current,/);
assert.match(profileEditor, /name: "reason"/);
assert.match(profileEditor, /saved\.current_version\?\.version_no/);
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/versions/);
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/audits/);
assert.match(profileHistory, /\/v2\/platform-agents\/\$\{encodeURIComponent\(normalizedPlatform\)\}\/profile\/rollback/);
assert.match(profileHistory, /renderPolicyVersionsHtml/);
assert.match(profileHistory, /renderPolicyAuditsHtml/);
assert.match(panel, /open-platform-agent-profile-history/);
assert.match(detail, /open-platform-agent-profile-history/);
assert.match(panel, /platform_agent_profile_version_no/);
assert.match(detail, /platform_agent_profile_version_no/);
assert.match(execution, /platformAgentProfile\.version_no/);
assert.match(actions, /name === "open-platform-agent-profile-history"/);
assert.match(actions, /openPlatformAgentProfileHistoryAction/);
});
test("main agent route actions keep landing context and destination screens render a notice", () => {
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
const actions = extractBetween(APP, "document.addEventListener(\"click\", async (event) => {", "document.addEventListener(\"submit\", async (event) => {");