返回 DeepSeek-Reasonix
embed.go
1 // Package builtincontent holds shipped skill markdown that is embedded into the
2 // Reasonix binary. Bodies stay out of the system prompt until the skill is
3 // invoked; only the name+description index line is cache-stable.
4 package builtincontent
5
6 import (
7 "embed"
8 "fmt"
9 "io/fs"
10 "path"
11 "strings"
12
13 "reasonix/internal/frontmatter"
14 )
15
16 //go:embed reasonix-guide/SKILL.md
17 var files embed.FS
18
19 // SkillMarkdown is one embedded skill file after frontmatter split.
20 type SkillMarkdown struct {
21 Name string
22 Description string
23 RunAs string // "inline" | "subagent" (and cross-tool aliases handled by caller)
24 Context string
25 Agent string
26 Body string
27 Path string // stable embed path for diagnostics
28 Frontmatter map[string]string
29 }
30
31 // LoadReasonixGuide returns the shipped reasonix-guide skill markdown.
32 func LoadReasonixGuide() (SkillMarkdown, error) {
33 return loadSkill("reasonix-guide/SKILL.md")
34 }
35
36 // All loads every embedded SKILL.md under this package (currently one).
37 func All() ([]SkillMarkdown, error) {
38 var out []SkillMarkdown
39 err := fs.WalkDir(files, ".", func(p string, d fs.DirEntry, err error) error {
40 if err != nil {
41 return err
42 }
43 if d.IsDir() {
44 return nil
45 }
46 if !strings.EqualFold(path.Base(p), "SKILL.md") {
47 return nil
48 }
49 sk, err := loadSkill(p)
50 if err != nil {
51 return err
52 }
53 out = append(out, sk)
54 return nil
55 })
56 return out, err
57 }
58
59 func loadSkill(embedPath string) (SkillMarkdown, error) {
60 raw, err := files.ReadFile(embedPath)
61 if err != nil {
62 return SkillMarkdown{}, err
63 }
64 return ParseSkillMarkdown(embedPath, string(raw))
65 }
66
67 // ParseSkillMarkdown splits embedded (or test) skill markdown using the same
68 // frontmatter rules as on-disk skills. It does not expand references/scripts
69 // (embedded skills ship a single file).
70 func ParseSkillMarkdown(sourcePath, content string) (SkillMarkdown, error) {
71 content = strings.TrimPrefix(strings.ReplaceAll(content, "\r\n", "\n"), "\uFEFF")
72 fm, body := frontmatter.Split(content)
73 name := strings.TrimSpace(fm["name"])
74 if name == "" {
75 // Fall back to directory name: reasonix-guide/SKILL.md → reasonix-guide
76 dir := path.Dir(sourcePath)
77 if dir != "" && dir != "." {
78 name = path.Base(dir)
79 }
80 }
81 if name == "" {
82 return SkillMarkdown{}, fmt.Errorf("embedded skill %s: missing name", sourcePath)
83 }
84 return SkillMarkdown{
85 Name: name,
86 Description: strings.TrimSpace(fm["description"]),
87 RunAs: strings.TrimSpace(fm["runas"]),
88 Context: strings.TrimSpace(fm["context"]),
89 Agent: strings.TrimSpace(fm["agent"]),
90 Body: strings.TrimSpace(body),
91 Path: sourcePath,
92 Frontmatter: fm,
93 }, nil
94 }
95
95 lines GO