wave-agent-sdk 0.6.5 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (174) hide show
  1. package/dist/agent.d.ts +8 -0
  2. package/dist/agent.d.ts.map +1 -1
  3. package/dist/agent.js +49 -240
  4. package/dist/constants/tools.d.ts +0 -2
  5. package/dist/constants/tools.d.ts.map +1 -1
  6. package/dist/constants/tools.js +0 -2
  7. package/dist/core/plugin.d.ts +86 -0
  8. package/dist/core/plugin.d.ts.map +1 -0
  9. package/dist/core/plugin.js +164 -0
  10. package/dist/index.d.ts +1 -4
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +1 -5
  13. package/dist/managers/MemoryRuleManager.d.ts +3 -1
  14. package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
  15. package/dist/managers/MemoryRuleManager.js +2 -1
  16. package/dist/managers/aiManager.d.ts +13 -23
  17. package/dist/managers/aiManager.d.ts.map +1 -1
  18. package/dist/managers/aiManager.js +59 -32
  19. package/dist/managers/backgroundTaskManager.d.ts +3 -1
  20. package/dist/managers/backgroundTaskManager.d.ts.map +1 -1
  21. package/dist/managers/backgroundTaskManager.js +2 -1
  22. package/dist/managers/bashManager.d.ts +4 -4
  23. package/dist/managers/bashManager.d.ts.map +1 -1
  24. package/dist/managers/bashManager.js +5 -2
  25. package/dist/managers/foregroundTaskManager.d.ts +3 -0
  26. package/dist/managers/foregroundTaskManager.d.ts.map +1 -1
  27. package/dist/managers/foregroundTaskManager.js +2 -1
  28. package/dist/managers/hookManager.d.ts +3 -3
  29. package/dist/managers/hookManager.d.ts.map +1 -1
  30. package/dist/managers/hookManager.js +20 -19
  31. package/dist/managers/liveConfigManager.d.ts +6 -13
  32. package/dist/managers/liveConfigManager.d.ts.map +1 -1
  33. package/dist/managers/liveConfigManager.js +50 -45
  34. package/dist/managers/lspManager.d.ts +4 -5
  35. package/dist/managers/lspManager.d.ts.map +1 -1
  36. package/dist/managers/lspManager.js +13 -12
  37. package/dist/managers/mcpManager.d.ts +3 -2
  38. package/dist/managers/mcpManager.d.ts.map +1 -1
  39. package/dist/managers/mcpManager.js +16 -15
  40. package/dist/managers/messageManager.d.ts +5 -7
  41. package/dist/managers/messageManager.d.ts.map +1 -1
  42. package/dist/managers/messageManager.js +12 -7
  43. package/dist/managers/permissionManager.d.ts +6 -4
  44. package/dist/managers/permissionManager.d.ts.map +1 -1
  45. package/dist/managers/permissionManager.js +39 -63
  46. package/dist/managers/planManager.d.ts +4 -6
  47. package/dist/managers/planManager.d.ts.map +1 -1
  48. package/dist/managers/planManager.js +18 -4
  49. package/dist/managers/pluginManager.d.ts +10 -22
  50. package/dist/managers/pluginManager.d.ts.map +1 -1
  51. package/dist/managers/pluginManager.js +27 -14
  52. package/dist/managers/reversionManager.d.ts +4 -3
  53. package/dist/managers/reversionManager.d.ts.map +1 -1
  54. package/dist/managers/reversionManager.js +5 -2
  55. package/dist/managers/skillManager.d.ts +3 -2
  56. package/dist/managers/skillManager.d.ts.map +1 -1
  57. package/dist/managers/skillManager.js +15 -14
  58. package/dist/managers/slashCommandManager.d.ts +9 -16
  59. package/dist/managers/slashCommandManager.d.ts.map +1 -1
  60. package/dist/managers/slashCommandManager.js +21 -10
  61. package/dist/managers/subagentManager.d.ts +7 -17
  62. package/dist/managers/subagentManager.d.ts.map +1 -1
  63. package/dist/managers/subagentManager.js +41 -34
  64. package/dist/managers/toolManager.d.ts +15 -38
  65. package/dist/managers/toolManager.d.ts.map +1 -1
  66. package/dist/managers/toolManager.js +66 -56
  67. package/dist/prompts/index.d.ts +6 -2
  68. package/dist/prompts/index.d.ts.map +1 -1
  69. package/dist/prompts/index.js +8 -4
  70. package/dist/services/MarketplaceService.d.ts.map +1 -1
  71. package/dist/services/MarketplaceService.js +13 -0
  72. package/dist/services/aiService.d.ts +4 -0
  73. package/dist/services/aiService.d.ts.map +1 -1
  74. package/dist/services/aiService.js +47 -7
  75. package/dist/services/configurationService.d.ts.map +1 -1
  76. package/dist/services/configurationService.js +30 -11
  77. package/dist/services/taskManager.d.ts +3 -1
  78. package/dist/services/taskManager.d.ts.map +1 -1
  79. package/dist/services/taskManager.js +2 -1
  80. package/dist/tools/bashTool.js +2 -2
  81. package/dist/tools/editTool.d.ts.map +1 -1
  82. package/dist/tools/editTool.js +9 -1
  83. package/dist/tools/readTool.d.ts.map +1 -1
  84. package/dist/tools/readTool.js +2 -2
  85. package/dist/tools/skillTool.d.ts +2 -4
  86. package/dist/tools/skillTool.d.ts.map +1 -1
  87. package/dist/tools/skillTool.js +61 -61
  88. package/dist/tools/taskOutputTool.js +1 -1
  89. package/dist/tools/taskTool.d.ts +2 -4
  90. package/dist/tools/taskTool.d.ts.map +1 -1
  91. package/dist/tools/taskTool.js +192 -187
  92. package/dist/tools/types.d.ts +11 -1
  93. package/dist/tools/types.d.ts.map +1 -1
  94. package/dist/tools/writeTool.d.ts.map +1 -1
  95. package/dist/tools/writeTool.js +4 -2
  96. package/dist/types/marketplace.d.ts +8 -0
  97. package/dist/types/marketplace.d.ts.map +1 -1
  98. package/dist/types/permissions.d.ts +1 -1
  99. package/dist/types/permissions.d.ts.map +1 -1
  100. package/dist/types/permissions.js +1 -3
  101. package/dist/types/skills.d.ts +0 -2
  102. package/dist/types/skills.d.ts.map +1 -1
  103. package/dist/types/tools.d.ts +0 -15
  104. package/dist/types/tools.d.ts.map +1 -1
  105. package/dist/utils/container.d.ts +31 -0
  106. package/dist/utils/container.d.ts.map +1 -0
  107. package/dist/utils/container.js +79 -0
  108. package/dist/utils/containerSetup.d.ts +26 -0
  109. package/dist/utils/containerSetup.d.ts.map +1 -0
  110. package/dist/utils/containerSetup.js +165 -0
  111. package/dist/utils/editUtils.d.ts +0 -3
  112. package/dist/utils/editUtils.d.ts.map +1 -1
  113. package/dist/utils/editUtils.js +4 -3
  114. package/dist/utils/hookMatcher.d.ts +1 -1
  115. package/dist/utils/hookMatcher.d.ts.map +1 -1
  116. package/dist/utils/hookMatcher.js +2 -2
  117. package/dist/utils/openaiClient.js +2 -2
  118. package/dist/utils/stringUtils.d.ts +6 -0
  119. package/dist/utils/stringUtils.d.ts.map +1 -1
  120. package/dist/utils/stringUtils.js +8 -0
  121. package/package.json +1 -1
  122. package/src/agent.ts +60 -282
  123. package/src/constants/tools.ts +0 -2
  124. package/src/core/plugin.ts +224 -0
  125. package/src/index.ts +1 -6
  126. package/src/managers/MemoryRuleManager.ts +6 -1
  127. package/src/managers/aiManager.ts +83 -58
  128. package/src/managers/backgroundTaskManager.ts +5 -1
  129. package/src/managers/bashManager.ts +9 -4
  130. package/src/managers/foregroundTaskManager.ts +3 -0
  131. package/src/managers/hookManager.ts +21 -23
  132. package/src/managers/liveConfigManager.ts +57 -53
  133. package/src/managers/lspManager.ts +14 -19
  134. package/src/managers/mcpManager.ts +20 -20
  135. package/src/managers/messageManager.ts +19 -12
  136. package/src/managers/permissionManager.ts +45 -70
  137. package/src/managers/planManager.ts +26 -7
  138. package/src/managers/pluginManager.ts +37 -33
  139. package/src/managers/reversionManager.ts +5 -3
  140. package/src/managers/skillManager.ts +19 -20
  141. package/src/managers/slashCommandManager.ts +30 -25
  142. package/src/managers/subagentManager.ts +53 -53
  143. package/src/managers/toolManager.ts +91 -90
  144. package/src/prompts/index.ts +13 -5
  145. package/src/services/MarketplaceService.ts +13 -0
  146. package/src/services/aiService.ts +61 -15
  147. package/src/services/configurationService.ts +34 -13
  148. package/src/services/taskManager.ts +5 -1
  149. package/src/tools/bashTool.ts +2 -2
  150. package/src/tools/editTool.ts +9 -1
  151. package/src/tools/readTool.ts +2 -2
  152. package/src/tools/skillTool.ts +75 -71
  153. package/src/tools/taskOutputTool.ts +1 -1
  154. package/src/tools/taskTool.ts +224 -225
  155. package/src/tools/types.ts +12 -1
  156. package/src/tools/writeTool.ts +4 -2
  157. package/src/types/marketplace.ts +9 -0
  158. package/src/types/permissions.ts +0 -4
  159. package/src/types/skills.ts +0 -3
  160. package/src/types/tools.ts +0 -17
  161. package/src/utils/container.ts +92 -0
  162. package/src/utils/containerSetup.ts +256 -0
  163. package/src/utils/editUtils.ts +4 -3
  164. package/src/utils/hookMatcher.ts +2 -2
  165. package/src/utils/openaiClient.ts +2 -2
  166. package/src/utils/stringUtils.ts +9 -0
  167. package/dist/tools/deleteFileTool.d.ts +0 -6
  168. package/dist/tools/deleteFileTool.d.ts.map +0 -1
  169. package/dist/tools/deleteFileTool.js +0 -100
  170. package/dist/tools/multiEditTool.d.ts +0 -6
  171. package/dist/tools/multiEditTool.d.ts.map +0 -1
  172. package/dist/tools/multiEditTool.js +0 -246
  173. package/src/tools/deleteFileTool.ts +0 -127
  174. package/src/tools/multiEditTool.ts +0 -306
