feat: carry platform agent config into 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-03 15:38:01 +08:00
parent bbceada4f1
commit f890a0ace7
5 changed files with 98 additions and 0 deletions

View File

@@ -103,6 +103,13 @@
- run 的治理快照也收窄成“当前主配置 + 当前版本”最小运行态,不再把完整版本历史和审计链塞进每次执行记录,避免 `agent_runs.governance_json` 无限制膨胀。
- Web 回归测试修正了 OneLiner 运行区函数边界,并新增了对执行链配置版本显示的断言;后端治理测试也补上了 run 完成态必须带配置版本的检查。
### 平台 Agent 配置进入执行链
- 主 Agent 在创建 run、重试 run 时,会把当前平台 Agent 的最小运行快照一起固化进治理快照包括平台、Agent 名称、承接使命、assistant 名称和 readiness 状态。
- 完成态结果现在会带上 `execution_card.platform_agent_profile`,前端浮窗、当前运行卡和结果卡都能直接看到“本轮平台 Agent”执行链不会再丢失平台侧配置来源。
- run 的平台 Agent 快照只保留运行时最小必要字段,不把完整平台 Agent 配置、技能列表和记忆列表塞进执行结果,避免执行记录继续膨胀。
- Web 回归测试新增了对“本轮平台 Agent”结果渲染的断言后端治理测试也补上了 run 创建态与完成态必须带平台 Agent 快照的检查。
### NAS 联调发布
- 最新 Web 已重新发布到 fnOS NAS

View File

@@ -1248,6 +1248,35 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
"updated_at": (row or {}).get("updated_at", ""),
}
def _platform_agent_runtime_snapshot(
account: dict[str, Any],
row: dict[str, Any] | None,
*,
platform: str,
project_id: str = "",
) -> dict[str, Any]:
payload = _platform_agent_payload(account, row, platform=platform, project_id=project_id)
assistant = payload.get("assistant") or {}
recent_memory = payload.get("recent_memory") or {}
recent_skill = payload.get("recent_skill") or {}
return {
"id": str(payload.get("id") or "").strip(),
"platform": str(payload.get("platform") or platform or "").strip(),
"platform_label": str(payload.get("platform_label") or legacy.platform_label(platform) or "").strip(),
"assistant_id": str(payload.get("assistant_id") or "").strip(),
"assistant_name": str((assistant or {}).get("name") or "").strip(),
"name": str(payload.get("name") or "").strip(),
"mission": str(payload.get("mission") or "").strip(),
"notes": str(payload.get("notes") or "").strip(),
"status": str(payload.get("status") or "").strip(),
"memory_count": int(payload.get("memory_count") or 0),
"skill_count": int(payload.get("skill_count") or 0),
"readiness_score": int(payload.get("readiness_score") or 0),
"readiness_label": str(payload.get("readiness_label") or "").strip(),
"recent_memory_title": str(recent_memory.get("title") or "").strip(),
"recent_skill_title": str(recent_skill.get("title") or "").strip(),
}
def _memory_payload(row: dict[str, Any]) -> dict[str, Any]:
return {
"id": row["id"],
@@ -3190,6 +3219,7 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
or (governance.get("oneliner_profile") or {}).get("current_version")
or {}
)
platform_agent_profile = governance.get("platform_agent_profile") or {}
steps = [str(item).strip() for item in list(plan.get("steps") or []) if str(item).strip()]
if not steps:
steps = ["读取当前项目上下文", "结合治理层生成执行计划", "收口为可执行建议"]
@@ -3222,6 +3252,16 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
"title": str(oneliner_profile_version.get("title") or "").strip(),
"summary": str(oneliner_profile_version.get("summary") or "").strip(),
},
"platform_agent_profile": {
"platform": str(platform_agent_profile.get("platform") or "").strip(),
"platform_label": str(platform_agent_profile.get("platform_label") or "").strip(),
"name": str(platform_agent_profile.get("name") or "").strip(),
"assistant_name": str(platform_agent_profile.get("assistant_name") or "").strip(),
"mission": str(platform_agent_profile.get("mission") or "").strip(),
"status": str(platform_agent_profile.get("status") or "").strip(),
"readiness_label": str(platform_agent_profile.get("readiness_label") or "").strip(),
"readiness_score": int(platform_agent_profile.get("readiness_score") or 0),
},
"next_steps": steps,
},
}
@@ -5087,11 +5127,21 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
platform=normalized_platform,
)
profile_row = _fetch_profile_row(account, project["id"]) or _ensure_oneliner_profile(account, project["id"])
platform_profile_row = legacy.db.fetch_one(
"SELECT * FROM platform_agent_profiles WHERE user_id = ? AND project_id = ? AND platform = ?",
(account["id"], project["id"], normalized_platform),
) if normalized_platform else None
oneliner_profile_bundle = _oneliner_profile_runtime_snapshot(profile_row, account=account)
governance_snapshot = {
**governance,
"oneliner_profile": oneliner_profile_bundle,
"oneliner_profile_version": oneliner_profile_bundle.get("current_version") or {},
"platform_agent_profile": _platform_agent_runtime_snapshot(
account,
platform_profile_row,
platform=normalized_platform,
project_id=project["id"],
) if normalized_platform else {},
}
plan = _agent_run_plan_payload(
request,
@@ -5178,11 +5228,21 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
platform=platform,
)
profile_row = _fetch_profile_row(account, project_id) or _ensure_oneliner_profile(account, project_id)
platform_profile_row = legacy.db.fetch_one(
"SELECT * FROM platform_agent_profiles WHERE user_id = ? AND project_id = ? AND platform = ?",
(account["id"], project_id, platform),
) if platform else None
oneliner_profile_bundle = _oneliner_profile_runtime_snapshot(profile_row, account=account)
governance_snapshot = {
**governance,
"oneliner_profile": oneliner_profile_bundle,
"oneliner_profile_version": oneliner_profile_bundle.get("current_version") or {},
"platform_agent_profile": _platform_agent_runtime_snapshot(
account,
platform_profile_row,
platform=platform,
project_id=project_id,
) if platform else {},
}
plan = _parse_json(row.get("plan_json"), {})
session_id = str(row.get("session_id") or "").strip()

