deerflow-code/offline-backend-20260512/backend/app/gateway/routers/_deep_research_seed.py
2026-09-07 18:24:55 +08:00

79 lines
2.8 KiB
Python

"""深度研究「收集员」内置 agent 的启动补建 seeder。
与 ``_ai_writing_seed.py`` / ``_roundtable_seed.py`` 完全同构:资源文件
(``_deep_research_seed_assets/deep-research-collector/``)是发布默认值的
唯一可信源,seeder 只在 ``.deer-flow/agents/deep-research-collector/``
目录缺失时字节级复制,**绝不覆盖**已存在目录(尊重 admin 在智能体管理页
的现场修改)。线上调优 SOUL 后请把改动写回资源文件,否则新机器补建出来
的还是旧版。
调用点:启动 lifespan(``app/gateway/app.py``),必须在 ``_sync_legacy_agents``
**之前**——后者会把目录 upsert 进 agents 表(`user_id IS NULL` 的内置
agent),所有用户即可在深度研究页使用。
"""
from __future__ import annotations
import logging
from pathlib import Path
from deerflow.config.paths import get_paths
logger = logging.getLogger(__name__)
DEEP_RESEARCH_COLLECTOR_AGENT_ID = "deep-research-collector"
_ASSETS_DIR = Path(__file__).parent / "_deep_research_seed_assets"
_SEED_FILES: tuple[str, ...] = ("config.yaml", "SOUL.md")
def _ensure_one(agent_id: str) -> bool:
"""Copy the verified SOUL.md + config.yaml into ``.deer-flow/agents/<id>/``
if that directory is missing.
Returns True if the files were just created, False if the directory already
existed (never overwrite — respect local edits) or the seed assets are
missing.
"""
agent_dir = get_paths().agent_dir(agent_id)
if agent_dir.exists():
return False
src_dir = _ASSETS_DIR / agent_id
if not src_dir.is_dir():
logger.error(
"Missing seed assets for deep-research agent '%s' (expected at %s)",
agent_id,
src_dir,
)
return False
agent_dir.mkdir(parents=True, exist_ok=True)
for fname in _SEED_FILES:
src = src_dir / fname
if src.exists():
(agent_dir / fname).write_bytes(src.read_bytes())
return True
def ensure_deep_research_collector_agent() -> list[str]:
"""Seed the deep-research collector agent if its on-disk directory is
missing. Idempotent — fast no-op when it exists.
Returns the list of agent ids just created (empty when nothing needed
seeding). Errors are logged but never raised — a seed failure must not
block startup.
"""
created: list[str] = []
try:
if _ensure_one(DEEP_RESEARCH_COLLECTOR_AGENT_ID):
created.append(DEEP_RESEARCH_COLLECTOR_AGENT_ID)
except Exception:
logger.exception("Failed to seed deep-research collector agent")
if created:
logger.info("Seeded missing deep-research collector agent: %s", ", ".join(created))
return created
__all__ = ["DEEP_RESEARCH_COLLECTOR_AGENT_ID", "ensure_deep_research_collector_agent"]