@@ -16,7 +16,15 @@ function formatCompactParams(args, context) {
16
16
  export const editTool = {
17
17
  name: EDIT_TOOL_NAME,
18
18
  formatCompactParams,
19
- prompt: () => `Performs exact string replacements in files. \n\nUsage:\n- You must use your \`${READ_TOOL_NAME}\` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file. \n- When editing text from read_file tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.\n- ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.\n- Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.\n- The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`. \n- Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`,
19
+ prompt: () => `Performs exact string replacements in files.
20
+
21
+ Usage:
22
+ - You must use your \`${READ_TOOL_NAME}\` tool at least once in the conversation before editing. This tool will error if you attempt an edit without reading the file.
23
+ - When editing text from ${READ_TOOL_NAME} tool output, ensure you preserve the exact indentation (tabs/spaces) as it appears AFTER the line number prefix. The line number prefix format is: spaces + line number + tab. Everything after that tab is the actual file content to match. Never include any part of the line number prefix in the old_string or new_string.
24
+ - ALWAYS prefer editing existing files in the codebase. NEVER write new files unless explicitly required.
25
+ - Only use emojis if the user explicitly requests it. Avoid adding emojis to files unless asked.
26
+ - The edit will FAIL if \`old_string\` is not unique in the file. Either provide a larger string with more surrounding context to make it unique or use \`replace_all\` to change every instance of \`old_string\`.
27
+ - Use \`replace_all\` for replacing and renaming strings across the file. This parameter is useful if you want to rename a variable for instance.`,
20
28
  config: {
21
29
  type: "function",
22
30
  function: {
@@ -1 +1 @@
1
- {"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AA6HtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAkOtB,CAAC"}
1
+ {"version":3,"file":"readTool.d.ts","sourceRoot":"","sources":["../../src/tools/readTool.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AA8HtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UAiOtB,CAAC"}
@@ -2,6 +2,7 @@ import { readFile, stat } from "fs/promises";
2
2
  import { extname } from "path";
3
3
  import { logger } from "../utils/globalLogger.js";
4
4
  import { resolvePath, getDisplayPath } from "../utils/path.js";
5
+ import { formatLineNumberPrefix } from "../utils/stringUtils.js";
5
6
  import { isBinaryDocument, getBinaryDocumentError, } from "../utils/fileFormat.js";
6
7
  import { convertImageToBase64 } from "../utils/messageOperations.js";
7
8
  import { READ_TOOL_NAME } from "../constants/tools.js";
@@ -123,7 +124,6 @@ Usage:
123
124
  - Any lines longer than 2000 characters will be truncated
124
125
  - Results are returned using cat -n format, with line numbers starting at 1
125
126
  - This tool allows Agent to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as Agent is a multimodal LLM.
126
- - This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.
127
127
  - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful.
128
128
  - You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png
129
129
  - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents.
@@ -245,7 +245,7 @@ Usage:
245
245
  const lineNumber = startLine + index;
246
246
  // Truncate overly long lines
247
247
  const truncatedLine = line.length > 2000 ? line.substring(0, 2000) + "..." : line;
248
- return `${lineNumber.toString().padStart(6)}\t${truncatedLine}`;
248
+ return `${formatLineNumberPrefix(lineNumber)}${truncatedLine}`;
249
249
  })
250
250
  .join("\n");
251
251
  // Add file information header
@@ -1,8 +1,6 @@
1
1
  import type { ToolPlugin } from "./types.js";
2
- import type { SkillManager } from "../managers/skillManager.js";
3
2
  /**
4
- * Create a skill tool plugin that uses the provided SkillManager
5
- * Note: SkillManager should be initialized before calling this function
3
+ * Skill tool plugin for invoking Wave skills
6
4
  */
7
- export declare function createSkillTool(skillManager: SkillManager): ToolPlugin;
5
+ export declare const skillTool: ToolPlugin;
8
6
  //# sourceMappingURL=skillTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"skillTool.d.ts","sourceRoot":"","sources":["../../src/tools/skillTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAc,MAAM,YAAY,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAGhE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,YAAY,GAAG,UAAU,CA8EtE"}
1
+ {"version":3,"file":"skillTool.d.ts","sourceRoot":"","sources":["../../src/tools/skillTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAItE;;GAEG;AACH,eAAO,MAAM,SAAS,EAAE,UAmFvB,CAAC"}
@@ -1,75 +1,75 @@
1
1
  import { SKILL_TOOL_NAME } from "../constants/tools.js";
2
2
  /**
3
- * Create a skill tool plugin that uses the provided SkillManager
4
- * Note: SkillManager should be initialized before calling this function
3
+ * Skill tool plugin for invoking Wave skills
5
4
  */
6
- export function createSkillTool(skillManager) {
7
- // Ensure SkillManager is initialized
8
- skillManager.getAvailableSkills();
9
- return {
10
- name: SKILL_TOOL_NAME,
11
- get config() {
12
- const availableSkills = skillManager.getAvailableSkills();
13
- const getToolDescription = () => {
14
- if (availableSkills.length === 0) {
15
- return "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific. No skills are currently available.";
16
- }
17
- const skillList = availableSkills
18
- .map((skill) => `• **${skill.name}** (${skill.type}): ${skill.description}`)
19
- .join("\n");
20
- return `Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific.\n\nAvailable skills:\n${skillList}`;
21
- };
22
- return {
23
- type: "function",
24
- function: {
25
- name: SKILL_TOOL_NAME,
26
- description: getToolDescription(),
27
- parameters: {
28
- type: "object",
29
- properties: {
30
- skill_name: {
31
- type: "string",
32
- description: "Name of the skill to invoke",
33
- enum: availableSkills.map((skill) => skill.name),
34
- },
35
- },
36
- required: ["skill_name"],
5
+ export const skillTool = {
6
+ name: SKILL_TOOL_NAME,
7
+ config: {
8
+ type: "function",
9
+ function: {
10
+ name: SKILL_TOOL_NAME,
11
+ description: "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific.",
12
+ parameters: {
13
+ type: "object",
14
+ properties: {
15
+ skill_name: {
16
+ type: "string",
17
+ description: "Name of the skill to invoke",
37
18
  },
38
19
  },
39
- };
20
+ required: ["skill_name"],
21
+ },
40
22
  },
41
- execute: async (args) => {
42
- try {
43
- // Validate arguments
44
- const skillName = args.skill_name;
45
- if (!skillName || typeof skillName !== "string") {
46
- return {
47
- success: false,
48
- content: "",
49
- error: "skill_name parameter is required and must be a string",
50
- };
51
- }
52
- // Execute the skill
53
- const result = await skillManager.executeSkill({
54
- skill_name: skillName,
55
- });
23
+ },
24
+ prompt: (args) => {
25
+ const availableSkills = args?.availableSkills;
26
+ if (!availableSkills || availableSkills.length === 0) {
27
+ return "Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific. No skills are currently available.";
28
+ }
29
+ const skillList = availableSkills
30
+ .map((skill) => `• **${skill.name}** (${skill.type}): ${skill.description}`)
31
+ .join("\n");
32
+ return `Invoke a Wave skill by name. Skills are user-defined automation templates that can be personal or project-specific.\n\nAvailable skills:\n${skillList}`;
33
+ },
34
+ execute: async (args, context) => {
35
+ try {
36
+ const skillManager = context.skillManager;
37
+ if (!skillManager) {
56
38
  return {
57
- success: true,
58
- content: result.content,
59
- shortResult: `Invoked skill: ${skillName}`,
39
+ success: false,
40
+ content: "",
41
+ error: "Skill manager not available in tool context",
60
42
  };
61
43
  }
62
- catch (error) {
44
+ // Validate arguments
45
+ const skillName = args.skill_name;
46
+ if (!skillName || typeof skillName !== "string") {
63
47
  return {
64
48
  success: false,
65
49
  content: "",
66
- error: error instanceof Error ? error.message : String(error),
50
+ error: "skill_name parameter is required and must be a string",
67
51
  };
68
52
  }
69
- },
70
- formatCompactParams: (params) => {
71
- const skillName = params.skill_name;
72
- return skillName || "unknown-skill";
73
- },
74
- };
75
- }
53
+ // Execute the skill
54
+ const result = await skillManager.executeSkill({
55
+ skill_name: skillName,
56
+ });
57
+ return {
58
+ success: true,
59
+ content: result.content,
60
+ shortResult: `Invoked skill: ${skillName}`,
61
+ };
62
+ }
63
+ catch (error) {
64
+ return {
65
+ success: false,
66
+ content: "",
67
+ error: error instanceof Error ? error.message : String(error),
68
+ };
69
+ }
70
+ },
71
+ formatCompactParams: (params) => {
72
+ const skillName = params.skill_name;
73
+ return skillName || "unknown-skill";
74
+ },
75
+ };
@@ -167,7 +167,7 @@ export const taskOutputTool = {
167
167
  },
168
168
  formatCompactParams: (params) => {
169
169
  const taskId = params.task_id;
170
- const block = params.block;
170
+ const block = params.block ?? true;
171
171
  return `${taskId}${block ? " (blocking)" : ""}`;
172
172
  },
173
173
  };
@@ -1,8 +1,6 @@
1
1
  import type { ToolPlugin } from "./types.js";
2
- import type { SubagentManager } from "../managers/subagentManager.js";
3
2
  /**
4
- * Create a task tool plugin that uses the provided SubagentManager
5
- * Note: SubagentManager should be initialized before calling this function
3
+ * Task tool plugin for delegating tasks to specialized subagents
6
4
  */
7
- export declare function createTaskTool(subagentManager: SubagentManager): ToolPlugin;
5
+ export declare const taskTool: ToolPlugin;
8
6
  //# sourceMappingURL=taskTool.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"taskTool.d.ts","sourceRoot":"","sources":["../../src/tools/taskTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AACtE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAC;AAItE;;;GAGG;AACH,wBAAgB,cAAc,CAAC,eAAe,EAAE,eAAe,GAAG,UAAU,CA2O3E"}
1
+ {"version":3,"file":"taskTool.d.ts","sourceRoot":"","sources":["../../src/tools/taskTool.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,YAAY,CAAC;AAKtE;;GAEG;AACH,eAAO,MAAM,QAAQ,EAAE,UA2OtB,CAAC"}
@@ -1,198 +1,203 @@
1
1
  import { EXPLORE_SUBAGENT_TYPE } from "../constants/subagents.js";
2
2
  import { TASK_TOOL_NAME } from "../constants/tools.js";
3
3
  /**
4
- * Create a task tool plugin that uses the provided SubagentManager
5
- * Note: SubagentManager should be initialized before calling this function
4
+ * Task tool plugin for delegating tasks to specialized subagents
6
5
  */
7
- export function createTaskTool(subagentManager) {
8
- // Ensure SubagentManager is initialized
9
- subagentManager.getConfigurations();
10
- return {
11
- name: TASK_TOOL_NAME,
12
- get config() {
13
- // Get available subagents from the initialized subagent manager
14
- const availableSubagents = subagentManager.getConfigurations();
15
- const subagentList = availableSubagents
16
- .map((config) => `- ${config.name}: ${config.description}`)
17
- .join("\n");
18
- const description = `Delegate a task to a specialized subagent. Use this when you need specialized expertise or want to break down complex work into focused subtasks.
19
-
20
- Available subagents:
21
- ${subagentList || "No subagents configured"}`;
22
- return {
23
- type: "function",
24
- function: {
25
- name: TASK_TOOL_NAME,
26
- description,
27
- parameters: {
28
- type: "object",
29
- properties: {
30
- description: {
31
- type: "string",
32
- description: "A clear, concise description of what needs to be accomplished",
33
- },
34
- prompt: {
35
- type: "string",
36
- description: "The specific instructions or prompt to send to the subagent",
37
- },
38
- subagent_type: {
39
- type: "string",
40
- description: `The type or name of subagent to use. Available options: ${availableSubagents.map((c) => c.name).join(", ") || "none"}`,
41
- },
42
- run_in_background: {
43
- type: "boolean",
44
- description: "Set to true to run this command in the background. Use TaskOutput to read the output later.",
45
- },
46
- },
47
- required: ["description", "prompt", "subagent_type"],
6
+ export const taskTool = {
7
+ name: TASK_TOOL_NAME,
8
+ config: {
9
+ type: "function",
10
+ function: {
11
+ name: TASK_TOOL_NAME,
12
+ description: "Delegate a task to a specialized subagent. Use this when you need specialized expertise or want to break down complex work into focused subtasks.",
13
+ parameters: {
14
+ type: "object",
15
+ properties: {
16
+ description: {
17
+ type: "string",
18
+ description: "A short (3-5 word) description of the task",
19
+ },
20
+ prompt: {
21
+ type: "string",
22
+ description: "The task for the agent to perform",
23
+ },
24
+ subagent_type: {
25
+ type: "string",
26
+ description: "The type of specialized agent to use for this task",
27
+ },
28
+ run_in_background: {
29
+ type: "boolean",
30
+ description: "Set to true to run this command in the background. Use TaskOutput to read the output later.",
48
31
  },
49
32
  },
50
- };
33
+ required: ["description", "prompt", "subagent_type"],
34
+ },
51
35
  },
52
- prompt: () => `
36
+ },
37
+ prompt: (args) => {
38
+ const subagentList = args?.availableSubagents
39
+ ? args.availableSubagents
40
+ .map((config) => `- ${config.name}: ${config.description}`)
41
+ .join("\n")
42
+ : "";
43
+ return `
44
+ Delegate a task to a specialized subagent. Use this when you need specialized expertise or want to break down complex work into focused subtasks.
45
+
46
+ Available subagents:
47
+ ${subagentList || "No subagents configured"}
48
+
53
49
  - When doing file search, prefer to use the ${TASK_TOOL_NAME} tool in order to reduce context usage.
54
50
  - You should proactively use the ${TASK_TOOL_NAME} tool with specialized agents when the task at hand matches the agent's description.
55
- - VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${TASK_TOOL_NAME} tool with subagent_type=${EXPLORE_SUBAGENT_TYPE} instead of running search commands directly.`,
56
- execute: async (args, context) => {
57
- return new Promise((resolve) => {
58
- (async () => {
59
- // Input validation
60
- const description = args.description;
61
- const prompt = args.prompt;
62
- const subagent_type = args.subagent_type;
63
- const run_in_background = args.run_in_background;
64
- if (!description || typeof description !== "string") {
65
- return resolve({
66
- success: false,
67
- content: "",
68
- error: "description parameter is required and must be a string",
69
- shortResult: "Task delegation failed",
70
- });
71
- }
72
- if (!prompt || typeof prompt !== "string") {
73
- return resolve({
74
- success: false,
75
- content: "",
76
- error: "prompt parameter is required and must be a string",
77
- shortResult: "Task delegation failed",
78
- });
79
- }
80
- if (!subagent_type || typeof subagent_type !== "string") {
81
- return resolve({
82
- success: false,
83
- content: "",
84
- error: "subagent_type parameter is required and must be a string",
85
- shortResult: "Task delegation failed",
86
- });
87
- }
88
- try {
89
- // Subagent selection logic with explicit name matching only
90
- const configuration = await subagentManager.findSubagent(subagent_type);
91
- if (!configuration) {
92
- // Error handling for nonexistent subagents with available subagents listing
93
- const allConfigs = subagentManager.getConfigurations();
94
- const availableNames = allConfigs.map((c) => c.name).join(", ");
95
- return resolve({
96
- success: false,
97
- content: "",
98
- error: `No subagent found matching "${subagent_type}". Available subagents: ${availableNames || "none"}`,
99
- shortResult: "Subagent not found",
100
- });
101
- }
102
- // Set up callback to update shortResult with tool names, tool count and tokens
103
- const updateShortResult = () => {
104
- const messages = instance.messageManager.getMessages();
105
- const tokens = instance.messageManager.getlatestTotalTokens();
106
- const lastTools = instance.lastTools;
107
- // Count tool blocks in messages
108
- let toolCount = 0;
109
- messages.forEach((msg) => {
110
- msg.blocks.forEach((block) => {
111
- if (block.type === "tool") {
112
- toolCount++;
113
- }
114
- });
115
- });
116
- let shortResult = "";
117
- if (toolCount > 2) {
118
- shortResult += "... ";
119
- }
120
- if (lastTools.length > 0) {
121
- shortResult += `${lastTools.join(", ")} `;
122
- }
123
- shortResult += `(${toolCount} tools`;
124
- if (tokens > 0) {
125
- shortResult += ` | ${tokens.toLocaleString()} tokens`;
126
- }
127
- shortResult += ")";
128
- context.onShortResultUpdate?.(shortResult);
129
- };
130
- // Create subagent instance and execute task
131
- const instance = await subagentManager.createInstance(configuration, {
132
- description,
133
- prompt,
134
- subagent_type,
135
- }, run_in_background, updateShortResult);
136
- // Initial update
137
- updateShortResult();
138
- let isBackgrounded = false;
139
- // Register for backgrounding if not already in background
140
- if (!run_in_background && context.foregroundTaskManager) {
141
- context.foregroundTaskManager.registerForegroundTask({
142
- id: instance.subagentId,
143
- backgroundHandler: async () => {
144
- isBackgrounded = true;
145
- const taskId = await subagentManager.backgroundInstance(instance.subagentId);
146
- // Resolve the tool execution early so the main agent can continue
147
- resolve({
148
- success: true,
149
- content: `Task moved to background with ID: ${taskId}.`,
150
- shortResult: "Task backgrounded",
151
- isManuallyBackgrounded: true,
152
- });
153
- },
154
- });
155
- }
156
- try {
157
- const result = await subagentManager.executeTask(instance, prompt, context.abortSignal, run_in_background);
158
- if (isBackgrounded)
159
- return;
160
- if (run_in_background) {
161
- return resolve({
162
- success: true,
163
- content: `Task started in background with ID: ${result}`,
164
- shortResult: `Task started in background: ${result}`,
165
- });
166
- }
167
- // Cleanup subagent instance after task completion
168
- subagentManager.cleanupInstance(instance.subagentId);
169
- return resolve({
170
- success: true,
171
- content: result,
172
- shortResult: `Task completed by ${configuration.name}`,
173
- });
174
- }
175
- finally {
176
- if (!run_in_background && context.foregroundTaskManager) {
177
- context.foregroundTaskManager.unregisterForegroundTask(instance.subagentId);
178
- }
51
+ - VERY IMPORTANT: When exploring the codebase to gather context or to answer a question that is not a needle query for a specific file/class/function, it is CRITICAL that you use the ${TASK_TOOL_NAME} tool with subagent_type=${EXPLORE_SUBAGENT_TYPE} instead of running search commands directly.`;
52
+ },
53
+ execute: async (args, context) => {
54
+ const subagentManager = context.subagentManager;
55
+ if (!subagentManager) {
56
+ return {
57
+ success: false,
58
+ content: "",
59
+ error: "Subagent manager not available in tool context",
60
+ shortResult: "Task delegation failed",
61
+ };
62
+ }
63
+ // Input validation
64
+ const description = args.description;
65
+ const prompt = args.prompt;
66
+ const subagent_type = args.subagent_type;
67
+ const run_in_background = args.run_in_background;
68
+ if (!description || typeof description !== "string") {
69
+ return {
70
+ success: false,
71
+ content: "",
72
+ error: "description parameter is required and must be a string",
73
+ shortResult: "Task delegation failed",
74
+ };
75
+ }
76
+ if (!prompt || typeof prompt !== "string") {
77
+ return {
78
+ success: false,
79
+ content: "",
80
+ error: "prompt parameter is required and must be a string",
81
+ shortResult: "Task delegation failed",
82
+ };
83
+ }
84
+ if (!subagent_type || typeof subagent_type !== "string") {
85
+ return {
86
+ success: false,
87
+ content: "",
88
+ error: "subagent_type parameter is required and must be a string",
89
+ shortResult: "Task delegation failed",
90
+ };
91
+ }
92
+ try {
93
+ // Subagent selection logic with explicit name matching only
94
+ const configuration = await subagentManager.findSubagent(subagent_type);
95
+ if (!configuration) {
96
+ // Error handling for nonexistent subagents with available subagents listing
97
+ const allConfigs = subagentManager.getConfigurations();
98
+ const availableNames = allConfigs.map((c) => c.name).join(", ");
99
+ return {
100
+ success: false,
101
+ content: "",
102
+ error: `No subagent found matching "${subagent_type}". Available subagents: ${availableNames || "none"}`,
103
+ shortResult: "Subagent not found",
104
+ };
105
+ }
106
+ let isBackgrounded = false;
107
+ // Create subagent instance and execute task
108
+ const instance = await subagentManager.createInstance(configuration, {
109
+ description,
110
+ prompt,
111
+ subagent_type,
112
+ }, run_in_background, () => {
113
+ // Do not update shortResult if it is running in background
114
+ if (run_in_background || isBackgrounded)
115
+ return;
116
+ const messages = instance.messageManager.getMessages();
117
+ const tokens = instance.messageManager.getlatestTotalTokens();
118
+ const lastTools = instance.lastTools;
119
+ // Count tool blocks in messages
120
+ let toolCount = 0;
121
+ messages.forEach((msg) => {
122
+ msg.blocks.forEach((block) => {
123
+ if (block.type === "tool") {
124
+ toolCount++;
179
125
  }
180
- }
181
- catch (error) {
182
- return resolve({
183
- success: false,
184
- content: "",
185
- error: `Task delegation failed: ${error instanceof Error ? error.message : String(error)}`,
186
- shortResult: "Delegation error",
187
- });
188
- }
189
- })();
126
+ });
127
+ });
128
+ let shortResult = "";
129
+ if (toolCount > 2) {
130
+ shortResult += "... ";
131
+ }
132
+ if (lastTools.length > 0) {
133
+ shortResult += `${lastTools.join(", ")} `;
134
+ }
135
+ shortResult += `(${toolCount} tools`;
136
+ if (tokens > 0) {
137
+ shortResult += ` | ${tokens.toLocaleString()} tokens`;
138
+ }
139
+ shortResult += ")";
140
+ context.onShortResultUpdate?.(shortResult);
190
141
  });
191
- },
192
- formatCompactParams: (params) => {
193
- const subagent_type = params.subagent_type;
194
- const description = params.description;
195
- return `${subagent_type || "unknown"}: ${description || "no description"}`;
196
- },
197
- };
198
- }
142
+ // Register for backgrounding if not already in background
143
+ if (!run_in_background && context.foregroundTaskManager) {
144
+ context.foregroundTaskManager.registerForegroundTask({
145
+ id: instance.subagentId,
146
+ backgroundHandler: async () => {
147
+ isBackgrounded = true;
148
+ await subagentManager.backgroundInstance(instance.subagentId);
149
+ },
150
+ });
151
+ }
152
+ try {
153
+ const result = await subagentManager.executeTask(instance, prompt, context.abortSignal, run_in_background);
154
+ if (isBackgrounded) {
155
+ // If it was backgrounded during execution, the backgroundHandler already returned/will return
156
+ // But wait, the backgroundHandler is async and returns a ToolResult.
157
+ // In the current ToolManager/AIManager implementation, the backgroundHandler's return value
158
+ // is what's used when backgrounding happens.
159
+ // However, executeTask might still be running.
160
+ // We should return a special value or just let it be.
161
+ return {
162
+ success: true,
163
+ content: "Task backgrounded",
164
+ shortResult: "Task backgrounded",
165
+ isManuallyBackgrounded: true,
166
+ };
167
+ }
168
+ if (run_in_background) {
169
+ return {
170
+ success: true,
171
+ content: `Task started in background with ID: ${result}`,
172
+ shortResult: `Task started in background: ${result}`,
173
+ };
174
+ }
175
+ // Cleanup subagent instance after task completion
176
+ subagentManager.cleanupInstance(instance.subagentId);
177
+ return {
178
+ success: true,
179
+ content: result,
180
+ shortResult: `Task completed by ${configuration.name}`,
181
+ };
182
+ }
183
+ finally {
184
+ if (!run_in_background && context.foregroundTaskManager) {
185
+ context.foregroundTaskManager.unregisterForegroundTask(instance.subagentId);
186
+ }
187
+ }
188
+ }
189
+ catch (error) {
190
+ return {
191
+ success: false,
192
+ content: "",
193
+ error: `Task delegation failed: ${error instanceof Error ? error.message : String(error)}`,
194
+ shortResult: "Delegation error",
195
+ };
196
+ }
197
+ },
198
+ formatCompactParams: (params) => {
199
+ const subagent_type = params.subagent_type;
200
+ const description = params.description;
201
+ return `${subagent_type || "unknown"}: ${description || "no description"}`;
202
+ },
203
+ };