View File

@@ -227,6 +227,8 @@ class MainAgentGovernanceTests(unittest.TestCase):
self.assertIn("oneliner_profile", payload["governance"])
self.assertIn("oneliner_profile_version", payload["governance"])
self.assertGreaterEqual(payload["governance"]["oneliner_profile_version"]["version_no"], 1)
self.assertIn("platform_agent_profile", payload["governance"])
self.assertEqual(payload["governance"]["platform_agent_profile"]["platform"], "douyin")
self.assertEqual(payload["events"][0]["event_type"], "run.created")
def test_agent_run_confirm_transitions_to_queue_or_running_and_logs_events(self) -> None:
@@ -310,6 +312,7 @@ class MainAgentGovernanceTests(unittest.TestCase):
self.assertGreaterEqual(len(payload["result"]["result_sections"]["cards"]), 2)
self.assertEqual(payload["result"]["result_sections"]["cards"][0]["title"], "当前焦点")
self.assertGreaterEqual(payload["result"]["execution_card"]["oneliner_profile_version"]["version_no"], 1)
self.assertEqual(payload["result"]["execution_card"]["platform_agent_profile"]["platform"], "douyin")
event_types = [item["event_type"] for item in payload["events"]]
self.assertIn("run.progress", event_types)
self.assertIn("run.done", event_types)

View File

