Files
deerflow-code/offline-backend-20260512/backend/app/gateway/routers/_agentfx_seed.py
T
董宏凯andCursor 52b9cbf707 feat: 新增 agentfx 任务深链与研判报告入库流程
支持 goPath=agentfx 的 iframe 嵌入问答、内置研判助手种子与报告导入协助卡,并完善深度研究流式报告能力。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-27 16:32:22 +08:00

102 lines
3.8 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Seeder for the built-in agentfx analyst agent and its import skill.
agentfx 任务深链(新系统 iframe 嵌入的智能体问答)固定使用内置智能体
``agentfx-analyst``:根据任务详情与用户输入搜集信息,生成 md 研判报告 +
结构化 ``task-reports.json``(14 类),总结后经前端「入库」协助卡或
``task-report-import`` 技能写入任务详情。
种子内容与 ``forced-research-responder`` 同一套模式:
- ``_agentfx_seed_assets/agentfx-analyst/{config.yaml, SOUL.md}`` → 复制到
``{DEER_FLOW_HOME}/agents/agentfx-analyst/``(目录存在则不动,尊重现场修改),
由启动流程的 ``_sync_legacy_agents`` upsert 进 ``agents`` 表(user_id IS NULL)。
- ``_agentfx_seed_assets/skills/task-report-import/`` → 复制到
``skills/public/task-report-import/``(``skills/`` 被 .gitignore 排除,同样
需要补建;public 类技能在 extensions_config 缺省即启用)。
必须在 ``_sync_legacy_agents`` **之前**调用。
"""
from __future__ import annotations
import logging
import shutil
from pathlib import Path
from deerflow.config.paths import get_paths
logger = logging.getLogger(__name__)
AGENTFX_AGENT_ID = "agentfx-analyst"
TASK_REPORT_IMPORT_SKILL_NAME = "task-report-import"
_ASSETS_DIR = Path(__file__).parent / "_agentfx_seed_assets"
_SEED_FILES: tuple[str, ...] = ("config.yaml", "SOUL.md")
def _ensure_agentfx_agent_dir() -> bool:
"""Create the built-in agent directory when missing; never overwrite it."""
try:
agent_dir = get_paths().agent_dir(AGENTFX_AGENT_ID)
if agent_dir.exists():
return False
src_dir = _ASSETS_DIR / AGENTFX_AGENT_ID
if not src_dir.is_dir():
logger.error(
"Missing seed assets for agent '%s' (expected at %s)",
AGENTFX_AGENT_ID,
src_dir,
)
return False
agent_dir.mkdir(parents=True, exist_ok=True)
for filename in _SEED_FILES:
src = src_dir / filename
if src.exists():
(agent_dir / filename).write_bytes(src.read_bytes())
logger.info("Seeded built-in agent '%s'", AGENTFX_AGENT_ID)
return True
except Exception:
logger.exception("Failed to seed built-in agent '%s'", AGENTFX_AGENT_ID)
return False
def _ensure_task_report_import_skill() -> bool:
"""Seed the task-report-import skill into ``skills/public/`` when missing."""
try:
src_dir = _ASSETS_DIR / "skills" / TASK_REPORT_IMPORT_SKILL_NAME
if not (src_dir / "SKILL.md").exists():
logger.error(
"Missing seed assets for skill '%s' (expected at %s)",
TASK_REPORT_IMPORT_SKILL_NAME,
src_dir,
)
return False
from deerflow.skills.storage import get_or_new_skill_storage
public_dir = Path(get_or_new_skill_storage().get_skills_root_path()) / "public"
skill_dir = public_dir / TASK_REPORT_IMPORT_SKILL_NAME
if skill_dir.exists():
return False
# 技能带 scripts/ 子目录,整目录复制(字节级,保留原样)。
shutil.copytree(src_dir, skill_dir)
logger.info("Seeded built-in skill '%s'", TASK_REPORT_IMPORT_SKILL_NAME)
return True
except Exception:
logger.exception("Failed to seed built-in skill '%s'", TASK_REPORT_IMPORT_SKILL_NAME)
return False
def ensure_agentfx_agent() -> bool:
"""Seed the agentfx analyst agent + its import skill (idempotent, non-fatal).
Returns True if the agent directory was just created.
"""
_ensure_task_report_import_skill()
return _ensure_agentfx_agent_dir()
__all__ = ["AGENTFX_AGENT_ID", "TASK_REPORT_IMPORT_SKILL_NAME", "ensure_agentfx_agent"]