feat: complete main agent message config tracing
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 07:56:20 +08:00
parent 64da9a4e9b
commit 294846e603
5 changed files with 126 additions and 24 deletions

View File

@@ -4,6 +4,12 @@
## 2026-04-04
### 主 Agent 消息卡补齐配置追溯与主动作执行上下文
- OneLiner 助手消息卡里的 `主配置历史 / 平台配置历史` 现在终于拿到真实 `version_id`,不再出现“入口在,但打开后只能停在列表顶部”的半截体验。
- 助手消息卡里的主动作也改成了和次级动作一致的执行标签:会把 `session_id / platform / executor_key / payload` 一起带上,后续再从消息卡直接执行时,不会丢掉真实上下文。
- 后端回归新增了消息卡 `execution_card` 配置追溯断言,前端回归也锁住了主动作统一走 `actionTag + buildOnelinerActionAttrs`,避免后续又退回到只剩一个裸 `data-action`
### 主 Agent 结果卡支持直达配置版本
- 主 Agent 当前运行卡、执行结果卡、平台 Agent 最近执行卡,现在不只显示 `配置 vN / 平台 Agent vN`,而且可以直接点进去打开对应的历史弹层。

View File

@@ -4052,6 +4052,8 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
context = _session_context_summary(account, project_id or "", plan.get("platform") or "")
oneliner_profile = context.get("oneliner_profile") or {}
platform_agent = context.get("platform_agent") or {}
platform_agent_assistant = platform_agent.get("assistant") or {}
context_assistant = context.get("assistant") or {}
governance = context.get("governance") or {}
effective_policy = (governance.get("effective") or {}).get("effective_policy") or {}
governance_layers = (governance.get("effective") or {}).get("layers") or []
@@ -4085,8 +4087,8 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
next_steps = []
if primary_action:
next_steps.append(f"优先执行「{primary_action.get('label', primary_action.get('key', '下一步'))}」。")
if platform_agent.get("assistant", {}).get("name"):
next_steps.append(f"默认调度 {platform_agent['assistant']['name']} 作为执行 Agent。")
if platform_agent_assistant.get("name"):
next_steps.append(f"默认调度 {platform_agent_assistant.get('name')} 作为执行 Agent。")
if evidence:
next_steps.append("我会优先参考该平台 Agent 最近沉淀的方法与技能。")
if governance_layers:
@@ -4106,7 +4108,7 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
if plan.get("intent_key") == "ops_admin" and account.get("role") != "super_admin":
summary_lines.append("当前账号不是平台最高权限用户,所以我不会放出运维 Agent 入口。")
if context.get("platform_agent"):
summary_lines.append(f"当前 {context['platform_agent']['platform_label']} Agent 已绑定:{context['platform_agent'].get('assistant', {}).get('name') or '未绑定执行 Agent'}")
summary_lines.append(f"当前 {context['platform_agent']['platform_label']} Agent 已绑定:{platform_agent_assistant.get('name') or '未绑定执行 Agent'}")
if platform_agent.get("recent_memory"):
summary_lines.append(f"最近有效经验:{platform_agent['recent_memory'].get('title') or '一条平台记忆'}")
if platform_agent.get("recent_skill"):
@@ -4204,7 +4206,7 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
},
}
)
if context.get("assistant"):
if context_assistant:
secondary_actions.append(
{
"key": "run-oneliner-action",
@@ -4261,6 +4263,11 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
"platform": "",
}
)
decorated_primary_action = _decorate_oneliner_action(
account,
project_id=project_id or "",
action=primary_action or {},
) if primary_action else {}
secondary_actions = [
_decorate_oneliner_action(account, project_id=project_id or "", action=item)
for item in secondary_actions
@@ -4275,17 +4282,28 @@ def register_oneliner_routes(app: Any, legacy: Any) -> None:
"platform": plan.get("platform", ""),
"platform_label": plan.get("platform_label", "待判断"),
"platform_agent_name": platform_agent.get("name") or "",
"assistant_name": platform_agent.get("assistant", {}).get("name") or context.get("assistant", {}).get("name") or "",
"assistant_name": platform_agent_assistant.get("name") or context_assistant.get("name") or "",
"readiness_label": platform_agent.get("readiness_label") or "",
"readiness_score": platform_agent.get("readiness_score") or 0,
"primary_action": primary_action or {},
"primary_action": decorated_primary_action,
"blocked_reason": blocked_reason,
"active_admin_override_notice": active_admin_override_notice,
"oneliner_profile_version": {
"version_id": oneliner_profile_version.get("id", ""),
"version_no": oneliner_profile_version.get("version_no", 0),
"title": oneliner_profile_version.get("title", ""),
"summary": oneliner_profile_version.get("summary", ""),
},
"platform_agent_profile": {
"platform": platform_agent.get("platform") or plan.get("platform", ""),
"platform_label": platform_agent.get("platform_label") or plan.get("platform_label", ""),
"name": platform_agent.get("name", ""),
"assistant_name": platform_agent_assistant.get("name") or context_assistant.get("name") or "",
"version_id": ((platform_agent.get("current_version") or {}).get("id") or ""),
"version_no": ((platform_agent.get("current_version") or {}).get("version_no") or 0),
"readiness_label": platform_agent.get("readiness_label") or "",
"readiness_score": platform_agent.get("readiness_score") or 0,
},
"evidence": evidence,
"next_steps": next_steps,
"secondary_actions": secondary_actions,

View File

@@ -1401,3 +1401,67 @@ class MainAgentGovernanceTests(unittest.TestCase):
action_keys = [item["action_key"] for item in audits_payload["items"]]
self.assertIn("update-oneliner-profile", action_keys)
self.assertIn("rollback-oneliner-profile", action_keys)
def test_oneliner_message_execution_card_tracks_config_versions(self) -> None:
profile_response = self.client.put(
"/v2/oneliner/profile",
headers=self.ctx["member_headers"],
json={
"project_id": self.ctx["project_id"],
"display_name": "增长总控 OneLiner",
"assistant_id": "",
"default_platform": "douyin",
"long_term_goal": "优先分析当前平台账号并收口到下一步动作",
"notes": "验证消息卡里的配置追溯链",
"config": {"analysis_mode": "fast"},
"reason": "给消息卡提供明确的主配置版本",
},
)
self.assertEqual(profile_response.status_code, 200, profile_response.text)
current_profile_version = profile_response.json()["current_version"]
platform_response = self.client.put(
"/v2/platform-agents/douyin/profile",
headers=self.ctx["member_headers"],
json={
"project_id": self.ctx["project_id"],
"name": "抖音增长 Agent",
"mission": "优先分析当前账号和高分作品",
"notes": "验证消息卡里的平台配置追溯链",
"status": "active",
"config": {"focus": "analysis"},
},
)
self.assertEqual(platform_response.status_code, 200, platform_response.text)
current_platform_version = platform_response.json()["current_version"]
session_response = self.client.post(
"/v2/oneliner/sessions",
headers=self.ctx["member_headers"],
json={
"project_id": self.ctx["project_id"],
"preferred_platform": "douyin",
"title": "消息卡配置追溯",
},
)
self.assertEqual(session_response.status_code, 200, session_response.text)
session_payload = session_response.json()
message_response = self.client.post(
f"/v2/oneliner/sessions/{session_payload['id']}/messages",
headers=self.ctx["member_headers"],
json={
"project_id": self.ctx["project_id"],
"platform": "douyin",
"content": "帮我创建 Agent",
},
)
self.assertEqual(message_response.status_code, 200, message_response.text)
payload = message_response.json()
execution_card = (((payload.get("assistant_message") or {}).get("result")) or {}).get("execution_card") or {}
self.assertEqual((execution_card.get("primary_action") or {}).get("key"), "open-create-assistant")
self.assertEqual((execution_card.get("oneliner_profile_version") or {}).get("version_id"), current_profile_version["id"])
self.assertEqual((execution_card.get("oneliner_profile_version") or {}).get("version_no"), current_profile_version["version_no"])
self.assertEqual((execution_card.get("platform_agent_profile") or {}).get("platform"), "douyin")
self.assertEqual((execution_card.get("platform_agent_profile") or {}).get("version_id"), current_platform_version["id"])
self.assertEqual((execution_card.get("platform_agent_profile") or {}).get("version_no"), current_platform_version["version_no"])

View File

@@ -1346,8 +1346,28 @@ function renderOneLinerMessagesHtml() {
const executionCard = result.execution_card || {};
const activeAdminOverrideNotice = executionCard.active_admin_override_notice || null;
const profileVersion = executionCard.oneliner_profile_version || {};
const platformAgentProfile = executionCard.platform_agent_profile || {};
const actions = safeArray(plan.suggested_actions);
const primaryAction = executionCard.primary_action || {};
const secondaryActions = safeArray(executionCard.secondary_actions);
const buildOnelinerActionAttrs = (item) => {
const attrs = [
item.executor_key ? `data-executor-key="${escapeHtml(item.executor_key)}"` : "",
item.platform ? `data-platform="${escapeHtml(item.platform)}"` : "",
message.session_id ? `data-session-id="${escapeHtml(message.session_id)}"` : "",
];
Object.entries(item.payload || {}).forEach(([payloadKey, payloadValue]) => {
const attrKey = String(payloadKey || "")
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
.replace(/_/g, "-")
.toLowerCase();
const serialized = typeof payloadValue === "string"
? payloadValue
: JSON.stringify(payloadValue);
attrs.push(`data-${escapeHtml(attrKey)}="${escapeHtml(serialized)}"`);
});
return attrs.filter(Boolean).join(" ");
};
return `
<div class="oneliner-message ${roleClass}">
<div class="oneliner-bubble">
@@ -1375,9 +1395,14 @@ function renderOneLinerMessagesHtml() {
${executionCard.assistant_name ? `<span class="tag green">${escapeHtml(executionCard.assistant_name)}</span>` : ""}
${profileVersion.version_no ? `<span class="tag">配置 v${escapeHtml(formatNumber(profileVersion.version_no || 0))}</span>` : ""}
${profileVersion.version_no ? `<span class="tag clickable-tag" data-action="open-oneliner-profile-history" data-version-id="${escapeHtml(profileVersion.version_id || "")}">看主配置历史</span>` : ""}
${executionCard.platform && executionCard.platform_agent_profile?.version_no ? `<span class="tag clickable-tag" data-action="open-platform-agent-profile-history" data-platform="${escapeHtml(executionCard.platform)}" data-version-id="${escapeHtml(executionCard.platform_agent_profile?.version_id || "")}">看平台配置历史</span>` : ""}
${executionCard.platform && platformAgentProfile.version_no ? `<span class="tag clickable-tag" data-action="open-platform-agent-profile-history" data-platform="${escapeHtml(executionCard.platform)}" data-version-id="${escapeHtml(platformAgentProfile.version_id || "")}">看平台配置历史</span>` : ""}
${executionCard.readiness_label ? `<span class="tag ${executionCard.readiness_score >= 75 ? "green" : executionCard.readiness_score >= 50 ? "blue" : "orange"}">${escapeHtml(executionCard.readiness_label)} ${escapeHtml(formatNumber(executionCard.readiness_score || 0))}</span>` : ""}
${executionCard.primary_action?.key ? `<span class="tag clickable-tag" data-action="${escapeHtml(executionCard.primary_action.key)}">${escapeHtml(executionCard.primary_action.label || "执行下一步")}</span>` : ""}
${primaryAction.key ? actionTag(
primaryAction.label || "执行下一步",
primaryAction.key || "",
buildOnelinerActionAttrs(primaryAction),
{ disabledReason: primaryAction.disabled_reason || "" }
) : ""}
</div>
${profileVersion.version_no ? `
<div class="panel-subtitle" style="margin-top:8px;">${escapeHtml(profileVersion.summary || profileVersion.title || `当前按 OneLiner 配置 v${formatNumber(profileVersion.version_no || 0)} 执行。`)}</div>
@@ -1412,22 +1437,7 @@ function renderOneLinerMessagesHtml() {
${secondaryActions.map((item) => actionTag(
item.label || item.key || "执行",
item.key || "",
[
item.executor_key ? `data-executor-key="${escapeHtml(item.executor_key)}"` : "",
item.platform ? `data-platform="${escapeHtml(item.platform)}"` : "",
message.session_id ? `data-session-id="${escapeHtml(message.session_id)}"` : "",
...Object.entries(item.payload || {}).map(([payloadKey, payloadValue]) => {
const attrKey = String(payloadKey || "")
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
.replace(/_/g, "-")
.toLowerCase();
const serialized = typeof payloadValue === "string"
? payloadValue
: JSON.stringify(payloadValue);
return `data-${escapeHtml(attrKey)}="${escapeHtml(serialized)}"`;
})
].filter(Boolean).join(" ")
,
buildOnelinerActionAttrs(item),
{ disabledReason: item.disabled_reason || "" }
)).join("")}
</div>

View File

@@ -961,9 +961,13 @@ test("main agent execution cards can jump to oneliner and platform profile histo
const messages = extractBetween(APP, "function renderOneLinerMessagesHtml()", "function renderAutoConnectingScreen(screenTitle, nextStepText)");
const runtime = extractBetween(APP, "function renderOneLinerRunsHtml()", "function renderOneLinerMessagesHtml()");
const execution = extractBetween(APP, "function renderOneLinerExecutionPayloadHtml(payload)", "function parseOneLinerActionPayloadValue(value)");
assert.match(messages, /const buildOnelinerActionAttrs = \(item\) =>/);
assert.match(messages, /data-action="open-oneliner-profile-history"/);
assert.match(messages, /data-action="open-platform-agent-profile-history"/);
assert.match(messages, /data-version-id="\$\{escapeHtml\(profileVersion\.version_id \|\| ""\)\}"/);
assert.match(messages, /data-version-id="\$\{escapeHtml\(platformAgentProfile\.version_id \|\| ""\)\}"/);
assert.match(messages, /actionTag\(\s*primaryAction\.label \|\| "执行下一步"/);
assert.match(messages, /buildOnelinerActionAttrs\(primaryAction\)/);
assert.match(runtime, /data-version-id="\$\{escapeHtml\(currentRunConfigVersion\.version_id \|\| ""\)\}"/);
assert.match(execution, /data-version-id="\$\{escapeHtml\(configVersion\.version_id \|\| ""\)\}"/);
assert.match(execution, /data-version-id="\$\{escapeHtml\(platformAgentProfile\.version_id \|\| ""\)\}"/);