@@ -1131,6 +1131,7 @@ function renderOneLinerRunsHtml() {
: "";
const canRetryCurrentRun = ["blocked", "failed", "cancelled"].includes(currentRun.run_status);
const currentRunConfigVersion = currentRun.governance?.oneliner_profile_version || currentRun.governance?.oneliner_profile?.current_version || {};
const currentRunPlatformAgentProfile = currentRun.result?.execution_card?.platform_agent_profile || currentRun.governance?.platform_agent_profile || {};
return `
<div class="task-item compact" style="margin-bottom:10px;">
<h4>近期运行概况</h4>
@@ -1232,6 +1233,18 @@ function renderOneLinerRunsHtml() {
</div>
</div>
` : ""}
${currentRunPlatformAgentProfile.platform ? `
<div class="task-item compact" style="margin-top:10px;">
<h4>本轮平台 Agent</h4>
<p>${escapeHtml(currentRunPlatformAgentProfile.mission || currentRunPlatformAgentProfile.name || `${currentRunPlatformAgentProfile.platform_label || platformLabel(currentRunPlatformAgentProfile.platform)} Agent 正在承接这轮执行。`)}</p>
<div class="task-meta">
<span class="tag blue">${escapeHtml(currentRunPlatformAgentProfile.platform_label || platformLabel(currentRunPlatformAgentProfile.platform))}</span>
${currentRunPlatformAgentProfile.name ? `<span class="tag">${escapeHtml(currentRunPlatformAgentProfile.name)}</span>` : ""}
${currentRunPlatformAgentProfile.assistant_name ? `<span class="tag green">${escapeHtml(currentRunPlatformAgentProfile.assistant_name)}</span>` : ""}
${currentRunPlatformAgentProfile.readiness_label ? `<span class="tag ${currentRunPlatformAgentProfile.readiness_score >= 75 ? "green" : currentRunPlatformAgentProfile.readiness_score >= 50 ? "blue" : "orange"}">${escapeHtml(currentRunPlatformAgentProfile.readiness_label)} ${escapeHtml(formatNumber(currentRunPlatformAgentProfile.readiness_score || 0))}</span>` : ""}
</div>
</div>
` : ""}
${!hasResultPayload && previewAction?.summary ? `<div class="panel-subtitle" style="margin-top:8px;">${escapeHtml(previewAction.summary)}</div>` : ""}
${planSteps.length ? `
<div class="list" style="margin-top:10px;">
@@ -1969,6 +1982,7 @@ function renderOneLinerExecutionPayloadHtml(payload) {
: {};
const resultCards = safeArray(resultSections.cards).slice(0, 4);
const configVersion = payload.execution_card?.oneliner_profile_version || payload.context?.oneliner_profile?.current_version || {};
const platformAgentProfile = payload.execution_card?.platform_agent_profile || {};
const landingAttrs = buildMainAgentLandingAttrs({
runId: landingRunId,
screen: landingScreen,
@@ -1997,6 +2011,18 @@ function renderOneLinerExecutionPayloadHtml(payload) {
</div>
</div>
` : ""}
${platformAgentProfile.platform ? `
<div class="task-item compact" style="margin-top:12px;">
<h4>本轮平台 Agent</h4>
<p>${escapeHtml(platformAgentProfile.mission || platformAgentProfile.name || `${platformAgentProfile.platform_label || platformLabel(platformAgentProfile.platform)} Agent 正在承接这轮执行。`)}</p>
<div class="task-meta">
<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.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>
` : ""}
${resultCards.length ? `
<div class="task-item compact" style="margin-top:12px;">
<h4>${escapeHtml(resultSections.workstream_label || "执行结果分组")}</h4>

View File

@@ -725,6 +725,8 @@ test("main agent result rendering offers a direct route back into the recommende
assert.match(execution, /result_sections/);
assert.match(execution, /当前焦点/);
assert.match(execution, /detail-grid/);
assert.match(execution, /本轮平台 Agent/);
assert.match(execution, /platform_agent_profile/);
assert.match(execution, /data-action="\$\{escapeHtml\(payload\.recommended_action\.action\)\}"/);
assert.match(lastAction, /open-oneliner-run-result/);
assert.match(lastAction, /recommended_action/);