51 lines
1.5 KiB
Python
51 lines
1.5 KiB
Python
"""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:
|
|
raw_content = self.loader.load_skill(name)
|
|
content = strip_frontmatter(raw_content).strip() if raw_content else ""
|
|
if not content:
|
|
continue
|
|
activated_skills.append(SkillContext(name=name, content=content))
|
|
|
|
return ResolvedSkillSet(activated_skills=activated_skills)
|