feat: 增加技能参考和模板的创建、获取及保存功能

This commit is contained in:
piexlMax(奇淼 2026-02-02 18:06:11 +08:00
parent 52cd5e72ab
commit 670aff79cc
8 changed files with 216 additions and 29 deletions

View File

@ -125,6 +125,76 @@ func (s *SkillsApi) SaveResource(c *gin.Context) {
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateReference(c *gin.Context) {
var req request.SkillReferenceCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateReference(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建参考失败", zap.Error(err))
response.FailWithMessage("创建参考失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetReference(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetReference(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取参考失败", zap.Error(err))
response.FailWithMessage("读取参考失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveReference(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveReference(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存参考失败", zap.Error(err))
response.FailWithMessage("保存参考失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) CreateTemplate(c *gin.Context) {
var req request.SkillTemplateCreateRequest
_ = c.ShouldBindJSON(&req)
fileName, content, err := skillsService.CreateTemplate(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("创建模板失败", zap.Error(err))
response.FailWithMessage("创建模板失败", c)
return
}
response.OkWithDetailed(gin.H{"fileName": fileName, "content": content}, "创建成功", c)
}
func (s *SkillsApi) GetTemplate(c *gin.Context) {
var req request.SkillFileRequest
_ = c.ShouldBindJSON(&req)
content, err := skillsService.GetTemplate(c.Request.Context(), req)
if err != nil {
global.GVA_LOG.Error("读取模板失败", zap.Error(err))
response.FailWithMessage("读取模板失败", c)
return
}
response.OkWithDetailed(gin.H{"content": content}, "获取成功", c)
}
func (s *SkillsApi) SaveTemplate(c *gin.Context) {
var req request.SkillFileSaveRequest
_ = c.ShouldBindJSON(&req)
if err := skillsService.SaveTemplate(c.Request.Context(), req); err != nil {
global.GVA_LOG.Error("保存模板失败", zap.Error(err))
response.FailWithMessage("保存模板失败", c)
return
}
response.OkWithMessage("保存成功", c)
}
func (s *SkillsApi) GetGlobalConstraint(c *gin.Context) {
var req request.SkillToolRequest
_ = c.ShouldBindJSON(&req)

View File

@ -32,6 +32,18 @@ type SkillResourceCreateRequest struct {
FileName string `json:"fileName"`
}
type SkillReferenceCreateRequest struct {
Tool string `json:"tool"`
Skill string `json:"skill"`
FileName string `json:"fileName"`
}
type SkillTemplateCreateRequest struct {
Tool string `json:"tool"`
Skill string `json:"skill"`
FileName string `json:"fileName"`
}
type SkillFileRequest struct {
Tool string `json:"tool"`
Skill string `json:"skill"`

View File

@ -9,12 +9,14 @@ type SkillMeta struct {
}
type SkillDetail struct {
Tool string `json:"tool"`
Skill string `json:"skill"`
Meta SkillMeta `json:"meta"`
Markdown string `json:"markdown"`
Scripts []string `json:"scripts"`
Resources []string `json:"resources"`
Tool string `json:"tool"`
Skill string `json:"skill"`
Meta SkillMeta `json:"meta"`
Markdown string `json:"markdown"`
Scripts []string `json:"scripts"`
Resources []string `json:"resources"`
References []string `json:"references"`
Templates []string `json:"templates"`
}
type SkillTool struct {

View File

@ -17,6 +17,12 @@ func (s *SkillsRouter) InitSkillsRouter(Router *gin.RouterGroup) {
skillsRouter.POST("createResource", skillsApi.CreateResource)
skillsRouter.POST("getResource", skillsApi.GetResource)
skillsRouter.POST("saveResource", skillsApi.SaveResource)
skillsRouter.POST("createReference", skillsApi.CreateReference)
skillsRouter.POST("getReference", skillsApi.GetReference)
skillsRouter.POST("saveReference", skillsApi.SaveReference)
skillsRouter.POST("createTemplate", skillsApi.CreateTemplate)
skillsRouter.POST("getTemplate", skillsApi.GetTemplate)
skillsRouter.POST("saveTemplate", skillsApi.SaveTemplate)
skillsRouter.POST("getGlobalConstraint", skillsApi.GetGlobalConstraint)
skillsRouter.POST("saveGlobalConstraint", skillsApi.SaveGlobalConstraint)
}

View File

@ -43,6 +43,10 @@ const defaultSkillMarkdown = "## 技能用途\n请在这里描述技能的目标
const defaultResourceMarkdown = "# 资源说明\n请在这里补充资源内容。\n"
const defaultReferenceMarkdown = "# 参考资料\n请在这里补充参考资料内容。\n"
const defaultTemplateMarkdown = "# 模板\n请在这里补充模板内容。\n"
const defaultGlobalConstraintMarkdown = "# 全局约束\n请在这里补充该工具的统一约束与使用规范。\n"
type SkillsService struct{}
@ -113,6 +117,8 @@ func (s *SkillsService) Detail(_ context.Context, tool, skill string) (system.Sk
detail.Scripts = listFiles(filepath.Join(skillDir, "scripts"))
detail.Resources = listFiles(filepath.Join(skillDir, "resources"))
detail.References = listFiles(filepath.Join(skillDir, "references"))
detail.Templates = listFiles(filepath.Join(skillDir, "templates"))
return detail, nil
}
@ -190,29 +196,7 @@ func (s *SkillsService) SaveScript(_ context.Context, req request.SkillFileSaveR
}
func (s *SkillsService) CreateResource(_ context.Context, req request.SkillResourceCreateRequest) (string, string, error) {
if !isSafeName(req.Skill) {
return "", "", errors.New("技能名称不合法")
}
fileName, err := buildResourceFileName(req.FileName)
if err != nil {
return "", "", err
}
skillDir, err := s.ensureSkillDir(req.Tool, req.Skill)
if err != nil {
return "", "", err
}
filePath := filepath.Join(skillDir, "resources", fileName)
if _, err := os.Stat(filePath); err == nil {
return "", "", errors.New("资源已存在")
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return "", "", err
}
content := defaultResourceMarkdown
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
return "", "", err
}
return fileName, content, nil
return s.createMarkdownFile(req.Tool, req.Skill, "resources", req.FileName, defaultResourceMarkdown, "资源")
}
func (s *SkillsService) GetResource(_ context.Context, req request.SkillFileRequest) (string, error) {
@ -223,6 +207,30 @@ func (s *SkillsService) SaveResource(_ context.Context, req request.SkillFileSav
return s.writeSkillFile(req.Tool, req.Skill, "resources", req.FileName, req.Content)
}
func (s *SkillsService) CreateReference(_ context.Context, req request.SkillReferenceCreateRequest) (string, string, error) {
return s.createMarkdownFile(req.Tool, req.Skill, "references", req.FileName, defaultReferenceMarkdown, "参考")
}
func (s *SkillsService) GetReference(_ context.Context, req request.SkillFileRequest) (string, error) {
return s.readSkillFile(req.Tool, req.Skill, "references", req.FileName)
}
func (s *SkillsService) SaveReference(_ context.Context, req request.SkillFileSaveRequest) error {
return s.writeSkillFile(req.Tool, req.Skill, "references", req.FileName, req.Content)
}
func (s *SkillsService) CreateTemplate(_ context.Context, req request.SkillTemplateCreateRequest) (string, string, error) {
return s.createMarkdownFile(req.Tool, req.Skill, "templates", req.FileName, defaultTemplateMarkdown, "模板")
}
func (s *SkillsService) GetTemplate(_ context.Context, req request.SkillFileRequest) (string, error) {
return s.readSkillFile(req.Tool, req.Skill, "templates", req.FileName)
}
func (s *SkillsService) SaveTemplate(_ context.Context, req request.SkillFileSaveRequest) error {
return s.writeSkillFile(req.Tool, req.Skill, "templates", req.FileName, req.Content)
}
func (s *SkillsService) GetGlobalConstraint(_ context.Context, tool string) (string, bool, error) {
skillsDir, err := s.toolSkillsDir(tool)
if err != nil {
@ -309,6 +317,35 @@ func (s *SkillsService) ensureSkillDir(tool, skill string) (string, error) {
return skillDir, nil
}
func (s *SkillsService) createMarkdownFile(tool, skill, subDir, fileName, defaultContent, label string) (string, string, error) {
if !isSafeName(skill) {
return "", "", errors.New("技能名称不合法")
}
cleanName, err := buildResourceFileName(fileName)
if err != nil {
return "", "", err
}
skillDir, err := s.ensureSkillDir(tool, skill)
if err != nil {
return "", "", err
}
filePath := filepath.Join(skillDir, subDir, cleanName)
if _, err := os.Stat(filePath); err == nil {
if label == "" {
label = "文件"
}
return "", "", fmt.Errorf("%s已存在", label)
}
if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil {
return "", "", err
}
content := defaultContent
if err := os.WriteFile(filePath, []byte(content), 0644); err != nil {
return "", "", err
}
return cleanName, content, nil
}
func (s *SkillsService) readSkillFile(tool, skill, subDir, fileName string) (string, error) {
if !isSafeName(skill) {
return "", errors.New("技能名称不合法")

View File

@ -124,6 +124,12 @@ func (i *initApi) InitializeData(ctx context.Context) (context.Context, error) {
{ApiGroup: "skills", Method: "POST", Path: "/skills/createResource", Description: "创建技能资源"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/getResource", Description: "读取技能资源"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/saveResource", Description: "保存技能资源"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/createReference", Description: "创建技能参考"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/getReference", Description: "读取技能参考"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/saveReference", Description: "保存技能参考"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/createTemplate", Description: "创建技能模板"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/getTemplate", Description: "读取技能模板"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/saveTemplate", Description: "保存技能模板"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/getGlobalConstraint", Description: "读取全局约束"},
{ApiGroup: "skills", Method: "POST", Path: "/skills/saveGlobalConstraint", Description: "保存全局约束"},

View File

@ -126,6 +126,12 @@ func (i *initCasbin) InitializeData(ctx context.Context) (context.Context, error
{Ptype: "p", V0: "888", V1: "/skills/createResource", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/getResource", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/saveResource", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/createReference", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/getReference", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/saveReference", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/createTemplate", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/getTemplate", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/saveTemplate", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/getGlobalConstraint", V2: "POST"},
{Ptype: "p", V0: "888", V1: "/skills/saveGlobalConstraint", V2: "POST"},

View File

@ -79,6 +79,54 @@ export const saveSkillResource = (data) => {
})
}
export const createSkillReference = (data) => {
return service({
url: '/skills/createReference',
method: 'post',
data
})
}
export const getSkillReference = (data) => {
return service({
url: '/skills/getReference',
method: 'post',
data
})
}
export const saveSkillReference = (data) => {
return service({
url: '/skills/saveReference',
method: 'post',
data
})
}
export const createSkillTemplate = (data) => {
return service({
url: '/skills/createTemplate',
method: 'post',
data
})
}
export const getSkillTemplate = (data) => {
return service({
url: '/skills/getTemplate',
method: 'post',
data
})
}
export const saveSkillTemplate = (data) => {
return service({
url: '/skills/saveTemplate',
method: 'post',
data
})
}
export const getGlobalConstraint = (data) => {
return service({
url: '/skills/getGlobalConstraint',