feat: 新增数字员工管理页面与工作台首页重构
后端优化 agent 资产种子初始化和常量配置,前端新增数字员工 视图和调度对话框组件,重构个人工作台首页布局和洞察面板, 完善审计页面数字员工详情和运行时模型,优化侧边栏导航和图 标配置,新增工作台摘要和工作台数据模块,补充单元测试。
This commit is contained in:
@@ -636,7 +636,7 @@ def list_agent_asset_versions(
|
||||
response_model=AgentAssetVersionRead,
|
||||
status_code=status.HTTP_201_CREATED,
|
||||
summary="创建资产版本",
|
||||
description="为指定资产创建新版本;规则使用 Markdown,其他资产使用 JSON 快照。",
|
||||
description="为指定资产创建新版本;规则和任务源文件可使用 Markdown,技能与 MCP 使用 JSON 快照。",
|
||||
responses={
|
||||
status.HTTP_400_BAD_REQUEST: {
|
||||
"model": ErrorResponse,
|
||||
|
||||
@@ -501,10 +501,10 @@ class AgentAssetService(
|
||||
):
|
||||
raise ValueError("规则资产版本内容必须使用 markdown。")
|
||||
if (
|
||||
asset.asset_type != AgentAssetType.RULE.value
|
||||
asset.asset_type not in {AgentAssetType.RULE.value, AgentAssetType.TASK.value}
|
||||
and payload.content_type != AgentAssetContentType.JSON
|
||||
):
|
||||
raise ValueError("技能、MCP、任务资产版本内容必须使用 json。")
|
||||
raise ValueError("技能、MCP 资产版本内容必须使用 json。")
|
||||
if payload.content_type == AgentAssetContentType.MARKDOWN and not isinstance(
|
||||
payload.content, str
|
||||
):
|
||||
|
||||
@@ -27,12 +27,40 @@ from app.services.agent_foundation_constants import (
|
||||
COMPANY_COMMUNICATION_RULE_VERSION,
|
||||
COMPANY_TRAVEL_RULE_SCENARIO_JSON,
|
||||
COMPANY_TRAVEL_RULE_VERSION,
|
||||
DIGITAL_EMPLOYEE_SKILL_CATEGORIES,
|
||||
DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP,
|
||||
)
|
||||
|
||||
logger = get_logger("app.services.agent_foundation")
|
||||
|
||||
|
||||
class AgentFoundationAssetSeedMixin:
|
||||
def _digital_employee_task_config(self, code: str, cron: str) -> dict[str, object]:
|
||||
return {
|
||||
"cron": cron,
|
||||
"agent": AgentName.HERMES.value,
|
||||
"skill_category": DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP.get(code, "整理"),
|
||||
"skill_category_options": list(DIGITAL_EMPLOYEE_SKILL_CATEGORIES),
|
||||
}
|
||||
|
||||
def _digital_employee_task_content(
|
||||
self,
|
||||
code: str,
|
||||
task_type: str,
|
||||
schedule: str,
|
||||
**extra: object,
|
||||
) -> str:
|
||||
return self._json_content(
|
||||
{
|
||||
"task_type": task_type,
|
||||
"skill_category": DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP.get(code, "整理"),
|
||||
"skill_category_options": list(DIGITAL_EMPLOYEE_SKILL_CATEGORIES),
|
||||
"schedule": schedule,
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
**extra,
|
||||
}
|
||||
)
|
||||
|
||||
def _seed_agent_assets(self) -> None:
|
||||
|
||||
existing_codes = set(self.db.scalars(select(AgentAsset.code)).all())
|
||||
@@ -239,7 +267,7 @@ class AgentFoundationAssetSeedMixin:
|
||||
current_version="v1.0.0",
|
||||
published_version="v1.0.0",
|
||||
working_version="v1.0.0",
|
||||
config_json={"cron": "0 9 * * *", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.daily_risk_scan", "0 9 * * *"),
|
||||
)
|
||||
|
||||
ar_summary_task = AgentAsset(
|
||||
@@ -255,7 +283,7 @@ class AgentFoundationAssetSeedMixin:
|
||||
current_version="v1.0.0",
|
||||
published_version="v1.0.0",
|
||||
working_version="v1.0.0",
|
||||
config_json={"cron": "0 10 * * 1", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.weekly_ar_summary", "0 10 * * 1"),
|
||||
)
|
||||
|
||||
rule_digest_task = AgentAsset(
|
||||
@@ -271,7 +299,7 @@ class AgentFoundationAssetSeedMixin:
|
||||
current_version="v1.0.0",
|
||||
published_version="v1.0.0",
|
||||
working_version="v1.0.0",
|
||||
config_json={"cron": "0 18 * * *", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.rule_review_digest", "0 18 * * *"),
|
||||
)
|
||||
|
||||
knowledge_index_task = AgentAsset(
|
||||
@@ -287,7 +315,7 @@ class AgentFoundationAssetSeedMixin:
|
||||
current_version="v1.0.0",
|
||||
published_version="v1.0.0",
|
||||
working_version="v1.0.0",
|
||||
config_json={"cron": "0 0 * * *", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.knowledge_index_sync", "0 0 * * *"),
|
||||
)
|
||||
|
||||
self.db.add_all(
|
||||
@@ -467,12 +495,10 @@ class AgentFoundationAssetSeedMixin:
|
||||
AgentAssetVersion(
|
||||
asset=task_asset,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "daily_risk_scan",
|
||||
"schedule": "0 9 * * *",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.daily_risk_scan",
|
||||
"daily_risk_scan",
|
||||
"0 9 * * *",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化任务快照。",
|
||||
@@ -481,12 +507,10 @@ class AgentFoundationAssetSeedMixin:
|
||||
AgentAssetVersion(
|
||||
asset=ar_summary_task,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "weekly_ar_summary",
|
||||
"schedule": "0 10 * * 1",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.weekly_ar_summary",
|
||||
"weekly_ar_summary",
|
||||
"0 10 * * 1",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化应收账龄汇总任务。",
|
||||
@@ -495,12 +519,10 @@ class AgentFoundationAssetSeedMixin:
|
||||
AgentAssetVersion(
|
||||
asset=rule_digest_task,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "rule_review_digest",
|
||||
"schedule": "0 18 * * *",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.rule_review_digest",
|
||||
"rule_review_digest",
|
||||
"0 18 * * *",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化规则待审摘要任务。",
|
||||
@@ -509,15 +531,13 @@ class AgentFoundationAssetSeedMixin:
|
||||
AgentAssetVersion(
|
||||
asset=knowledge_index_task,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "knowledge_index_sync",
|
||||
"schedule": "0 0 * * *",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
"folder": "报销制度",
|
||||
"changed_only": True,
|
||||
"index_engine": "lightrag",
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.knowledge_index_sync",
|
||||
"knowledge_index_sync",
|
||||
"0 0 * * *",
|
||||
folder="报销制度",
|
||||
changed_only=True,
|
||||
index_engine="lightrag",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化制度知识与规则草稿形成任务。",
|
||||
|
||||
@@ -9,7 +9,6 @@ from app.core.agent_enums import (
|
||||
AgentAssetDomain,
|
||||
AgentAssetStatus,
|
||||
AgentAssetType,
|
||||
AgentName,
|
||||
AgentReviewStatus,
|
||||
)
|
||||
from app.core.logging import get_logger
|
||||
@@ -27,17 +26,46 @@ from app.services.agent_foundation_constants import (
|
||||
COMPANY_COMMUNICATION_RULE_VERSION,
|
||||
COMPANY_TRAVEL_RULE_SCENARIO_JSON,
|
||||
COMPANY_TRAVEL_RULE_VERSION,
|
||||
DIGITAL_EMPLOYEE_SKILL_CATEGORIES,
|
||||
DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP,
|
||||
)
|
||||
|
||||
logger = get_logger("app.services.agent_foundation")
|
||||
|
||||
|
||||
class AgentFoundationAssetTopUpMixin:
|
||||
def _sync_digital_employee_skill_categories(self) -> None:
|
||||
category_options = list(DIGITAL_EMPLOYEE_SKILL_CATEGORIES)
|
||||
has_changes = False
|
||||
|
||||
for code, category in DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP.items():
|
||||
asset = self.db.scalar(select(AgentAsset).where(AgentAsset.code == code))
|
||||
if asset is None:
|
||||
continue
|
||||
|
||||
config_json = dict(asset.config_json or {})
|
||||
changed = False
|
||||
if config_json.get("skill_category") != category:
|
||||
config_json["skill_category"] = category
|
||||
changed = True
|
||||
if config_json.get("skill_category_options") != category_options:
|
||||
config_json["skill_category_options"] = category_options
|
||||
changed = True
|
||||
|
||||
if changed:
|
||||
asset.config_json = config_json
|
||||
self.db.add(asset)
|
||||
has_changes = True
|
||||
|
||||
if has_changes:
|
||||
self.db.commit()
|
||||
|
||||
def _top_up_agent_assets(self, existing_codes: set[str]) -> None:
|
||||
|
||||
self._remove_legacy_rule_assets()
|
||||
|
||||
existing_codes = set(self.db.scalars(select(AgentAsset.code)).all())
|
||||
self._sync_digital_employee_skill_categories()
|
||||
|
||||
attachment_rule = self.db.scalar(
|
||||
select(AgentAsset).where(AgentAsset.code == ATTACHMENT_RULE_ASSET_CODE)
|
||||
@@ -557,18 +585,16 @@ class AgentFoundationAssetTopUpMixin:
|
||||
reviewer="顾承宇",
|
||||
status=AgentAssetStatus.ACTIVE.value,
|
||||
current_version="v1.0.0",
|
||||
config_json={"cron": "0 10 * * 1", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.weekly_ar_summary", "0 10 * * 1"),
|
||||
)
|
||||
|
||||
self._ensure_asset_version(
|
||||
asset,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "weekly_ar_summary",
|
||||
"schedule": "0 10 * * 1",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.weekly_ar_summary",
|
||||
"weekly_ar_summary",
|
||||
"0 10 * * 1",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化应收账龄汇总任务。",
|
||||
@@ -588,18 +614,16 @@ class AgentFoundationAssetTopUpMixin:
|
||||
reviewer="顾承宇",
|
||||
status=AgentAssetStatus.ACTIVE.value,
|
||||
current_version="v1.0.0",
|
||||
config_json={"cron": "0 18 * * *", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.rule_review_digest", "0 18 * * *"),
|
||||
)
|
||||
|
||||
self._ensure_asset_version(
|
||||
asset,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "rule_review_digest",
|
||||
"schedule": "0 18 * * *",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.rule_review_digest",
|
||||
"rule_review_digest",
|
||||
"0 18 * * *",
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化规则待审摘要任务。",
|
||||
@@ -619,20 +643,18 @@ class AgentFoundationAssetTopUpMixin:
|
||||
reviewer="顾承宇",
|
||||
status=AgentAssetStatus.ACTIVE.value,
|
||||
current_version="v1.0.0",
|
||||
config_json={"cron": "0 0 * * *", "agent": AgentName.HERMES.value},
|
||||
config_json=self._digital_employee_task_config("task.hermes.knowledge_index_sync", "0 0 * * *"),
|
||||
)
|
||||
|
||||
self._ensure_asset_version(
|
||||
asset,
|
||||
version="v1.0.0",
|
||||
content=self._json_content(
|
||||
{
|
||||
"task_type": "knowledge_index_sync",
|
||||
"schedule": "0 0 * * *",
|
||||
"target_agent": AgentName.HERMES.value,
|
||||
"folder": "报销制度",
|
||||
"changed_only": True,
|
||||
}
|
||||
content=self._digital_employee_task_content(
|
||||
"task.hermes.knowledge_index_sync",
|
||||
"knowledge_index_sync",
|
||||
"0 0 * * *",
|
||||
folder="报销制度",
|
||||
changed_only=True,
|
||||
),
|
||||
content_type=AgentAssetContentType.JSON.value,
|
||||
change_note="初始化制度知识与规则草稿形成任务。",
|
||||
|
||||
@@ -86,6 +86,22 @@ COMPANY_TRAVEL_RULE_SCENARIO_JSON = ("差旅费",)
|
||||
|
||||
COMPANY_COMMUNICATION_RULE_SCENARIO_JSON = ("通信费",)
|
||||
|
||||
DIGITAL_EMPLOYEE_SKILL_CATEGORIES = ("积累", "升级", "整理", "评估")
|
||||
|
||||
DIGITAL_EMPLOYEE_TASK_CATEGORY_MAP = {
|
||||
|
||||
"task.hermes.daily_risk_scan": "评估",
|
||||
|
||||
"task.hermes.weekly_ar_summary": "整理",
|
||||
|
||||
"task.hermes.rule_review_digest": "升级",
|
||||
|
||||
"task.hermes.knowledge_index_sync": "积累",
|
||||
|
||||
"task.hermes.llm_wiki_rule_formation": "积累",
|
||||
|
||||
}
|
||||
|
||||
ATTACHMENT_RULE_RUNTIME_CONFIG = {
|
||||
|
||||
"kind": "policy_rule_draft",
|
||||
|
||||
Reference in New Issue
Block a user