Skip to content

Commit ddb8f75

Browse files
chore
1 parent 8bf1d61 commit ddb8f75

File tree

5 files changed

+288
-265
lines changed

5 files changed

+288
-265
lines changed

adk/middlewares/skill/local.go

Lines changed: 37 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -65,19 +65,40 @@ func NewLocalBackend(config *LocalBackendConfig) (*LocalBackend, error) {
6565
}, nil
6666
}
6767

68-
// skillFrontmatter represents the YAML frontmatter in a SKILL.md file.
69-
type skillFrontmatter struct {
70-
Name string `yaml:"name"`
71-
Description string `yaml:"description"`
72-
License *string `yaml:"license"`
73-
Compatibility *string `yaml:"compatibility"`
74-
Metadata map[string]any `yaml:"metadata"`
75-
AllowedTools []string `yaml:"allowed-tools"`
76-
}
77-
7868
// List returns all skills from the local filesystem.
7969
// It scans subdirectories of baseDir for SKILL.md files and parses them as skills.
80-
func (b *LocalBackend) List(ctx context.Context) ([]Skill, error) {
70+
func (b *LocalBackend) List(ctx context.Context) ([]FrontMatter, error) {
71+
skills, err := b.list(ctx)
72+
if err != nil {
73+
return nil, fmt.Errorf("failed to list skills: %w", err)
74+
}
75+
76+
matters := make([]FrontMatter, 0, len(skills))
77+
for _, skill := range skills {
78+
matters = append(matters, skill.FrontMatter)
79+
}
80+
81+
return matters, nil
82+
}
83+
84+
// Get returns a skill by name from the local filesystem.
85+
// It searches subdirectories for a SKILL.md file with matching name.
86+
func (b *LocalBackend) Get(ctx context.Context, name string) (Skill, error) {
87+
skills, err := b.list(ctx)
88+
if err != nil {
89+
return Skill{}, fmt.Errorf("failed to list skills: %w", err)
90+
}
91+
92+
for _, skill := range skills {
93+
if skill.Name == name {
94+
return skill, nil
95+
}
96+
}
97+
98+
return Skill{}, fmt.Errorf("skill not found: %s", name)
99+
}
100+
101+
func (b *LocalBackend) list(ctx context.Context) ([]Skill, error) {
81102
var skills []Skill
82103

83104
entries, err := os.ReadDir(b.baseDir)
@@ -109,23 +130,6 @@ func (b *LocalBackend) List(ctx context.Context) ([]Skill, error) {
109130
return skills, nil
110131
}
111132

112-
// Get returns a skill by name from the local filesystem.
113-
// It searches subdirectories for a SKILL.md file with matching name.
114-
func (b *LocalBackend) Get(ctx context.Context, name string) (Skill, error) {
115-
skills, err := b.List(ctx)
116-
if err != nil {
117-
return Skill{}, fmt.Errorf("failed to list skills: %w", err)
118-
}
119-
120-
for _, skill := range skills {
121-
if skill.Name == name {
122-
return skill, nil
123-
}
124-
}
125-
126-
return Skill{}, fmt.Errorf("skill not found: %s", name)
127-
}
128-
129133
// loadSkillFromFile loads a skill from a SKILL.md file.
130134
// The file format is:
131135
//
@@ -145,7 +149,7 @@ func (b *LocalBackend) loadSkillFromFile(path string) (Skill, error) {
145149
return Skill{}, fmt.Errorf("failed to parse frontmatter: %w", err)
146150
}
147151

148-
var fm skillFrontmatter
152+
var fm FrontMatter
149153
if err = yaml.Unmarshal([]byte(frontmatter), &fm); err != nil {
150154
return Skill{}, fmt.Errorf("failed to unmarshal frontmatter: %w", err)
151155
}
@@ -157,12 +161,10 @@ func (b *LocalBackend) loadSkillFromFile(path string) (Skill, error) {
157161
}
158162

159163
return Skill{
160-
Name: fm.Name,
161-
Description: fm.Description,
162-
License: fm.License,
163-
Compatibility: fm.Compatibility,
164-
Metadata: fm.Metadata,
165-
AllowedTools: fm.AllowedTools,
164+
FrontMatter: FrontMatter{
165+
Name: fm.Name,
166+
Description: fm.Description,
167+
},
166168
Content: strings.TrimSpace(content),
167169
BaseDirectory: absDir,
168170
}, nil

adk/middlewares/skill/local_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,6 @@ This is the skill content.`), 0644))
162162
require.Len(t, skills, 1)
163163
assert.Equal(t, "pdf-processing", skills[0].Name)
164164
assert.Equal(t, "Extract text and tables from PDF files, fill forms, merge documents.", skills[0].Description)
165-
assert.Equal(t, "Apache-2.0", *skills[0].License)
166-
assert.Equal(t, map[string]any{"author": "example-org", "version": "1.0"}, skills[0].Metadata)
167-
assert.Equal(t, "This is the skill content.", skills[0].Content)
168-
assert.Equal(t, skillDir, skills[0].BaseDirectory)
169165
})
170166

171167
t.Run("multiple skill directories returns all skills", func(t *testing.T) {

adk/middlewares/skill/prompt.go

Lines changed: 110 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,71 @@
1717
package skill
1818

1919
const (
20-
skillToolDescriptionBase = `Execute a skill within the main conversation
20+
systemPrompt = `
21+
# Skills System
22+
23+
**How to Use Skills (Progressive Disclosure):**
24+
25+
Skills follow a **progressive disclosure** pattern - you see their name and description above, but only read full instructions when needed:
26+
27+
1. **Recognize when a skill applies**: Check if the user's task matches a skill's description
28+
2. **Read the skill's full instructions**: Use the '{tool_name}' tool to load skill
29+
3. **Follow the skill's instructions**: tool result contains step-by-step workflows, best practices, and examples
30+
4. **Access supporting files**: Skills may include helper scripts, configs, or reference docs - use absolute paths
31+
32+
**When to Use Skills:**
33+
- User's request matches a skill's domain (e.g., "research X" -> web-research skill)
34+
- You need specialized knowledge or structured workflows
35+
- A skill provides proven patterns for complex tasks
36+
37+
**Executing Skill Scripts:**
38+
Skills may contain Python scripts or other executable files. Always use absolute paths.
39+
40+
**Example Workflow:**
41+
42+
User: "Can you research the latest developments in quantum computing?"
43+
44+
1. Check available skills -> See "web-research" skill
45+
2. Call '{tool_name}' tool to read the full skill instructions
46+
3. Follow the skill's research workflow (search -> organize -> synthesize)
47+
4. Use any helper scripts with absolute paths
48+
49+
Remember: Skills make you more capable and consistent. When in doubt, check if a skill exists for the task!
50+
`
51+
52+
systemPromptChinese = `
53+
# 技能系统
54+
55+
**如何使用技能(渐进式展示):**
56+
57+
技能遵循**渐进式展示**模式 - 你可以在上方看到技能的名称和描述,但只在需要时才阅读完整说明:
58+
59+
1. **识别技能适用场景**:检查用户的任务是否匹配某个技能的描述
60+
2. **阅读技能的完整说明**:使用 '{tool_name}' 工具加载 skill
61+
3. **遵循技能说明操作**:工具结果包含逐步工作流程、最佳实践和示例
62+
4. **访问支持文件**:技能可能包含辅助脚本、配置或参考文档 - 使用绝对路径访问
63+
64+
**何时使用技能:**
65+
- 用户请求匹配某个技能的领域(例如"研究 X" -> web-research 技能)
66+
- 你需要专业知识或结构化工作流程
67+
- 某个技能为复杂任务提供了经过验证的模式
68+
69+
**执行技能脚本:**
70+
技能可能包含 Python 脚本或其他可执行文件。始终使用绝对路径。
71+
72+
**示例工作流程:**
73+
74+
用户:"你能研究一下量子计算的最新发展吗?"
75+
76+
1. 检查可用技能 -> 发现 "web-research" 技能
77+
2. 调用 '{tool_name}' 工具读取完整的技能说明
78+
3. 遵循技能的研究工作流程(搜索 -> 整理 -> 综合)
79+
4. 使用绝对路径运行任何辅助脚本
80+
81+
记住:技能让你更加强大和稳定。如有疑问,请检查是否存在适用于该任务的技能!
82+
`
83+
84+
toolDescriptionBase = `Execute a skill within the main conversation
2185
2286
<skills_instructions>
2387
When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
@@ -39,9 +103,31 @@ Important:
39103
</skills_instructions>
40104
41105
`
42-
skillToolDescriptionTemplate = `
106+
toolDescriptionBaseChinese = `在主对话中执行技能
107+
108+
<技能指令>
109+
当用户要求你执行任务时,检查下方可用技能列表中是否有技能可以更有效地完成任务。技能提供专业能力和领域知识。
110+
111+
如何调用:
112+
- 仅使用技能名称调用此工具(无需其他参数)
113+
- 示例:
114+
- ` + "`" + `skill: "pdf"` + "`" + ` - 调用 pdf 技能
115+
- ` + "`" + `skill: "xlsx"` + "`" + ` - 调用 xlsx 技能
116+
- ` + "`" + `skill: "ms-office-suite:pdf"` + "`" + ` - 使用完全限定名称调用
117+
118+
重要说明:
119+
- 当技能相关时,你必须立即调用此工具作为第一个动作
120+
- 切勿仅在文本回复中提及技能而不实际调用此工具
121+
- 这是阻塞性要求:在生成任何关于任务的其他响应之前,先调用相关的技能工具
122+
- 仅使用 <可用技能> 中列出的技能
123+
- 不要调用已经运行中的技能
124+
- 不要将此工具用于内置 CLI 命令(如 /help、/clear 等)
125+
</技能指令>
126+
127+
`
128+
toolDescriptionTemplate = `
43129
<available_skills>
44-
{{- range .Skills }}
130+
{{- range .Matters }}
45131
<skill>
46132
<name>
47133
{{ .Name }}
@@ -53,8 +139,27 @@ Important:
53139
{{- end }}
54140
</available_skills>
55141
`
56-
skillToolResult = "Launching skill: %s\n"
57-
skillUserContent = `Base directory for this skill: %s
142+
toolDescriptionTemplateChinese = `
143+
<可用技能>
144+
{{- range .Matters }}
145+
<技能>
146+
<名称>
147+
{{ .Name }}
148+
</名称>
149+
<描述>
150+
{{ .Description }}
151+
</描述>
152+
</技能>
153+
{{- end }}
154+
</可用技能>
155+
`
156+
toolResult = "Launching skill: %s\n"
157+
toolResultChinese = "正在启动技能:%s\n"
158+
userContent = `Base directory for this skill: %s
159+
160+
%s`
161+
userContentChinese = `此技能的目录:%s
58162
59163
%s`
164+
toolName = "skill"
60165
)

0 commit comments

Comments
 (0)