Files
2026-06-08 18:14:59 +08:00

173 lines
6.3 KiB
Python

"""
Built-in agent Chinese display normalization.
"""
from __future__ import annotations
from copy import deepcopy
from typing import Any, Dict, Iterable, Optional
class BuiltinAgentText:
def __init__(
self,
*,
name: str,
code_label: str,
description: str,
role: str = "",
skills: Optional[list[str]] = None,
constraints: Optional[list[str]] = None,
background: str = "",
keys: Iterable[str],
description_keywords: Iterable[str] = (),
persona_keywords: Iterable[str] = (),
):
self.name = name
self.code_label = code_label
self.description = description
self.role = role
self.skills = skills or []
self.constraints = constraints or []
self.background = background
self.keys = list(keys)
self.description_keywords = list(description_keywords)
self.persona_keywords = list(persona_keywords)
BUILTIN_AGENT_TEXTS = [
BuiltinAgentText(
name="项目经理",
code_label="项目管理",
description="协调交付状态、进度风险和跨角色协作,确保项目按计划推进。",
keys=("project manager", "project_manager", "project-manager", "projectmanager"),
description_keywords=("coordinates delivery status",),
),
BuiltinAgentText(
name="Multica 产品经理",
code_label="产品管理",
description="负责产品需求分诊、优先级判断和方案澄清,推动产品决策落地。",
role="负责 Multica 协作工作的产品需求分诊、范围澄清、验收标准和质量推进决策。",
skills=["范围澄清", "验收标准设计", "优先级取舍分析", "干系人沟通"],
constraints=[
"需求必须能追溯到具体 issue 或用户请求。",
"没有明确验收标准时,不推进下游工作。",
"遇到未决产品决策时要明确指出,不能擅自假设。",
],
background="擅长把模糊的平台需求转化为责任清晰、可评审、可交付的 Multica issue。",
keys=(
"multica product manager",
"multica_product_manager",
"multica-product-manager",
"product manager",
"product_manager",
"product-manager",
),
description_keywords=("owns product triage",),
persona_keywords=(
"product manager for multica",
"scope clarification",
"acceptance criteria design",
"priority tradeoff analysis",
"stakeholder communication",
"keep requirements traceable",
),
),
BuiltinAgentText(
name="业务需求分析师",
code_label="需求分析",
description="将业务诉求转化为清晰需求、验收标准和可执行的交付范围。",
keys=(
"business requirements analyst",
"business_requirements_analyst",
"business-requirements-analyst",
"business analyst",
"business_analyst",
"business-analyst",
),
description_keywords=("translates business needs",),
),
BuiltinAgentText(
name="系统架构师",
code_label="系统架构",
description="设计系统边界、模块职责和技术方案,保障架构一致性与可演进性。",
keys=("system architect", "system_architect", "system-architect"),
),
BuiltinAgentText(
name="前端工程师",
code_label="前端开发",
description="负责前端页面、组件交互、路由状态和浏览器端体验实现。",
keys=("frontend engineer", "frontend_engineer", "frontend-engineer"),
),
BuiltinAgentText(
name="后端工程师",
code_label="后端开发",
description="负责后端接口、业务服务、数据模型和系统集成能力建设。",
keys=("backend engineer", "backend_engineer", "backend-engineer"),
),
BuiltinAgentText(
name="测试工程师",
code_label="质量保障",
description="负责测试策略、用例设计、缺陷验证和发布质量把关。",
keys=("qa engineer", "qa_engineer", "qa-engineer"),
),
]
def _normalize_text(value: Any) -> str:
return " ".join(str(value or "").strip().lower().replace("-", " ").replace("_", " ").split())
def _iter_persona_values(persona: Any) -> Iterable[str]:
if not isinstance(persona, dict):
return []
values: list[str] = []
for key in ("role", "background"):
value = persona.get(key)
if isinstance(value, str):
values.append(value)
for key in ("personality", "skills", "constraints"):
values.extend(item for item in persona.get(key) or [] if isinstance(item, str))
return values
def find_builtin_agent_text(data: Dict[str, Any]) -> Optional[BuiltinAgentText]:
name = _normalize_text(data.get("name"))
code = _normalize_text(data.get("code"))
description = _normalize_text(data.get("description"))
persona_text = _normalize_text(" ".join(_iter_persona_values(data.get("persona"))))
for display in BUILTIN_AGENT_TEXTS:
keys = {_normalize_text(key) for key in display.keys}
if name in keys or code in keys:
return display
if any(keyword in description for keyword in display.description_keywords):
return display
if any(keyword in persona_text for keyword in display.persona_keywords):
return display
return None
def normalize_builtin_agent_payload(data: Dict[str, Any], *, include_code_label: bool = False) -> Dict[str, Any]:
display = find_builtin_agent_text(data)
if not display:
return data
normalized = deepcopy(data)
normalized["name"] = display.name
normalized["description"] = display.description
if include_code_label:
normalized["code_label"] = display.code_label
persona = deepcopy(normalized.get("persona") or {})
if display.role:
persona["role"] = display.role
if display.skills:
persona["skills"] = list(display.skills)
if display.constraints:
persona["constraints"] = list(display.constraints)
if display.background:
persona["background"] = display.background
normalized["persona"] = persona
return normalized