-
Notifications
You must be signed in to change notification settings - Fork 0
release/v5.3.0 #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
+985
−100
Merged
release/v5.3.0 #44
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7deda9f
Implement skill tool functionality and update dependencies
code-crusher a08ada9
Update CHANGELOG.md for v5.3.0
code-crusher 43e31d6
Update assistant message handling and tool integration
code-crusher 2250551
Fix type error in useSkillTool - use ask instead of say
code-crusher 47cbb0f
fix skill use tool
code-crusher 1822381
clean up skill tool
code-crusher File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| import type OpenAI from "openai" | ||
|
|
||
| export default { | ||
| type: "function", | ||
| function: { | ||
| name: "use_skill", | ||
| description: | ||
| "Use a specific skill to guide the task execution. This tool allows you to apply predefined skills stored in the workspace's .agent/skills directory. Each skill contains specialized instructions for performing specific tasks or following particular patterns.", | ||
| strict: true, | ||
| parameters: { | ||
| type: "object", | ||
| properties: { | ||
| skill_name: { | ||
| type: "string", | ||
| description: | ||
| "The name of the skill to use. Must match one of the available skills listed in the tool description.", | ||
| }, | ||
| }, | ||
| required: ["skill_name"], | ||
| additionalProperties: false, | ||
| }, | ||
| }, | ||
| } satisfies OpenAI.Chat.ChatCompletionTool |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import { discoverSkills } from "../../tools/skills" | ||
| import type { ToolArgs } from "./types" | ||
|
|
||
| export async function getUseSkillDescription(args: ToolArgs): Promise<string> { | ||
| const skills = await discoverSkills({ workspacePath: args.cwd }) | ||
|
|
||
| if (skills.length === 0) { | ||
| return `## use_skill | ||
| Description: Use a specific skill to guide the task execution. This tool allows you to apply predefined skills stored in the workspace's .agent/skills directory. | ||
| Parameters: | ||
| - skill_name: (required) The name of the skill to use. | ||
|
|
||
| No skills are currently available in this workspace. To add skills, create SKILL.md files in .agent/skills/<skill-name>/ directories.` | ||
| } | ||
|
|
||
| const skillList = skills | ||
| .map((skill) => { | ||
| return ` - ${skill.metadata.name}: ${skill.metadata.description}` | ||
| }) | ||
| .join("\n") | ||
|
|
||
| const example = skills[0] | ||
| ? `Example: Using the "${skills[0].metadata.name}" skill | ||
|
|
||
| <use_skill> | ||
| <skill_name>${skills[0].metadata.name}</skill_name> | ||
| </use_skill>` | ||
| : "" | ||
|
|
||
| return `## use_skill | ||
| Description: Use a specific skill to guide the task execution. This tool allows you to apply predefined skills stored in the workspace's .agent/skills directory. Each skill contains specialized instructions for performing specific tasks or following particular patterns. | ||
| Parameters: | ||
| - skill_name: (required) The name of the skill to use. Available skills: | ||
| ${skillList} | ||
|
|
||
| ${example}` | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,130 @@ | ||
| import { describe, it, expect, vi, beforeEach } from "vitest" | ||
| import { useSkillTool } from "../useSkillTool" | ||
| import { Task } from "../../task/Task" | ||
| import { formatResponse } from "../../prompts/responses" | ||
|
|
||
| // Mock dependencies | ||
| vi.mock("../../prompts/responses", () => ({ | ||
| formatResponse: { | ||
| toolError: vi.fn((msg) => `<error>${msg}</error>`), | ||
| }, | ||
| })) | ||
|
|
||
| describe("useSkillTool", () => { | ||
| let mockCline: any | ||
| let mockHandleError: any | ||
| let mockPushToolResult: any | ||
|
|
||
| beforeEach(() => { | ||
| mockPushToolResult = vi.fn() | ||
| mockHandleError = vi.fn() | ||
|
|
||
| mockCline = { | ||
| workspacePath: "/workspace", | ||
| consecutiveMistakeCount: 0, | ||
| recordToolError: vi.fn(), | ||
| sayAndCreateMissingParamError: vi.fn().mockResolvedValue("Missing param error"), | ||
| ask: vi.fn().mockResolvedValue({ text: "", images: [] }), | ||
| say: vi.fn().mockResolvedValue(undefined), | ||
| } as const | ||
| }) | ||
|
|
||
| it("should handle partial tool call", async () => { | ||
| const block = { | ||
| type: "tool_use", | ||
| id: "test-id-1", | ||
| name: "use_skill", | ||
| params: {}, | ||
| partial: true, | ||
| } as const | ||
|
|
||
| await useSkillTool(mockCline, block, mockHandleError, mockPushToolResult) | ||
|
|
||
| expect(mockCline.ask).toHaveBeenCalledWith("tool", expect.any(String), true) | ||
| expect(mockPushToolResult).not.toHaveBeenCalled() | ||
| }) | ||
|
|
||
| it("should return error when skill_name is missing", async () => { | ||
| const block = { | ||
| type: "tool_use", | ||
| name: "use_skill", | ||
| params: {}, | ||
| partial: false, | ||
| } as const | ||
|
|
||
| await useSkillTool(mockCline, block, mockHandleError, mockPushToolResult) | ||
|
|
||
| expect(mockCline.consecutiveMistakeCount).toBe(1) | ||
| expect(mockCline.recordToolError).toHaveBeenCalledWith("use_skill") | ||
| expect(mockCline.sayAndCreateMissingParamError).toHaveBeenCalledWith("use_skill", "skill_name") | ||
| expect(mockPushToolResult).toHaveBeenCalledWith("Missing param error") | ||
| }) | ||
|
|
||
| it("should return error when skill is not found", async () => { | ||
| const block = { | ||
| type: "tool_use", | ||
| name: "use_skill", | ||
| params: { skill_name: "non-existent-skill" }, | ||
| partial: false, | ||
| } as const | ||
|
|
||
| await useSkillTool(mockCline, block, mockHandleError, mockPushToolResult) | ||
|
|
||
| expect(mockCline.say).toHaveBeenCalled() | ||
| expect(mockPushToolResult).toHaveBeenCalledWith( | ||
| '<error>Skill "non-existent-skill" not found. Make sure the skill exists in .agent/skills/<skill-name>/SKILL.md</error>', | ||
| ) | ||
| }) | ||
|
|
||
| it("should return skill content when skill is found", async () => { | ||
| const block = { | ||
| type: "tool_use", | ||
| name: "use_skill", | ||
| params: { skill_name: "test-skill" }, | ||
| partial: false, | ||
| } as const | ||
|
|
||
| // Mock the skill discovery to return a skill | ||
| vi.doMock( | ||
| "../skills", | ||
| () => | ||
| ({ | ||
| getSkillByName: vi.fn().mockResolvedValue({ | ||
| metadata: { name: "test-skill", description: "Test skill" }, | ||
| content: "# Test Skill\n\nThis is the skill content.", | ||
| folderName: "test", | ||
| path: "/workspace/.agent/skills/test/SKILL.md", | ||
| } as const), | ||
| }) as const, | ||
| ) | ||
|
|
||
| await useSkillTool(mockCline, block, mockHandleError, mockPushToolResult) | ||
|
|
||
| expect(mockCline.say).toHaveBeenCalled() | ||
| expect(mockPushToolResult).toHaveBeenCalledWith( | ||
| "You are requested to follow the below instructions\n\n# Test Skill\n\nThis is the skill content.", | ||
| ) | ||
| }) | ||
|
|
||
| it("should handle errors gracefully", async () => { | ||
| const block = { | ||
| type: "tool_use", | ||
| name: "use_skill", | ||
| params: { skill_name: "test-skill" }, | ||
| partial: false, | ||
| } as const | ||
|
|
||
| // Mock an error in skill discovery | ||
| vi.doMock( | ||
| "../skills", | ||
| () => | ||
| ({ | ||
| getSkillByName: vi.fn().mockRejectedValue(new Error("Discovery error")), | ||
| }) as const, | ||
| ) | ||
|
|
||
| await useSkillTool(mockCline, block, mockHandleError, mockPushToolResult) | ||
|
|
||
| expect(mockHandleError).toHaveBeenCalledWith("using skill", expect.any(Error)) | ||
| }) | ||
| }) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟠 Logic/Performance
Issue: Listing all skills in the system prompt is redundant as they are already listed in the
use_skilltool description (which is required for the model to know valid arguments). This consumes unnecessary tokens. Additionally, there are typos in the text ("descretion", "for you tasks").Fix: Remove the detailed list from the system prompt and direct the model to refer to the
use_skilltool definition.Impact: Reduces token usage and improves prompt clarity.