feat: 完善标准 Skill 包底座

- 标准化 SKILL.md、资源模型、校验规则与安全限额

- 支持流式内容存储和单、多 Skill ZIP 双向编解码
This commit is contained in:
2026-07-27 18:53:24 +08:00
parent 6fa93bd671
commit c48d9a9da6
53 changed files with 7809 additions and 666 deletions

View File

@@ -2,6 +2,8 @@ package com.easyagents.skill.factory;
import com.easyagents.skill.model.*;
import com.easyagents.skill.util.SkillFrontmatter;
import com.easyagents.skill.util.SkillResources;
import com.easyagents.skill.validation.defaults.DefaultSkillValidator;
import java.util.List;
import java.util.Map;
@@ -25,6 +27,49 @@ public final class SkillFactory {
return create(id, skillContent, null, null, null);
}
/**
* 基于 SKILL.md 内容创建并严格校验正式标准 Skill。
*
* @param id Skill ID
* @param skillContent SKILL.md 原始内容
* @return 通过正式标准校验的 Skill 聚合
*/
public static Skill createStrict(String id, String skillContent) {
Skill skill = create(id, skillContent);
new DefaultSkillValidator().validate(skill);
return skill;
}
/**
* 基于 SKILL.md 内容和通用资源创建 Skill。
*
* @param id 仓储 ID可为空
* @param skillContent SKILL.md 原始内容
* @param resources 通用资源列表
* @return Skill 聚合
*/
public static Skill createWithResources(String id, String skillContent, List<SkillResource> resources) {
Skill skill = create(id, skillContent);
skill.setResources(resources);
SkillResources.refreshLegacyViews(skill);
return skill;
}
/**
* 基于 SKILL.md 和通用资源创建并严格校验正式标准 Skill。
*
* @param id 仓储 ID可为空
* @param skillContent SKILL.md 原始内容
* @param resources 通用资源列表
* @return 通过正式标准校验的 Skill 聚合
*/
public static Skill createWithResourcesStrict(String id, String skillContent,
List<SkillResource> resources) {
Skill skill = createWithResources(id, skillContent, resources);
new DefaultSkillValidator().validate(skill);
return skill;
}
/**
* 基于 SKILL.md 内容和资源列表创建 Skill。
*
@@ -37,16 +82,29 @@ public final class SkillFactory {
*/
public static Skill create(String id, String skillContent, List<SkillReference> references,
List<SkillScript> scripts, List<SkillAsset> assets) {
Map<String, Object> values = SkillFrontmatter.parse(skillContent);
SkillDocument document = SkillFrontmatter.parseDocument(skillContent);
Map<String, Object> values = document.getFrontmatter().getValues();
String name = requiredScalar(values, "name");
String description = requiredScalar(values, "description");
Skill skill = new Skill();
skill.setId(id);
skill.setName(values.get("name").toString());
skill.setDescription(values.get("description").toString());
skill.setName(name);
skill.setDescription(description);
skill.setMetadata(new SkillMetadata(values));
skill.setSkillContent(skillContent);
skill.setDocument(document);
skill.setReferences(references);
skill.setScripts(scripts);
skill.setAssets(assets);
skill.setResources(SkillResources.canonicalResources(skill));
return skill;
}
private static String requiredScalar(Map<String, Object> values, String key) {
Object value = values.get(key);
if (!(value instanceof String text) || text.isBlank()) {
throw new com.easyagents.skill.exception.SkillValidationException(
"SKILL.md frontmatter " + key + " must be a non-blank string.");
}
return text;
}
}