Files

116 lines
4.8 KiB
Python
Raw Permalink 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.
"""Seed the built-in ``cognitive-situation-map`` public skill.
认知态势图技能(cognitive-situation-map)此前只存在于各台机器的运行时
``skills/public/`` 目录里——该目录被 .gitignore 排除,也不随离线发版的
git 干净快照搬运,导致新机器部署后技能缺失。_verified_ 技能资产因此与
本模块同目录存放(``_cognitive_situation_seed_assets/skills/``),启动时
同步到运行时技能根目录(``skills/public/``)。部署只需更新 ``app`` 和
``packages``:每次启动会覆盖该内置技能的受管文件,但保留目标目录中
额外的用户文件;下线状态(extensions_config 里的 ``skills.<name>.enabled``)
不受影响;public 类技能在 extensions_config 缺省即启用。
技能目录只保留渲染时必须读取的 ``assets/runtime/index.html`` 模板。
样式、脚本、底图和国旗由 harness
``deerflow/html_runtime/assets/cognitive-situation-map/``(Gateway 静态
服务端)按需提供,不能再复制进沙箱技能视图;否则一次技能调用会搬运约
25 MB 的重复资源并阻塞后续模型调用。
"""
from __future__ import annotations
import logging
import shutil
from pathlib import Path
logger = logging.getLogger(__name__)
COGNITIVE_SITUATION_SKILL_NAMES: tuple[str, ...] = ("cognitive-situation-map",)
_ASSETS_DIR = Path(__file__).parent / "_cognitive_situation_seed_assets"
_LEGACY_RUNTIME_ENTRIES: tuple[str, ...] = ("app.js", "styles.css", "assets", "data")
def _prune_legacy_runtime_bundle(target: Path) -> int:
"""Remove only formerly package-managed runtime duplicates.
Earlier releases seeded a full browser runtime below the skill itself. The
Gateway now serves that runtime from the harness package, but ``copytree``
intentionally preserves extra target files. Prune these known legacy
paths before syncing so upgrading an existing deployment immediately drops
the expensive sandbox payload without touching user-authored files.
"""
runtime_dir = target / "assets" / "runtime"
removed = 0
for name in _LEGACY_RUNTIME_ENTRIES:
candidate = runtime_dir / name
if candidate.is_dir():
shutil.rmtree(candidate)
removed += 1
elif candidate.is_file() or candidate.is_symlink():
candidate.unlink()
removed += 1
return removed
def _seed_copy_ignore(source: Path):
"""Keep obsolete source-tree runtime copies out of the deployed skill.
This filter makes the deployment lightweight even when upgrading from a
source checkout that still contains a legacy bundle. The template itself
remains in ``assets/runtime/index.html`` because the deterministic renderer
reads it while composing the small output page.
"""
runtime_dir = (source / "assets" / "runtime").resolve()
def ignore(directory: str, names: list[str]) -> set[str]:
if Path(directory).resolve() == runtime_dir:
return set(names).intersection(_LEGACY_RUNTIME_ENTRIES)
return set()
return ignore
def ensure_cognitive_situation_skills() -> bool:
"""Synchronize every built-in public cognitive-situation skill into this deployment.
Idempotent and non-fatal: package-managed files are synchronized into an
existing target while unrelated target files remain intact. Any failure is
logged instead of blocking startup. Returns True when at least one skill
directory was created or synchronized.
"""
seeded = False
try:
from deerflow.skills.storage import get_or_new_skill_storage
public_dir = Path(get_or_new_skill_storage().get_skills_root_path()) / "public"
public_dir.mkdir(parents=True, exist_ok=True)
for skill_name in COGNITIVE_SITUATION_SKILL_NAMES:
source = _ASSETS_DIR / "skills" / skill_name
target = public_dir / skill_name
if not (source / "SKILL.md").is_file():
logger.error(
"Missing seed asset for cognitive-situation skill '%s': %s",
skill_name,
source,
)
continue
target_existed = target.exists()
removed = _prune_legacy_runtime_bundle(target) if target_existed else 0
shutil.copytree(source, target, dirs_exist_ok=True, ignore=_seed_copy_ignore(source))
logger.info(
"%s public cognitive-situation skill '%s'%s",
"Synchronized" if target_existed else "Seeded",
skill_name,
f" (removed {removed} legacy runtime entries)" if removed else "",
)
seeded = True
except Exception:
logger.exception("Failed to seed cognitive-situation public skills")
return seeded
__all__ = [
"COGNITIVE_SITUATION_SKILL_NAMES",
"ensure_cognitive_situation_skills",
]