fix: 模块技能全文加载剥离 frontmatter,对齐分层导入规范

模块技能作为「项目模块」scope 注入时,目录层只放名字+描述,
全文层(load_skill)剥离 frontmatter 只返回正文,与 skill_loader.
to_prompt_block 行为一致。
This commit is contained in:
ymq 2026-08-23 21:24:47 +08:00
parent 7ede8f4d7a
commit 32cd8c2e8a

View File

@ -649,7 +649,9 @@ def _collect_module_skills(workspace_dir):
模块仓库自带 skill/SKILL.md(架构/数据模型/挂载函数/坑位),但这些不进 skill_loader 模块仓库自带 skill/SKILL.md(架构/数据模型/挂载函数/坑位),但这些不进 skill_loader
的静态文件树,导致项目角色不知道模块怎么用。这里运行时扫描,作为「项目模块」scope 的静态文件树,导致项目角色不知道模块怎么用。这里运行时扫描,作为「项目模块」scope
注入技能目录 + 支持 load_skill 加载全文。返回 [{name, description, content, path}]。 注入技能目录 + 支持 load_skill 加载全文。返回 [{name, description, body, path}]。
其中 body 是剥离 frontmatter 后的正文(对齐 skill_loader.to_prompt_block 的分层导入规范:
目录层只放名字+描述,全文层剥离 frontmatter 只返回正文)。
""" """
modules = [] modules = []
repos_dir = os.path.join(workspace_dir, 'repos') repos_dir = os.path.join(workspace_dir, 'repos')
@ -667,8 +669,14 @@ def _collect_module_skills(workspace_dir):
fm = _parse_skill_frontmatter(content) fm = _parse_skill_frontmatter(content)
name = (fm.get('name') or entry).strip() name = (fm.get('name') or entry).strip()
description = (fm.get('description') or '').strip() description = (fm.get('description') or '').strip()
# 剥离 frontmatter,只保留正文(对齐 skill_loader.to_prompt_block 行为)
body = content.strip()
if body.startswith("---"):
end = body.find("---", 3)
if end != -1:
body = body[end + 3:].strip()
if not description: if not description:
for line in content.split("\n"): for line in body.split("\n"):
line = line.strip() line = line.strip()
if line and not line.startswith("#") and not line.startswith("---"): if line and not line.startswith("#") and not line.startswith("---"):
description = line[:200] description = line[:200]
@ -676,7 +684,7 @@ def _collect_module_skills(workspace_dir):
modules.append({ modules.append({
"name": name, "name": name,
"description": description, "description": description,
"content": content, "body": body,
"path": skill_file, "path": skill_file,
"repo": entry, "repo": entry,
}) })
@ -1228,12 +1236,13 @@ async def _load_skill_by_name(sor, project_id, role, org_id, name, file_path=Non
merged = loader.get_merged(pipeline_id=pid, role=role, merged = loader.get_merged(pipeline_id=pid, role=role,
project_id=project_id, org_id=org_id or '0') project_id=project_id, org_id=org_id or '0')
if name not in merged: if name not in merged:
# 项目模块技能(workspace repos/*/skill/SKILL.md)不在 skill_loader 静态树里,运行时补查 # 项目模块技能(workspace repos/*/skill/SKILL.md)不在 skill_loader 静态树里,运行时补查。
# 全文层对齐 skill_loader.to_prompt_block:剥离 frontmatter 只返回正文(body)。
try: try:
ws = await _get_workspace_dir(sor, project_id) ws = await _get_workspace_dir(sor, project_id)
for m in _collect_module_skills(ws): for m in _collect_module_skills(ws):
if m['name'] == name or m['repo'] == name: if m['name'] == name or m['repo'] == name:
return f"## [项目模块] {m['name']}\n{m['description']}\n\n{m['content']}" return f"## [项目模块] {m['name']}\n{m['description']}\n\n{m['body']}"
except Exception: except Exception:
pass pass
names = ", ".join(sorted(merged.keys())) or "(无可用技能)" names = ", ".join(sorted(merged.keys())) or "(无可用技能)"