"""Runtime skill resolver。 这层负责回答一个运行时问题: “这一次调用,哪些 skill 要被激活,并以什么形式注入上下文?” 第一版保持保守,只综合三类来源: 1. `always` skills 不在这里做复杂的语义匹配或自动推荐。 """ from __future__ import annotations from dataclasses import dataclass, field from beaver.engine.context import SkillContext from beaver.skills.catalog.loader import SkillsLoader from beaver.skills.catalog.utils import strip_frontmatter @dataclass(slots=True) class ResolvedSkillSet: """一次运行最终解析出的 skills 结果。""" activated_skills: list[SkillContext] = field(default_factory=list) class RuntimeSkillResolver: """把 profile/request 转成当前轮次真正激活的 skill 集合。""" def __init__(self, loader: SkillsLoader) -> None: self.loader = loader def resolve( self, ) -> ResolvedSkillSet: selected: list[str] = [] for name in self.loader.get_always_skills(): if name not in selected: selected.append(name) activated_skills: list[SkillContext] = [] for name in selected: record = self.loader.get_skill_record(name) raw_content = self.loader.load_published_skill(name) content = strip_frontmatter(raw_content).strip() if raw_content else "" if not content: continue activated_skills.append( SkillContext( name=name, content=content, version=record.version if record is not None else "legacy", content_hash=(record.content_hash if record is not None and record.content_hash else ""), activation_reason="always_skill", tool_hints=list(record.tool_hints) if record is not None else [], ) ) return ResolvedSkillSet(activated_skills=activated_skills)